End-to-end scenarios — ec2-api — branch 17.0.0
Branch
17.0.0@32740781f605— repository https://opendev.org/openstack/ec2-api (retired; local branchpre-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
endWhere 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 running3. 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 VPC4. 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-0a1b2c3d7. 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 listedSource: reverse-spec-ec2-api/04-scenarios_17.0.0.md. The _rewrite/ and _inventory/ files are not published on the site.