OpenKeel: the sovereign French Cloud solution of the inherent group, with a European reach Discover inherent

Reverse-spec · Services

ec2-api — Scenarios

End-to-end scenarios — ec2-api — branch 17.0.0

Branch 17.0.0 @ 32740781f605 — repository https://opendev.org/openstack/ec2-api (retired; local branch pre-retirement) — analysed on 2026-10-29

Participants: the EC2 client (boto3, AWS CLI, Terraform), ec2-api, its database, Keystone, Nova, Neutron, Cinder, Glance, and the metadata path (Neutron metadata agent → ec2-api-metadata).

1. Any authenticated request (SigV4, boto3)

sequenceDiagram
  participant C as EC2 client
  participant A as ec2-api (paste pipeline)
  participant K as Keystone
  participant DB as MariaDB ec2api
  participant O as Nova/Neutron/Cinder/Glance
  C->>A: POST / form Action=DescribeVpcs&Version=2016-11-15<br/>Authorization: AWS4-HMAC-SHA256 Credential=AK/…, Signature=…
  A->>A: body_hash = sha256(body); signature, access key from header
  A->>K: POST /v3/ec2tokens {"ec2Credentials": {access, signature, host, verb, path, params: {}, headers, body_hash}}
  alt signature invalid / key unknown / expired
    K-->>A: 401 / 404
    A-->>C: 401|404 text/xml <Code>AuthFailure</Code> (message = reason phrase)
  else ok
    K-->>A: 200 X-Subject-Token + token (user, project, catalogue)
    A->>A: Requestify: Timestamp/Expires check, strip auth params,<br/>dotted names → dicts, _try_convert values
    alt Action unknown
      A-->>C: 400 <Code>InvalidRequest</Code>
    else
      A->>A: validators of the controller stub (ec2api/api/cloud.py)
      A->>DB: SELECT items WHERE project_id AND id LIKE 'vpc-%'
      A->>O: REST calls with the user's token (admin session for some Nova reads)
      A->>DB: auto-create / delete items (Describe reconciliation)
      A-->>C: 200 text/xml <DescribeVpcsResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/"><requestId>…
    end
  end

Where to look when it fails: Keystone logs for ec2tokens 401s (clock skew beyond [credential] auth_ttl, region in the credential scope, port in Host); ec2-api access log line (ec2api/api/__init__.py:96) for the action and status; ERROR logs "Unexpected … raised" for 500s (ec2api/api/__init__.py:329).

2. RunInstances in a VPC subnet

sequenceDiagram
  participant C as Client
  participant A as ec2-api
  participant DB as DB
  participant G as Glance
  participant N as Nova
  participant Q as Neutron
  C->>A: RunInstances ImageId=ami-…, MinCount=1, MaxCount=2, SubnetId=subnet-…, InstanceType=m1.small
  A->>DB: get_items_ids(ami, ami-…) → Glance UUID
  A->>G: GET /v2/images/{uuid} (must be active)
  A->>N: GET /flavors/detail (pick by name)
  A->>DB: subnet item, default security group of the VPC
  A->>A: reservation r-xxxxxxxx
  loop index 0..MaxCount-1 (sequential)
    A->>Q: POST /v2.0/ports {network_id, fixed_ips [{subnet_id}], security_groups}
    A->>DB: INSERT eni-…; PUT port name=eni-…
    A->>N: POST /servers {name: r-…-<i>, imageRef, flavorRef, networks [{port}], block_device_mapping_v2, key_name, user_data, availability_zone}
    A->>DB: INSERT i-… {reservation_id, launch_index}, vpc_id
    A->>N: PUT /servers/{id} {name: i-…}
    A->>DB: UPDATE eni-… {instance_id, device_index 0, attach_time, delete_on_termination}
    alt failure and index < MinCount
      A->>N: DELETE servers; A->>Q: DELETE ports; A->>DB: DELETE items
      A-->>C: error (02)
    end
  end
  A->>N: GET /servers/detail?all_tenants&project_id [admin] (DescribeInstances)
  A-->>C: 200 reservation, instances pending
  Note over N: Nova schedules and boots asynchronously;<br/>the client polls DescribeInstances until running

3. First Describe with disable_ec2_classic = True: default VPC

sequenceDiagram
  participant C as Client
  participant A as ec2-api
  participant L as file lock (lock_path)
  participant DB as DB
  participant Q as Neutron
  C->>A: DescribeSecurityGroups (or DescribeVpcs/Subnets/RouteTables/InternetGateways)
  A->>L: acquire ec2api-default-vpc-lock-<project>-
  A->>DB: any vpc item with is_default?
  alt none
    A->>Q: POST /routers; PUT name=vpc-…
    A->>DB: INSERT vpc-… {cidr 172.31.0.0/16, is_default}, rtb-… (local route)
    A->>Q: POST /security-groups name=vpc-… ; DB sg-<vpc hex>
    A->>DB: INSERT igw-…; A->>Q: PUT router external_gateway_info (external network)
    A->>Q: POST /networks, /subnets 172.31.0.0/20 (host_routes), add_router_interface
    A->>DB: INSERT subnet-…; rtb routes += 0.0.0.0/0 → igw; A->>Q: PUT subnet host_routes, gateway_ip
  end
  A->>L: release
  A-->>C: describe result (now including the default VPC objects)
  Note over A: any failure is logged ("Failed to create default vpc")<br/>and the describe continues without a default VPC

4. Elastic IP for a VPC instance

sequenceDiagram
  participant C as Client
  participant A as ec2-api
  participant DB as DB
  participant Q as Neutron
  C->>A: AllocateAddress Domain=vpc
  A->>Q: GET /networks?router:external=True[&name=external_network]
  A->>Q: POST /floatingips {floating_network_id}
  A->>DB: INSERT eipalloc-… {public_ip}
  A-->>C: publicIp, domain vpc, allocationId eipalloc-…
  C->>A: AssociateAddress AllocationId=eipalloc-…, InstanceId=i-…
  A->>DB: ENIs of the instance (exactly one), eipalloc item
  A->>Q: GET /floatingips/{id} (still exists)
  A->>DB: igw attached to the ENI's VPC? (else Gateway.NotAttached)
  A->>DB: UPDATE eipalloc {network_interface_id, private_ip_address}
  A->>Q: PUT /floatingips/{id} {port_id, fixed_ip_address}
  A-->>C: return true, associationId eipassoc-<same hex>

5. CreateImage of a running EBS-backed instance (asynchronous)

sequenceDiagram
  participant C as Client
  participant A as ec2-api request
  participant T as green thread (same process)
  participant DB as DB
  participant N as Nova
  participant G as Glance
  C->>A: CreateImage InstanceId=i-…, Name=…
  A->>N: GET server [admin]; Cinder: root device is a volume?
  A->>DB: INSERT ami-… {is_public false, description} (os_id NULL)
  A->>T: eventlet.spawn_n(delayed_create)
  A-->>C: 200 imageId ami-…
  T->>N: os-stop; poll GET server every 1 s until SHUTOFF (≤ 1 h)
  T->>N: createImage name, metadata {ec2_id: ami-…}
  T->>DB: UPDATE ami-… os_id = <glance uuid>
  T->>N: os-start
  alt failure
    T->>DB: UPDATE ami-… state = failed
  end
  C->>A: DescribeImages (polling)
  A->>G: GET /v2/images
  A->>DB: pending items matched by Glance property ec2_id (if the thread died before storing os_id)
  A-->>C: imageState pending → available (Glance active)

If the ec2-api process restarts while the thread runs, the stop/snapshot/start sequence stops where it was; the server may stay stopped, and the image item stays pending until a Glance image carrying ec2_id appears (ec2api/api/image.py:412, ec2api/api/image.py:463).

6. Instance metadata

sequenceDiagram
  participant VM as Instance
  participant P as Neutron metadata agent/proxy
  participant M as ec2-api-metadata
  participant Ca as oslo.cache
  participant N as Nova
  participant Q as Neutron
  VM->>P: GET http://169.254.169.254/latest/meta-data/instance-id
  P->>M: GET /latest/meta-data/instance-id<br/>X-Instance-ID, X-Tenant-ID, X-Forwarded-For, X-Instance-ID-Signature
  M->>M: HMAC-SHA256(shared secret, instance uuid) == signature? (else 403)
  M->>Ca: GET ec2api-metadata-<uuid>
  alt miss
    M->>M: DescribeInstances for the instance (admin session, project = X-Tenant-ID)
    M->>N: servers.get, keypair (user_id), user_data [admin]
    M->>Q: ports, floating IPs, security groups
    M->>Ca: SET {metadata, owner_id} (15 s)
  end
  M-->>P: 200 text/plain i-0a1b2c3d
  P-->>VM: i-0a1b2c3d

7. TerminateInstances and the delayed clean-up

sequenceDiagram
  participant C as Client
  participant A as ec2-api
  participant DB as DB
  participant N as Nova
  participant Q as Neutron
  C->>A: TerminateInstances InstanceId.1=i-…
  A->>DB: items (disable_api_termination? → OperationNotPermitted)
  A->>N: GET server; DELETE server; GET server (state)
  A-->>C: previousState running(16), currentState shutting-down(32)
  Note over DB: the i- item and its ENI attachments stay in the DB
  C->>A: DescribeInstances (later)
  A->>N: servers.list [admin] — the server is gone
  A->>DB: detach ENIs; ENIs with delete_on_termination
  A->>Q: DELETE /ports/{id}
  A->>DB: DELETE i-… (and its tags)
  A-->>C: instance no longer listed

Source: reverse-spec-ec2-api/04-scenarios_17.0.0.md. The _rewrite/ and _inventory/ files are not published on the site.