Rename instance to server and instance type to flavor
Change-Id: I35a7fb0b4f3fa9e09f2fc2c739c0a9b39a8576ab
This commit is contained in:
@ -6,9 +6,9 @@
|
||||
|
||||
Show and manage server flavors.
|
||||
|
||||
Flavors are a way to describe the basic dimensions of a instance to be
|
||||
Flavors are a way to describe the basic dimensions of a server to be
|
||||
created including how much ``cpu``, ``ram``, and ``disk space`` are
|
||||
allocated to an instance built with this flavor.
|
||||
allocated to a server built with this flavor.
|
||||
|
||||
List Flavors
|
||||
============
|
||||
@ -189,7 +189,7 @@ Delete Flavor
|
||||
Deletes a flavor.
|
||||
|
||||
This is typically an admin only action. Deleting a flavor that is in use by
|
||||
existing instances is not recommended as it can cause incorrect data to
|
||||
existing servers is not recommended as it can cause incorrect data to
|
||||
be returned to the user under some operations.
|
||||
|
||||
Normal response codes: 204
|
||||
|
@ -7,9 +7,9 @@ Baremetal Compute API V1 (CURRENT)
|
||||
.. rest_expand_all::
|
||||
|
||||
.. include:: urls.inc
|
||||
.. include:: instances.inc
|
||||
.. include:: instance_states.inc
|
||||
.. include:: instance_networks.inc
|
||||
.. include:: servers.inc
|
||||
.. include:: server_states.inc
|
||||
.. include:: server_networks.inc
|
||||
.. include:: flavors.inc
|
||||
.. include:: flavor_access.inc
|
||||
.. include:: availability_zones.inc
|
||||
|
@ -1,35 +0,0 @@
|
||||
.. -*- rst -*-
|
||||
|
||||
========================
|
||||
Instance Serial Console
|
||||
========================
|
||||
|
||||
Instances Serial Console can be managed through serial_console sub-resource.
|
||||
|
||||
|
||||
Instance Serial Console Summary
|
||||
===============================
|
||||
|
||||
.. rest_method:: GET /v1/instances/{instance_uuid}/serial_console
|
||||
|
||||
Get the console url info of the Instance.
|
||||
|
||||
Normal response code: 200
|
||||
|
||||
Request
|
||||
-------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- instance_uuid: instance_ident
|
||||
|
||||
Response
|
||||
--------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- console: console_info
|
||||
|
||||
**Example instance network:**
|
||||
|
||||
.. literalinclude:: samples/instance_console/instance-serial-console-get.json
|
@ -1,140 +0,0 @@
|
||||
.. -*- rst -*-
|
||||
|
||||
=================
|
||||
Instance States
|
||||
=================
|
||||
|
||||
Instances States can be managed through states sub-resource.
|
||||
|
||||
A Instance can be rebooted, turned on, or turned off by requesting a change to
|
||||
its power state.
|
||||
|
||||
|
||||
Instance State Summary
|
||||
======================
|
||||
|
||||
.. rest_method:: GET /v1/instances/{instance_uuid}/states
|
||||
|
||||
Get a summary of the Instance's current states.
|
||||
|
||||
Normal response code: 200
|
||||
|
||||
Request
|
||||
-------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- instance_uuid: instance_ident
|
||||
|
||||
Response
|
||||
--------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- power_state: power_state
|
||||
- locked: lock_state
|
||||
- status: instance_status
|
||||
|
||||
**Example instance state:**
|
||||
|
||||
.. literalinclude:: samples/instance_states/instance-get-state-response.json
|
||||
|
||||
|
||||
Change Instance Power State
|
||||
===========================
|
||||
|
||||
.. rest_method:: PUT /v1/instances/{instance_uuid}/states/power
|
||||
|
||||
Request a change to the Instance's power state.
|
||||
|
||||
Normal response code: 202
|
||||
|
||||
Error codes:
|
||||
- 409 (ClientError)
|
||||
- 400 (InvalidState)
|
||||
- 406 (NotAcceptable)
|
||||
|
||||
Request
|
||||
-------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- instance_uuid: instance_ident
|
||||
- target: power_state_target
|
||||
|
||||
**Example request to power off a Instance:**
|
||||
|
||||
.. literalinclude:: samples/instance_states/instance-set-power-off.json
|
||||
|
||||
Response
|
||||
--------
|
||||
|
||||
If successful, this method does not return content in the response body.
|
||||
|
||||
|
||||
Change Instance Lock State
|
||||
===========================
|
||||
|
||||
.. rest_method:: PUT /v1/instances/{instance_uuid}/states/lock
|
||||
|
||||
Request a change to the Instance's lockstate.
|
||||
|
||||
Normal response code: 202
|
||||
|
||||
Error codes:
|
||||
- 409 (ClientError)
|
||||
- 400 (BadRequest)
|
||||
- 403 (Forbidden)
|
||||
|
||||
Request
|
||||
-------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- instance_uuid: instance_ident
|
||||
- target: lock_state
|
||||
|
||||
**Example request to lock an Instance:**
|
||||
|
||||
.. literalinclude:: samples/instance_states/lock-instance.json
|
||||
|
||||
**Example request to unlock an Instance:**
|
||||
|
||||
.. literalinclude:: samples/instance_states/unlock-instance.json
|
||||
|
||||
Response
|
||||
--------
|
||||
|
||||
If successful, this method does not return content in the response body.
|
||||
|
||||
|
||||
Change Instance Provision State
|
||||
===============================
|
||||
|
||||
.. rest_method:: PUT /v1/instances/{instance_uuid}/states/provision
|
||||
|
||||
Request a change to the Instance's provision state.
|
||||
|
||||
Normal response code: 202
|
||||
|
||||
Error codes:
|
||||
- 409 (ClientError)
|
||||
- 400 (BadRequest)
|
||||
- 403 (Forbidden)
|
||||
|
||||
Request
|
||||
-------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- instance_uuid: instance_ident
|
||||
- target: provision_state
|
||||
|
||||
**Example request to rebuild an Instance:**
|
||||
|
||||
.. literalinclude:: samples/instance_states/rebuild-instance.json
|
||||
|
||||
Response
|
||||
--------
|
||||
|
||||
If successful, this method does not return content in the response body.
|
@ -27,9 +27,9 @@ flavor_uuid_path:
|
||||
in: path
|
||||
required: true
|
||||
type: string
|
||||
instance_ident:
|
||||
server_ident:
|
||||
description: |
|
||||
The UUID of the instance.
|
||||
The UUID of the server.
|
||||
in: path
|
||||
required: true
|
||||
type: string
|
||||
@ -49,7 +49,7 @@ tenant_id_path:
|
||||
# variables in query
|
||||
all_tenants:
|
||||
description: |
|
||||
Specify the ``all_tenants=1`` query parameter to list all instances
|
||||
Specify the ``all_tenants=1`` query parameter to list all servers
|
||||
for all projects. By default this is only allowed by admin users.
|
||||
in: query
|
||||
required: false
|
||||
@ -59,11 +59,11 @@ fields:
|
||||
One or more fields to be returned in the response.
|
||||
|
||||
For example, the following request returns only the ``uuid``
|
||||
and ``name`` fields for each instance:
|
||||
and ``name`` fields for each server:
|
||||
|
||||
::
|
||||
|
||||
GET /v1/instances?fields=uuid,name
|
||||
GET /v1/servers?fields=uuid,name
|
||||
in: query
|
||||
required: false
|
||||
type: array
|
||||
@ -84,11 +84,11 @@ address:
|
||||
type: string
|
||||
availability_zone:
|
||||
description: |
|
||||
The availability zone from which to launch the instance. When you provision resources,
|
||||
you specify from which availability zone you want your instance to be built. Typically,
|
||||
The availability zone from which to launch the server. When you provision resources,
|
||||
you specify from which availability zone you want your server to be built. Typically,
|
||||
you use availability zones to arrange bare metal nodes into logical groups.
|
||||
An availability zone provides a form of physical isolation and redundancy from
|
||||
other availability zones. For instance, if some racks in your data center are
|
||||
other availability zones. For server, if some racks in your data center are
|
||||
on a separate power source, you can put servers in those racks in their own availability
|
||||
zone. Availability zones can also help separate different classes of hardware. By
|
||||
segregating resources into availability zones, you can ensure that your application
|
||||
@ -183,7 +183,7 @@ flavor_uuid_not_required:
|
||||
type: string
|
||||
flavorRef:
|
||||
description: |
|
||||
The flavor reference, as a UUID for the flavor for your server instance.
|
||||
The flavor reference, as a UUID for the flavor for your server server.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
@ -195,39 +195,7 @@ flavors:
|
||||
type: array
|
||||
imageRef:
|
||||
description: |
|
||||
The UUID of the image to use for your instance.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
instance_description:
|
||||
description: |
|
||||
A free form description of the instance. Limited to 255 characters
|
||||
in length.
|
||||
in: body
|
||||
required: false
|
||||
type: string
|
||||
instance_name:
|
||||
description: |
|
||||
The instance name.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
instance_power_state:
|
||||
description: |
|
||||
The current power state of this instance. Usually, “power on” or “power off”, but may be “None”
|
||||
if Mogan is unable to determine the power state (eg, due to hardware failure)
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
instance_status:
|
||||
description: |
|
||||
The status of this instance. Usually, "building", "active", "error", or "None".
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
instance_uuid:
|
||||
description: |
|
||||
The UUID of the instance
|
||||
The UUID of the image to use for your server.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
@ -304,7 +272,7 @@ keypairs:
|
||||
Array of Keypair objects
|
||||
launched_at:
|
||||
description: |
|
||||
The date and time when the instance was launched. The date and time
|
||||
The date and time when the server was launched. The date and time
|
||||
stamp format is `ISO 8601 <https://en.wikipedia.org/wiki/ISO_8601>`_
|
||||
|
||||
::
|
||||
@ -325,23 +293,23 @@ links:
|
||||
type: array
|
||||
lock_state:
|
||||
description: |
|
||||
The request to lock/unlock instances.
|
||||
The request to lock/unlock servers.
|
||||
in: body
|
||||
required: true
|
||||
type: boolean
|
||||
max_count_body:
|
||||
description: |
|
||||
The max number of instances to be created. Defaults to the value of ``min_count``.
|
||||
The max number of servers to be created. Defaults to the value of ``min_count``.
|
||||
in: body
|
||||
required: false
|
||||
type: integer
|
||||
min_count_body:
|
||||
description: |
|
||||
The min number of instances to be created. Defaults to 1.
|
||||
The min number of servers to be created. Defaults to 1.
|
||||
in: body
|
||||
required: false
|
||||
type: integer
|
||||
multi_instacne_name_body:
|
||||
multi_server_name_body:
|
||||
description: |
|
||||
A base name for creating unique names during multiple create. A unique
|
||||
string will be appended to the end of this base name for every instacne
|
||||
@ -351,30 +319,30 @@ multi_instacne_name_body:
|
||||
type: string
|
||||
network_info:
|
||||
description: |
|
||||
The port info in the requested network for the instance, with fixed_ip, mac_address, and
|
||||
The port info in the requested network for the server, with fixed_ip, mac_address, and
|
||||
network uuid
|
||||
in: body
|
||||
required: true
|
||||
type: dict
|
||||
network_port_type:
|
||||
description: |
|
||||
To provision the server instance with a specified type of NIC(like 1GE or 10 GE) for a
|
||||
To provision the server server with a specified type of NIC(like 1GE or 10 GE) for a
|
||||
network, specify the type of the NIC in the ``port_type`` key in a dict in ``networks`` list.
|
||||
in: body
|
||||
required: false
|
||||
type: string
|
||||
network_uuid:
|
||||
description: |
|
||||
To provision the server instance with a NIC for a network, specify the UUID of
|
||||
To provision the server server with a NIC for a network, specify the UUID of
|
||||
the network in the ``uuid`` key in a dict in ``networks`` list.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
networks:
|
||||
description: |
|
||||
A list of networks of the tenant. Optionally, you can create one or more NICs on the instance.
|
||||
To provision the server instance with a NIC for a network, specify the UUID of the network
|
||||
in the ``uuid`` key in a dict in ``networks`` list. To provision the server instance with a
|
||||
A list of networks of the tenant. Optionally, you can create one or more NICs on the server.
|
||||
To provision the server server with a NIC for a network, specify the UUID of the network
|
||||
in the ``uuid`` key in a dict in ``networks`` list. To provision the server server with a
|
||||
specified type of NIC, specify the port-type key in a dict in a ``networks`` list.
|
||||
in: body
|
||||
required: true
|
||||
@ -389,7 +357,7 @@ personality:
|
||||
type: string
|
||||
power_state:
|
||||
description: |
|
||||
The current power state of this Instance. Usually, "power on" or
|
||||
The current power state of this Server. Usually, "power on" or
|
||||
"power off", but may be "None" if Mogan is unable to determine the power
|
||||
state (eg, due to hardware failure).
|
||||
in: body
|
||||
@ -414,6 +382,38 @@ provision_state:
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
server_description:
|
||||
description: |
|
||||
A free form description of the server. Limited to 255 characters
|
||||
in length.
|
||||
in: body
|
||||
required: false
|
||||
type: string
|
||||
server_name:
|
||||
description: |
|
||||
The server name.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
server_power_state:
|
||||
description: |
|
||||
The current power state of this server. Usually, “power on” or “power off”, but may be “None”
|
||||
if Mogan is unable to determine the power state (eg, due to hardware failure)
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
server_status:
|
||||
description: |
|
||||
The status of this server. Usually, "building", "active", "error", or "None".
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
server_uuid:
|
||||
description: |
|
||||
The UUID of the server
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
tenant_id_body:
|
||||
description: |
|
||||
The UUID of the tenant in a multi-tenancy cloud.
|
||||
@ -443,7 +443,7 @@ user_data:
|
||||
type: string
|
||||
user_id_body:
|
||||
description: |
|
||||
The user ID of the user who owns the instance.
|
||||
The user ID of the user who owns the server.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "test_instance",
|
||||
"description": "this is a test instance",
|
||||
"instance_type_uuid": "0607b5f3-6111-424d-ba46-f5de39a6fa69",
|
||||
"name": "test_server",
|
||||
"description": "this is a test server",
|
||||
"flavor_uuid": "0607b5f3-6111-424d-ba46-f5de39a6fa69",
|
||||
"image_uuid": "efe0a06f-ca95-4808-b41e-9f55b9c5eb98",
|
||||
"networks": [
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "test_instance",
|
||||
"description": "this is a test instance",
|
||||
"instance_type_uuid": "0607b5f3-6111-424d-ba46-f5de39a6fa69",
|
||||
"name": "test_server",
|
||||
"description": "this is a test server",
|
||||
"flavor_uuid": "0607b5f3-6111-424d-ba46-f5de39a6fa69",
|
||||
"image_uuid": "efe0a06f-ca95-4808-b41e-9f55b9c5eb98",
|
||||
"availability_zone": "mogan",
|
||||
"networks": [
|
@ -1,18 +1,18 @@
|
||||
{
|
||||
"name": "test_instance",
|
||||
"description": "this is a test instance",
|
||||
"instance_type_uuid": "0607b5f3-6111-424d-ba46-f5de39a6fa69",
|
||||
"name": "test_server",
|
||||
"description": "this is a test server",
|
||||
"flavor_uuid": "0607b5f3-6111-424d-ba46-f5de39a6fa69",
|
||||
"image_uuid": "efe0a06f-ca95-4808-b41e-9f55b9c5eb98",
|
||||
"availability_zone" : "Beijing-01",
|
||||
"status": "active",
|
||||
"power_state": "on",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://10.3.150.17:6688/v1/instances/7de2859d-ec6d-42c7-bb86-9d630ba5ac94",
|
||||
"href": "http://10.3.150.17:6688/v1/servers/7de2859d-ec6d-42c7-bb86-9d630ba5ac94",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://10.3.150.17:6688/instances/7de2859d-ec6d-42c7-bb86-9d630ba5ac94",
|
||||
"href": "http://10.3.150.17:6688/servers/7de2859d-ec6d-42c7-bb86-9d630ba5ac94",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
@ -1,20 +1,20 @@
|
||||
{
|
||||
"availability_zone": null,
|
||||
"created_at": "2016-10-17T04:12:41+00:00",
|
||||
"description": "this is a test instance",
|
||||
"description": "this is a test server",
|
||||
"image_uuid": "ac3b2291-b9ef-45f6-8eeb-21ac568a64a5",
|
||||
"instance_type_uuid": "28708dff-283c-449e-9bfa-a48c93480c86",
|
||||
"flavor_uuid": "28708dff-283c-449e-9bfa-a48c93480c86",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://localhost:6688/v1/instances/f978ef48-d4af-4dad-beec-e6174309bc71",
|
||||
"href": "http://localhost:6688/v1/servers/f978ef48-d4af-4dad-beec-e6174309bc71",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://localhost:6688/instances/f978ef48-d4af-4dad-beec-e6174309bc71",
|
||||
"href": "http://localhost:6688/servers/f978ef48-d4af-4dad-beec-e6174309bc71",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "test_instance",
|
||||
"name": "test_server",
|
||||
"network_info": {
|
||||
"12cffc4a-b845-409e-b589-7c84be4b10d9": {
|
||||
"fixed_ips": [
|
@ -1,22 +1,22 @@
|
||||
{
|
||||
"instances": [
|
||||
"servers": [
|
||||
{
|
||||
"availability_zone": null,
|
||||
"created_at": "2016-10-17T04:12:41+00:00",
|
||||
"description": "this is a test instance",
|
||||
"description": "this is a test server",
|
||||
"image_uuid": "ac3b2291-b9ef-45f6-8eeb-21ac568a64a5",
|
||||
"instance_type_uuid": "28708dff-283c-449e-9bfa-a48c93480c86",
|
||||
"flavor_uuid": "28708dff-283c-449e-9bfa-a48c93480c86",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://localhost:6688/v1/instances/f978ef48-d4af-4dad-beec-e6174309bc71",
|
||||
"href": "http://localhost:6688/v1/servers/f978ef48-d4af-4dad-beec-e6174309bc71",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://localhost:6688/instances/f978ef48-d4af-4dad-beec-e6174309bc71",
|
||||
"href": "http://localhost:6688/servers/f978ef48-d4af-4dad-beec-e6174309bc71",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "test_instance",
|
||||
"name": "test_server",
|
||||
"network_info": {
|
||||
"12cffc4a-b845-409e-b589-7c84be4b10d9": {
|
||||
"fixed_ips": [
|
@ -1,18 +1,18 @@
|
||||
{
|
||||
"instances": [
|
||||
"servers": [
|
||||
{
|
||||
"description": "this is a test instance",
|
||||
"description": "this is a test server",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://localhost:6688/v1/instances/f978ef48-d4af-4dad-beec-e6174309bc71",
|
||||
"href": "http://localhost:6688/v1/servers/f978ef48-d4af-4dad-beec-e6174309bc71",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://localhost:6688/instances/f978ef48-d4af-4dad-beec-e6174309bc71",
|
||||
"href": "http://localhost:6688/servers/f978ef48-d4af-4dad-beec-e6174309bc71",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "test_instance",
|
||||
"name": "test_server",
|
||||
"status": "building",
|
||||
"power_state": "power on",
|
||||
"uuid": "f978ef48-d4af-4dad-beec-e6174309bc71"
|
@ -1,18 +1,18 @@
|
||||
{
|
||||
"name": "test_instance",
|
||||
"description": "this is a test instance",
|
||||
"instance_type_uuid": "0607b5f3-6111-424d-ba46-f5de39a6fa69",
|
||||
"name": "test_server",
|
||||
"description": "this is a test server",
|
||||
"flavor_uuid": "0607b5f3-6111-424d-ba46-f5de39a6fa69",
|
||||
"image_uuid": "efe0a06f-ca95-4808-b41e-9f55b9c5eb98",
|
||||
"availability_zone": "Beijing-01",
|
||||
"status": "active",
|
||||
"power_state": "on",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://10.3.150.17:6688/v1/instances/7de2859d-ec6d-42c7-bb86-9d630ba5ac94",
|
||||
"href": "http://10.3.150.17:6688/v1/servers/7de2859d-ec6d-42c7-bb86-9d630ba5ac94",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://10.3.150.17:6688/instances/7de2859d-ec6d-42c7-bb86-9d630ba5ac94",
|
||||
"href": "http://10.3.150.17:6688/servers/7de2859d-ec6d-42c7-bb86-9d630ba5ac94",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
@ -1,21 +1,21 @@
|
||||
.. -*- rst -*-
|
||||
|
||||
===================
|
||||
Instance Networks
|
||||
Server Networks
|
||||
===================
|
||||
|
||||
Instances Networks can be managed through networks sub-resource.
|
||||
Servers Networks can be managed through networks sub-resource.
|
||||
|
||||
A Instance can be associated or dissociated with a floating IP by requesting
|
||||
A Server can be associated or dissociated with a floating IP by requesting
|
||||
the floatingip sub-resource.
|
||||
|
||||
|
||||
Instance Network Summary
|
||||
Server Network Summary
|
||||
========================
|
||||
|
||||
.. rest_method:: GET /v1/instances/{instance_uuid}/networks
|
||||
.. rest_method:: GET /v1/servers/{server_uuid}/networks
|
||||
|
||||
Get a summary of the Instance's networks.
|
||||
Get a summary of the Server's networks.
|
||||
|
||||
Normal response code: 200
|
||||
|
||||
@ -24,7 +24,7 @@ Request
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- instance_uuid: instance_ident
|
||||
- server_uuid: server_ident
|
||||
|
||||
Response
|
||||
--------
|
||||
@ -33,20 +33,20 @@ Response
|
||||
|
||||
- ports: network_info
|
||||
|
||||
**Example instance network:**
|
||||
**Example server network:**
|
||||
|
||||
.. literalinclude:: samples/instance_networks/instance-get-network-response.json
|
||||
.. literalinclude:: samples/server_networks/server-get-network-response.json
|
||||
|
||||
|
||||
Add (Associate) Floating IP
|
||||
===========================
|
||||
|
||||
.. rest_method:: POST /v1/instances/{instance_uuid}/networks/floatingips
|
||||
.. rest_method:: POST /v1/servers/{server_uuid}/networks/floatingips
|
||||
|
||||
Adds a floating IP address to an instance, which associates
|
||||
that address with the instance.
|
||||
Adds a floating IP address to a server, which associates
|
||||
that address with the server.
|
||||
|
||||
If an instance is connected to multiple networks, you can associate a
|
||||
If a server is connected to multiple networks, you can associate a
|
||||
floating IP address with a specific fixed IP address by using the
|
||||
optional ``fixed_address`` parameter.
|
||||
|
||||
@ -59,13 +59,13 @@ Request
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- instance_uuid: instance_ident
|
||||
- server_uuid: server_ident
|
||||
- address: address
|
||||
- fixed_address: fixed_address
|
||||
|
||||
**Example request to Add (Associate) Floating IP to an instance:**
|
||||
**Example request to Add (Associate) Floating IP to a server:**
|
||||
|
||||
.. literalinclude:: samples/instance_networks/instance-associate-fip-req.json
|
||||
.. literalinclude:: samples/server_networks/server-associate-fip-req.json
|
||||
|
||||
Response
|
||||
--------
|
||||
@ -76,9 +76,9 @@ If successful, this method does not return content in the response body.
|
||||
Remove (Disassociate) Floating IP
|
||||
=================================
|
||||
|
||||
.. rest_method:: DELETE /v1/instances/{instance_uuid}/networks/floatingips/{fip_address}
|
||||
.. rest_method:: DELETE /v1/servers/{server_uuid}/networks/floatingips/{fip_address}
|
||||
|
||||
Removes, or disassociates, a floating IP address from an instance.
|
||||
Removes, or disassociates, a floating IP address from a server.
|
||||
|
||||
Normal response codes: 204
|
||||
|
||||
@ -90,7 +90,7 @@ Request
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- instance_uuid: instance_ident
|
||||
- server_uuid: server_ident
|
||||
- fip_address: address_path
|
||||
|
||||
Response
|
35
api-ref/source/v1/server_serial_console.inc
Normal file
35
api-ref/source/v1/server_serial_console.inc
Normal file
@ -0,0 +1,35 @@
|
||||
.. -*- rst -*-
|
||||
|
||||
========================
|
||||
Server Serial Console
|
||||
========================
|
||||
|
||||
Servers Serial Console can be managed through serial_console sub-resource.
|
||||
|
||||
|
||||
Server Serial Console Summary
|
||||
===============================
|
||||
|
||||
.. rest_method:: GET /v1/servers/{server_uuid}/serial_console
|
||||
|
||||
Get the console url info of the Server.
|
||||
|
||||
Normal response code: 200
|
||||
|
||||
Request
|
||||
-------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- server_uuid: server_ident
|
||||
|
||||
Response
|
||||
--------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- console: console_info
|
||||
|
||||
**Example server network:**
|
||||
|
||||
.. literalinclude:: samples/server_console/server-serial-console-get.json
|
140
api-ref/source/v1/server_states.inc
Normal file
140
api-ref/source/v1/server_states.inc
Normal file
@ -0,0 +1,140 @@
|
||||
.. -*- rst -*-
|
||||
|
||||
=================
|
||||
Server States
|
||||
=================
|
||||
|
||||
Servers States can be managed through states sub-resource.
|
||||
|
||||
A Server can be rebooted, turned on, or turned off by requesting a change to
|
||||
its power state.
|
||||
|
||||
|
||||
Server State Summary
|
||||
======================
|
||||
|
||||
.. rest_method:: GET /v1/servers/{server_uuid}/states
|
||||
|
||||
Get a summary of the Server's current states.
|
||||
|
||||
Normal response code: 200
|
||||
|
||||
Request
|
||||
-------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- server_uuid: server_ident
|
||||
|
||||
Response
|
||||
--------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- power_state: power_state
|
||||
- locked: lock_state
|
||||
- status: server_status
|
||||
|
||||
**Example server state:**
|
||||
|
||||
.. literalinclude:: samples/server_states/server-get-state-response.json
|
||||
|
||||
|
||||
Change Server Power State
|
||||
===========================
|
||||
|
||||
.. rest_method:: PUT /v1/servers/{server_uuid}/states/power
|
||||
|
||||
Request a change to the Server's power state.
|
||||
|
||||
Normal response code: 202
|
||||
|
||||
Error codes:
|
||||
- 409 (ClientError)
|
||||
- 400 (InvalidState)
|
||||
- 406 (NotAcceptable)
|
||||
|
||||
Request
|
||||
-------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- server_uuid: server_ident
|
||||
- target: power_state_target
|
||||
|
||||
**Example request to power off a Server:**
|
||||
|
||||
.. literalinclude:: samples/server_states/server-set-power-off.json
|
||||
|
||||
Response
|
||||
--------
|
||||
|
||||
If successful, this method does not return content in the response body.
|
||||
|
||||
|
||||
Change Server Lock State
|
||||
===========================
|
||||
|
||||
.. rest_method:: PUT /v1/servers/{server_uuid}/states/lock
|
||||
|
||||
Request a change to the Server's lockstate.
|
||||
|
||||
Normal response code: 202
|
||||
|
||||
Error codes:
|
||||
- 409 (ClientError)
|
||||
- 400 (BadRequest)
|
||||
- 403 (Forbidden)
|
||||
|
||||
Request
|
||||
-------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- server_uuid: server_ident
|
||||
- target: lock_state
|
||||
|
||||
**Example request to lock a Server:**
|
||||
|
||||
.. literalinclude:: samples/server_states/lock-server.json
|
||||
|
||||
**Example request to unlock a Server:**
|
||||
|
||||
.. literalinclude:: samples/server_states/unlock-server.json
|
||||
|
||||
Response
|
||||
--------
|
||||
|
||||
If successful, this method does not return content in the response body.
|
||||
|
||||
|
||||
Change Server Provision State
|
||||
===============================
|
||||
|
||||
.. rest_method:: PUT /v1/servers/{server_uuid}/states/provision
|
||||
|
||||
Request a change to the Server's provision state.
|
||||
|
||||
Normal response code: 202
|
||||
|
||||
Error codes:
|
||||
- 409 (ClientError)
|
||||
- 400 (BadRequest)
|
||||
- 403 (Forbidden)
|
||||
|
||||
Request
|
||||
-------
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- server_uuid: server_ident
|
||||
- target: provision_state
|
||||
|
||||
**Example request to rebuild a Server:**
|
||||
|
||||
.. literalinclude:: samples/server_states/rebuild-server.json
|
||||
|
||||
Response
|
||||
--------
|
||||
|
||||
If successful, this method does not return content in the response body.
|
@ -1,24 +1,24 @@
|
||||
.. -*- rst -*-
|
||||
|
||||
===========
|
||||
Instances
|
||||
Servers
|
||||
===========
|
||||
|
||||
Lists, creates, shows details for, updates, and deletes instances.
|
||||
Lists, creates, shows details for, updates, and deletes servers.
|
||||
|
||||
Create Instance
|
||||
Create Server
|
||||
===============
|
||||
|
||||
.. rest_method:: POST /instances
|
||||
.. rest_method:: POST /servers
|
||||
|
||||
Creates an instance.
|
||||
Creates a server.
|
||||
|
||||
The progress of this operation depends on the location of the
|
||||
requested image, network I/O, selected type, and other factors.
|
||||
|
||||
The ``Location`` header returns the full URL to the newly created
|
||||
instance and is available as a ``self`` and ``bookmark`` link in the
|
||||
instance representation.
|
||||
server and is available as a ``self`` and ``bookmark`` link in the
|
||||
server representation.
|
||||
|
||||
Normal response codes: 201
|
||||
|
||||
@ -30,9 +30,9 @@ Request
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- name: instance_name
|
||||
- description: instance_description
|
||||
- instance_type_uuid: flavorRef
|
||||
- name: server_name
|
||||
- description: server_description
|
||||
- flavor_uuid: flavorRef
|
||||
- image_uuid: imageRef
|
||||
- availability_zone: availability_zone
|
||||
- networks: networks
|
||||
@ -42,9 +42,9 @@ Request
|
||||
- personality: personality
|
||||
- key_name: key_name
|
||||
|
||||
**Example Create Instance: JSON request**
|
||||
**Example Create Server: JSON request**
|
||||
|
||||
.. literalinclude:: samples/instances/instance-create-req.json
|
||||
.. literalinclude:: samples/servers/server-create-req.json
|
||||
:language: javascript
|
||||
|
||||
Response
|
||||
@ -52,40 +52,40 @@ Response
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- name: instance_name
|
||||
- description: instance_description
|
||||
- instance_type_uuid: flavorRef
|
||||
- name: server_name
|
||||
- description: server_description
|
||||
- flavor_uuid: flavorRef
|
||||
- image_uuid: imageRef
|
||||
- availability_zone: availability_zone
|
||||
- network_info: network_info
|
||||
- links: links
|
||||
- uuid: instance_uuid
|
||||
- status: instance_status
|
||||
- power_state: instance_power_state
|
||||
- uuid: server_uuid
|
||||
- status: server_status
|
||||
- power_state: server_power_state
|
||||
- project_id: project_id_body
|
||||
- user_id: user_id_body
|
||||
- updated_at: updated_at
|
||||
- created_at: created_at
|
||||
- extra: extra
|
||||
|
||||
**Example Create Instance: JSON response**
|
||||
**Example Create Server: JSON response**
|
||||
|
||||
.. literalinclude:: samples/instances/instance-create-resp.json
|
||||
.. literalinclude:: samples/servers/server-create-resp.json
|
||||
:language: javascript
|
||||
|
||||
Create Multiple Instances
|
||||
Create Multiple Servers
|
||||
=========================
|
||||
|
||||
.. rest_method:: POST /instances
|
||||
.. rest_method:: POST /servers
|
||||
|
||||
Create Multiple Instances.
|
||||
Create Multiple Servers.
|
||||
|
||||
There is a second kind of create call which can create multiple instances
|
||||
There is a second kind of create call which can create multiple servers
|
||||
at once. This supports all the same parameters as create with a few additional
|
||||
attributes specific to multiple create.
|
||||
|
||||
Error handling for multiple create is not as consistent as for single instance
|
||||
create, and there is no guarantee that all the instances will be created
|
||||
Error handling for multiple create is not as consistent as for single server
|
||||
create, and there is no guarantee that all the servers will be created
|
||||
successfully.
|
||||
|
||||
Normal response codes: 201
|
||||
@ -100,37 +100,37 @@ These are the parameters beyond single create that are supported.
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- name: multi_instacne_name_body
|
||||
- name: multi_server_name_body
|
||||
- min_count: min_count_body
|
||||
- max_count: max_count_body
|
||||
|
||||
**Example Create Multiple Instance: JSON request**
|
||||
**Example Create Multiple Server: JSON request**
|
||||
|
||||
.. literalinclude:: samples/instances/multi-instance-create-req.json
|
||||
.. literalinclude:: samples/servers/multi-server-create-req.json
|
||||
:language: javascript
|
||||
|
||||
Response
|
||||
--------
|
||||
|
||||
The first instance will be returned. The returned paramaters is same to creating
|
||||
a single instance's.
|
||||
The first server will be returned. The returned paramaters is same to creating
|
||||
a single server's.
|
||||
|
||||
**Example Create Multiple Instance: JSON response**
|
||||
**Example Create Multiple Server: JSON response**
|
||||
|
||||
.. literalinclude:: samples/instances/instance-create-resp.json
|
||||
.. literalinclude:: samples/servers/server-create-resp.json
|
||||
:language: javascript
|
||||
|
||||
|
||||
List Instances
|
||||
List Servers
|
||||
===============
|
||||
|
||||
.. rest_method:: GET /instances
|
||||
.. rest_method:: GET /servers
|
||||
|
||||
Return a list of bare metal Instances, with some useful information about each
|
||||
Instance.
|
||||
Return a list of bare metal Servers, with some useful information about each
|
||||
Server.
|
||||
|
||||
By default, this query will return the name, instance uuid, instance status
|
||||
and description for each Instance.
|
||||
By default, this query will return the name, server uuid, server status
|
||||
and description for each Server.
|
||||
|
||||
Normal response codes: 200
|
||||
|
||||
@ -150,25 +150,25 @@ Response
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- name: instance_name
|
||||
- description: instance_description
|
||||
- uuid: instance_uuid
|
||||
- status: instance_status
|
||||
- power_state: instance_power_state
|
||||
- name: server_name
|
||||
- description: server_description
|
||||
- uuid: server_uuid
|
||||
- status: server_status
|
||||
- power_state: server_power_state
|
||||
- links: links
|
||||
|
||||
**Example List of Instances: JSON response**
|
||||
**Example List of Servers: JSON response**
|
||||
|
||||
.. literalinclude:: samples/instances/instance-list-resp.json
|
||||
.. literalinclude:: samples/servers/server-list-resp.json
|
||||
:language: javascript
|
||||
|
||||
|
||||
List Instances Detailed
|
||||
List Servers Detailed
|
||||
=======================
|
||||
|
||||
.. rest_method:: GET /instances/detail
|
||||
.. rest_method:: GET /servers/detail
|
||||
|
||||
Return a list of bare metal Instances with complete details.
|
||||
Return a list of bare metal Servers with complete details.
|
||||
|
||||
Normal response codes: 200
|
||||
|
||||
@ -185,16 +185,16 @@ Response
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- name: instance_name
|
||||
- description: instance_description
|
||||
- instance_type_uuid: flavorRef
|
||||
- name: server_name
|
||||
- description: server_description
|
||||
- flavor_uuid: flavorRef
|
||||
- image_uuid: imageRef
|
||||
- availability_zone: availability_zone
|
||||
- network_info: network_info
|
||||
- links: links
|
||||
- uuid: instance_uuid
|
||||
- status: instance_status
|
||||
- power_state: instance_power_state
|
||||
- uuid: server_uuid
|
||||
- status: server_status
|
||||
- power_state: server_power_state
|
||||
- project_id: project_id_body
|
||||
- user_id: user_id_body
|
||||
- updated_at: updated_at
|
||||
@ -202,18 +202,18 @@ Response
|
||||
- launched_at: launched_at
|
||||
- extra: extra
|
||||
|
||||
**Example Detailed list of Instances: JSON response**
|
||||
**Example Detailed list of Servers: JSON response**
|
||||
|
||||
.. literalinclude:: samples/instances/instance-list-detail-resp.json
|
||||
.. literalinclude:: samples/servers/server-list-detail-resp.json
|
||||
:language: javascript
|
||||
|
||||
|
||||
Show Instance Details
|
||||
Show Server Details
|
||||
=====================
|
||||
|
||||
.. rest_method:: GET /instances/{instance_uuid}
|
||||
.. rest_method:: GET /servers/{server_uuid}
|
||||
|
||||
Shows details of an instance. By default, this will return the full
|
||||
Shows details of a server. By default, this will return the full
|
||||
representation of the resource; an optional fields parameter can be supplied to
|
||||
return only the specified set.
|
||||
|
||||
@ -227,7 +227,7 @@ Request
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- instance_uuid: instance_ident
|
||||
- server_uuid: server_ident
|
||||
- fields: fields
|
||||
|
||||
Response
|
||||
@ -235,16 +235,16 @@ Response
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- name: instance_name
|
||||
- description: instance_description
|
||||
- instance_type_uuid: flavorRef
|
||||
- name: server_name
|
||||
- description: server_description
|
||||
- flavor_uuid: flavorRef
|
||||
- image_uuid: imageRef
|
||||
- availability_zone: availability_zone
|
||||
- network_info: network_info
|
||||
- links: links
|
||||
- uuid: instance_uuid
|
||||
- status: instance_status
|
||||
- power_state: instance_power_state
|
||||
- uuid: server_uuid
|
||||
- status: server_status
|
||||
- power_state: server_power_state
|
||||
- project_id: project_id_body
|
||||
- user_id: user_id_body
|
||||
- updated_at: updated_at
|
||||
@ -252,18 +252,18 @@ Response
|
||||
- launched_at: launched_at
|
||||
- extra: extra
|
||||
|
||||
**Example Instance Details: JSON response**
|
||||
**Example Server Details: JSON response**
|
||||
|
||||
.. literalinclude:: samples/instances/instance-detail-resp.json
|
||||
.. literalinclude:: samples/servers/server-detail-resp.json
|
||||
:language: javascript
|
||||
|
||||
|
||||
Update Instance
|
||||
Update Server
|
||||
===============
|
||||
|
||||
.. rest_method:: PATCH /instances/{instance_uuid}
|
||||
.. rest_method:: PATCH /servers/{server_uuid}
|
||||
|
||||
Updates the infromation stored about an instance.
|
||||
Updates the infromation stored about a server.
|
||||
|
||||
Normal response codes: 200
|
||||
|
||||
@ -278,11 +278,11 @@ The BODY of the PATCH request must be a JSON PATCH document, adhering to
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- instance_uuid: instance_ident
|
||||
- server_uuid: server_ident
|
||||
|
||||
**Example Update Instance: JSON request**
|
||||
**Example Update Server: JSON request**
|
||||
|
||||
.. literalinclude:: samples/instances/instance-update-req.json
|
||||
.. literalinclude:: samples/servers/server-update-req.json
|
||||
:language: javascript
|
||||
|
||||
Response
|
||||
@ -290,38 +290,38 @@ Response
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- name: instance_name
|
||||
- description: instance_description
|
||||
- instance_type_uuid: flavorRef
|
||||
- name: server_name
|
||||
- description: server_description
|
||||
- flavor_uuid: flavorRef
|
||||
- image_uuid: imageRef
|
||||
- availability_zone: availability_zone
|
||||
- network_info: network_info
|
||||
- links: links
|
||||
- uuid: instance_uuid
|
||||
- status: instance_status
|
||||
- power_state: instance_power_state
|
||||
- uuid: server_uuid
|
||||
- status: server_status
|
||||
- power_state: server_power_state
|
||||
- project_id: project_id_body
|
||||
- user_id: user_id_body
|
||||
- updated_at: updated_at
|
||||
- created_at: created_at
|
||||
- extra: extra
|
||||
|
||||
**Example Update Instance: JSON response**
|
||||
**Example Update Server: JSON response**
|
||||
|
||||
.. literalinclude:: samples/instances/instance-update-resp.json
|
||||
.. literalinclude:: samples/servers/server-update-resp.json
|
||||
:language: javascript
|
||||
|
||||
|
||||
Delete Instance
|
||||
Delete Server
|
||||
===============
|
||||
|
||||
.. rest_method:: DELETE /instances/{instance_uuid}
|
||||
.. rest_method:: DELETE /servers/{server_uuid}
|
||||
|
||||
Deletes an instance.
|
||||
Deletes a server.
|
||||
|
||||
Preconditions
|
||||
|
||||
- The instance must exist.
|
||||
- The server must exist.
|
||||
|
||||
Normal response codes: 204
|
||||
|
||||
@ -332,7 +332,7 @@ Request
|
||||
|
||||
.. rest_parameters:: parameters.yaml
|
||||
|
||||
- instance_uuid: instance_ident
|
||||
- server_uuid: server_ident
|
||||
|
||||
Response
|
||||
--------
|
@ -12,7 +12,7 @@ will be added to build a full path.
|
||||
|
||||
For instance, if the ``service url`` is
|
||||
``http://mycompute.pvt/mogan/v1`` then the full API call for
|
||||
``/instances`` is ``http://mycompute.pvt/mogan/v1/instances``.
|
||||
``/servers`` is ``http://mycompute.pvt/mogan/v1/servers``.
|
||||
|
||||
Depending on the deployment the baremetal compute service url might
|
||||
be http or https, a custom port, a custom path, and include your
|
||||
@ -23,5 +23,5 @@ to work at a single site. It should always be discovered from the
|
||||
Identity token.
|
||||
|
||||
As such, for the rest of this document we will be using short hand
|
||||
where ``GET /instances`` really means ``GET
|
||||
{your_service_url}/instances``.
|
||||
where ``GET /servers`` really means ``GET
|
||||
{your_service_url}/servers``.
|
||||
|
@ -193,7 +193,7 @@ if is_service_enabled mogan; then
|
||||
echo_summary "Initializing mogan"
|
||||
init_mogan
|
||||
start_mogan
|
||||
echo_summary "Creating instance type"
|
||||
echo_summary "Creating flavor"
|
||||
create_flavor
|
||||
echo_summary "Updating ironic node properties"
|
||||
update_ironic_node_type
|
||||
|
@ -1,11 +1,11 @@
|
||||
{
|
||||
"event_type": "instance.create.start",
|
||||
"event_type": "server.create.start",
|
||||
"payload": {
|
||||
"mogan_object.name": "InstanceActionPayload",
|
||||
"mogan_object.name": "ServerActionPayload",
|
||||
"mogan_object.namespace": "mogan",
|
||||
"mogan_object.version": "1.0",
|
||||
"mogan_object.data": {
|
||||
"instance_type_uuid": "6ce9904f-c61f-4ee8-afbe-c852c05258f6",
|
||||
"flavor_uuid": "6ce9904f-c61f-4ee8-afbe-c852c05258f6",
|
||||
"status": "building",
|
||||
"user_id": "dfc14a6e939646d1929362de1758d7b2",
|
||||
"uuid": "e1a7b5b7-c76c-4459-8328-10deda95819f",
|
@ -350,14 +350,14 @@ Run stack.sh::
|
||||
|
||||
./stack.sh
|
||||
|
||||
Source credentials, and spawn an instance as the ``demo`` user::
|
||||
Source credentials, and spawn a server as the ``demo`` user::
|
||||
|
||||
source ~/devstack/openrc
|
||||
|
||||
# query the image id of the default cirros image
|
||||
image=$(openstack image show $DEFAULT_IMAGE_NAME -f value -c id)
|
||||
|
||||
# spawn instance
|
||||
# spawn server
|
||||
As our moganclient is not ready now, will add this soon...
|
||||
|
||||
Building developer documentation
|
||||
|
@ -27,8 +27,8 @@ from mogan.api.controllers import base
|
||||
from mogan.api.controllers import link
|
||||
from mogan.api.controllers.v1 import availability_zone
|
||||
from mogan.api.controllers.v1 import flavors
|
||||
from mogan.api.controllers.v1 import instances
|
||||
from mogan.api.controllers.v1 import keypairs
|
||||
from mogan.api.controllers.v1 import servers
|
||||
from mogan.api import expose
|
||||
|
||||
|
||||
@ -38,11 +38,11 @@ class V1(base.APIBase):
|
||||
id = wtypes.text
|
||||
"""The ID of the version, also acts as the release number"""
|
||||
|
||||
instances = [link.Link]
|
||||
"""Links to the instances resource"""
|
||||
servers = [link.Link]
|
||||
"""Links to the servers resource"""
|
||||
|
||||
flavors = [link.Link]
|
||||
"""Links to the instance types resource"""
|
||||
"""Links to the server types resource"""
|
||||
|
||||
availability_zones = [link.Link]
|
||||
"""Links to the availability zones resource"""
|
||||
@ -54,13 +54,13 @@ class V1(base.APIBase):
|
||||
def convert():
|
||||
v1 = V1()
|
||||
v1.id = "v1"
|
||||
v1.instances = [link.Link.make_link('self', pecan.request.public_url,
|
||||
'instances', ''),
|
||||
link.Link.make_link('bookmark',
|
||||
pecan.request.public_url,
|
||||
'instances', '',
|
||||
bookmark=True)
|
||||
]
|
||||
v1.servers = [link.Link.make_link('self', pecan.request.public_url,
|
||||
'servers', ''),
|
||||
link.Link.make_link('bookmark',
|
||||
pecan.request.public_url,
|
||||
'servers', '',
|
||||
bookmark=True)
|
||||
]
|
||||
v1.flavors = [link.Link.make_link('self', pecan.request.public_url,
|
||||
'flavors', ''),
|
||||
link.Link.make_link('bookmark',
|
||||
@ -91,7 +91,7 @@ class Controller(rest.RestController):
|
||||
"""Version 1 API controller root."""
|
||||
|
||||
flavors = flavors.FlavorsController()
|
||||
instances = instances.InstanceController()
|
||||
servers = servers.ServerController()
|
||||
availability_zones = availability_zone.AvailabilityZoneController()
|
||||
keypairs = keypairs.KeyPairController()
|
||||
|
||||
|
@ -65,7 +65,7 @@ class Flavor(base.APIBase):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.fields = []
|
||||
for field in objects.InstanceType.fields:
|
||||
for field in objects.Flavor.fields:
|
||||
# Skip fields we do not expose.
|
||||
if not hasattr(self, field):
|
||||
continue
|
||||
@ -109,8 +109,7 @@ class FlavorExtraSpecsController(rest.RestController):
|
||||
def get_all(self, flavor_uuid):
|
||||
"""Retrieve a list of extra specs of the queried flavor."""
|
||||
|
||||
flavor = objects.InstanceType.get(pecan.request.context,
|
||||
flavor_uuid)
|
||||
flavor = objects.Flavor.get(pecan.request.context, flavor_uuid)
|
||||
return dict(extra_specs=flavor.extra_specs)
|
||||
|
||||
@expose.expose(types.jsontype, types.uuid, body=types.jsontype,
|
||||
@ -118,8 +117,7 @@ class FlavorExtraSpecsController(rest.RestController):
|
||||
def patch(self, flavor_uuid, extra_spec):
|
||||
"""Create/update extra specs for the given flavor."""
|
||||
|
||||
flavor = objects.InstanceType.get(pecan.request.context,
|
||||
flavor_uuid)
|
||||
flavor = objects.Flavor.get(pecan.request.context, flavor_uuid)
|
||||
flavor.extra_specs = dict(flavor.extra_specs, **extra_spec)
|
||||
flavor.save()
|
||||
return dict(extra_specs=flavor.extra_specs)
|
||||
@ -129,8 +127,7 @@ class FlavorExtraSpecsController(rest.RestController):
|
||||
def delete(self, flavor_uuid, spec_name):
|
||||
"""Delete an extra specs for the given flavor."""
|
||||
|
||||
flavor = objects.InstanceType.get(pecan.request.context,
|
||||
flavor_uuid)
|
||||
flavor = objects.Flavor.get(pecan.request.context, flavor_uuid)
|
||||
del flavor.extra_specs[spec_name]
|
||||
flavor.save()
|
||||
|
||||
@ -142,8 +139,8 @@ class FlavorAccessController(rest.RestController):
|
||||
def get_all(self, flavor_uuid):
|
||||
"""Retrieve a list of extra specs of the queried flavor."""
|
||||
|
||||
flavor = objects.InstanceType.get(pecan.request.context,
|
||||
flavor_uuid)
|
||||
flavor = objects.Flavor.get(pecan.request.context,
|
||||
flavor_uuid)
|
||||
|
||||
# public flavor to all projects
|
||||
if flavor.is_public:
|
||||
@ -160,8 +157,8 @@ class FlavorAccessController(rest.RestController):
|
||||
"""Add flavor access for the given tenant."""
|
||||
validation.check_schema(tenant, flavor_access.add_tenant_access)
|
||||
|
||||
flavor = objects.InstanceType.get(pecan.request.context,
|
||||
flavor_uuid)
|
||||
flavor = objects.Flavor.get(pecan.request.context,
|
||||
flavor_uuid)
|
||||
if flavor.is_public:
|
||||
msg = _("Can not add access to a public flavor.")
|
||||
raise wsme.exc.ClientSideError(
|
||||
@ -182,8 +179,8 @@ class FlavorAccessController(rest.RestController):
|
||||
def delete(self, flavor_uuid, tenant_id):
|
||||
"""Remove flavor access for the given tenant."""
|
||||
|
||||
flavor = objects.InstanceType.get(pecan.request.context,
|
||||
flavor_uuid)
|
||||
flavor = objects.Flavor.get(pecan.request.context,
|
||||
flavor_uuid)
|
||||
try:
|
||||
# TODO(zhenguo): this should be synchronized.
|
||||
if tenant_id in flavor.projects:
|
||||
@ -208,7 +205,7 @@ class FlavorsController(rest.RestController):
|
||||
def get_all(self):
|
||||
"""Retrieve a list of flavor."""
|
||||
|
||||
flavors = objects.InstanceType.list(pecan.request.context)
|
||||
flavors = objects.Flavor.list(pecan.request.context)
|
||||
return FlavorCollection.convert_with_links(flavors)
|
||||
|
||||
@expose.expose(Flavor, types.uuid)
|
||||
@ -217,8 +214,7 @@ class FlavorsController(rest.RestController):
|
||||
|
||||
:param flavor_uuid: UUID of a flavor.
|
||||
"""
|
||||
rpc_flavor = objects.InstanceType.get(pecan.request.context,
|
||||
flavor_uuid)
|
||||
rpc_flavor = objects.Flavor.get(pecan.request.context, flavor_uuid)
|
||||
return Flavor.convert_with_links(rpc_flavor)
|
||||
|
||||
@expose.expose(Flavor, body=Flavor,
|
||||
@ -228,8 +224,8 @@ class FlavorsController(rest.RestController):
|
||||
|
||||
:param flavor: a flavor within the request body.
|
||||
"""
|
||||
new_flavor = objects.InstanceType(pecan.request.context,
|
||||
**flavor.as_dict())
|
||||
new_flavor = objects.Flavor(pecan.request.context,
|
||||
**flavor.as_dict())
|
||||
new_flavor.create()
|
||||
# Set the HTTP Location Header
|
||||
pecan.response.location = link.build_url('flavors',
|
||||
@ -244,10 +240,10 @@ class FlavorsController(rest.RestController):
|
||||
:param flavor: a flavor within the request body.
|
||||
"""
|
||||
try:
|
||||
flavor_in_db = objects.InstanceType.get(
|
||||
flavor_in_db = objects.Flavor.get(
|
||||
pecan.request.context, flavor_uuid)
|
||||
except exception.FlavorTypeNotFound:
|
||||
msg = (_("InstanceType %s could not be found") %
|
||||
msg = (_("Flavor %s could not be found") %
|
||||
flavor_uuid)
|
||||
raise wsme.exc.ClientSideError(
|
||||
msg, status_code=http_client.BAD_REQUEST)
|
||||
@ -270,6 +266,5 @@ class FlavorsController(rest.RestController):
|
||||
|
||||
:param flavor_uuid: UUID of a flavor.
|
||||
"""
|
||||
rpc_flavor = objects.InstanceType.get(pecan.request.context,
|
||||
flavor_uuid)
|
||||
rpc_flavor = objects.Flavor.get(pecan.request.context, flavor_uuid)
|
||||
rpc_flavor.destroy()
|
||||
|
@ -93,7 +93,7 @@ class KeyPairCollection(base.APIBase):
|
||||
"""API representation of a collection of keypairs."""
|
||||
|
||||
keypairs = [KeyPair]
|
||||
"""A list containing Instance Type objects"""
|
||||
"""A list containing Flavor objects"""
|
||||
|
||||
@staticmethod
|
||||
def convert_with_links(keypairs, url=None, **kwargs):
|
||||
|
@ -17,14 +17,14 @@
|
||||
from mogan.api.validation import parameter_types
|
||||
|
||||
|
||||
create_instance = {
|
||||
create_server = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
'name': parameter_types.name,
|
||||
'description': parameter_types.description,
|
||||
'availability_zone': parameter_types.availability_zone,
|
||||
'image_uuid': parameter_types.image_id,
|
||||
'instance_type_uuid': parameter_types.instance_type_id,
|
||||
'flavor_uuid': parameter_types.flavor_id,
|
||||
'networks': {
|
||||
'type': 'array', 'minItems': 1,
|
||||
'items': {
|
||||
@ -44,6 +44,6 @@ create_instance = {
|
||||
'max_count': {'type': 'integer', 'minimum': 1},
|
||||
'extra': parameter_types.extra,
|
||||
},
|
||||
'required': ['name', 'image_uuid', 'instance_type_uuid', 'networks'],
|
||||
'required': ['name', 'image_uuid', 'flavor_uuid', 'networks'],
|
||||
'additionalProperties': False,
|
||||
}
|
@ -26,7 +26,7 @@ from wsme import types as wtypes
|
||||
from mogan.api.controllers import base
|
||||
from mogan.api.controllers import link
|
||||
from mogan.api.controllers.v1.schemas import floating_ips as fip_schemas
|
||||
from mogan.api.controllers.v1.schemas import instances as inst_schemas
|
||||
from mogan.api.controllers.v1.schemas import servers as server_schemas
|
||||
from mogan.api.controllers.v1 import types
|
||||
from mogan.api.controllers.v1 import utils as api_utils
|
||||
from mogan.api import expose
|
||||
@ -38,23 +38,23 @@ from mogan.common import states
|
||||
from mogan import network
|
||||
from mogan import objects
|
||||
|
||||
_DEFAULT_INSTANCE_RETURN_FIELDS = ('uuid', 'name', 'description',
|
||||
'status', 'power_state')
|
||||
_DEFAULT_SERVER_RETURN_FIELDS = ('uuid', 'name', 'description',
|
||||
'status', 'power_state')
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class InstanceStates(base.APIBase):
|
||||
"""API representation of the states of a instance."""
|
||||
class ServerStates(base.APIBase):
|
||||
"""API representation of the states of a server."""
|
||||
|
||||
power_state = wtypes.text
|
||||
"""Represent the current power state of the instance"""
|
||||
"""Represent the current power state of the server"""
|
||||
|
||||
status = wtypes.text
|
||||
"""Represent the current status of the instance"""
|
||||
"""Represent the current status of the server"""
|
||||
|
||||
locked = types.boolean
|
||||
"""Represent the current lock state of the instance"""
|
||||
"""Represent the current lock state of the server"""
|
||||
|
||||
@classmethod
|
||||
def sample(cls):
|
||||
@ -63,16 +63,16 @@ class InstanceStates(base.APIBase):
|
||||
return sample
|
||||
|
||||
|
||||
class InstanceControllerBase(rest.RestController):
|
||||
class ServerControllerBase(rest.RestController):
|
||||
_resource = None
|
||||
|
||||
# This _resource is used for authorization.
|
||||
def _get_resource(self, uuid, *args, **kwargs):
|
||||
self._resource = objects.Instance.get(pecan.request.context, uuid)
|
||||
self._resource = objects.Server.get(pecan.request.context, uuid)
|
||||
return self._resource
|
||||
|
||||
|
||||
class InstanceStatesController(InstanceControllerBase):
|
||||
class ServerStatesController(ServerControllerBase):
|
||||
|
||||
_custom_actions = {
|
||||
'power': ['PUT'],
|
||||
@ -80,148 +80,148 @@ class InstanceStatesController(InstanceControllerBase):
|
||||
'provision': ['PUT'],
|
||||
}
|
||||
|
||||
@policy.authorize_wsgi("mogan:instance", "get_states")
|
||||
@expose.expose(InstanceStates, types.uuid)
|
||||
def get(self, instance_uuid):
|
||||
"""List the states of the instance, just support power state at present.
|
||||
@policy.authorize_wsgi("mogan:server", "get_states")
|
||||
@expose.expose(ServerStates, types.uuid)
|
||||
def get(self, server_uuid):
|
||||
"""List the states of the server, just support power state at present.
|
||||
|
||||
:param instance_uuid: the UUID of a instance.
|
||||
:param server_uuid: the UUID of a server.
|
||||
"""
|
||||
rpc_instance = self._resource or self._get_resource(instance_uuid)
|
||||
rpc_server = self._resource or self._get_resource(server_uuid)
|
||||
|
||||
return InstanceStates(power_state=rpc_instance.power_state,
|
||||
status=rpc_instance.status,
|
||||
locked=rpc_instance.locked)
|
||||
return ServerStates(power_state=rpc_server.power_state,
|
||||
status=rpc_server.status,
|
||||
locked=rpc_server.locked)
|
||||
|
||||
@policy.authorize_wsgi("mogan:instance", "set_power_state")
|
||||
@policy.authorize_wsgi("mogan:server", "set_power_state")
|
||||
@expose.expose(None, types.uuid, wtypes.text,
|
||||
status_code=http_client.ACCEPTED)
|
||||
def power(self, instance_uuid, target):
|
||||
"""Set the power state of the instance.
|
||||
def power(self, server_uuid, target):
|
||||
"""Set the power state of the server.
|
||||
|
||||
:param instance_uuid: the UUID of a instance.
|
||||
:param server_uuid: the UUID of a server.
|
||||
:param target: the desired target to change power state,
|
||||
on, off or reboot.
|
||||
:raises Conflict (HTTP 409): if a power operation is
|
||||
already in progress.
|
||||
:raises BadRequest (HTTP 400): if the requested target
|
||||
state is not valid or if the instance is in CLEANING state.
|
||||
state is not valid or if the server is in CLEANING state.
|
||||
|
||||
"""
|
||||
if target not in ["on", "off", "reboot", "soft_off", "soft_reboot"]:
|
||||
# ironic will throw InvalidStateRequested
|
||||
raise exception.InvalidActionParameterValue(
|
||||
value=target, action="power",
|
||||
instance=instance_uuid)
|
||||
server=server_uuid)
|
||||
|
||||
rpc_instance = self._resource or self._get_resource(instance_uuid)
|
||||
rpc_server = self._resource or self._get_resource(server_uuid)
|
||||
pecan.request.engine_api.power(
|
||||
pecan.request.context, rpc_instance, target)
|
||||
pecan.request.context, rpc_server, target)
|
||||
# At present we do not catch the Exception from ironicclient.
|
||||
# Such as Conflict and BadRequest.
|
||||
# varify provision_state, if instance is being cleaned,
|
||||
# varify provision_state, if server is being cleaned,
|
||||
# don't change power state?
|
||||
|
||||
# Set the HTTP Location Header, user can get the power_state
|
||||
# by locaton.
|
||||
url_args = '/'.join([instance_uuid, 'states'])
|
||||
pecan.response.location = link.build_url('instances', url_args)
|
||||
url_args = '/'.join([server_uuid, 'states'])
|
||||
pecan.response.location = link.build_url('servers', url_args)
|
||||
|
||||
@policy.authorize_wsgi("mogan:instance", "set_lock_state")
|
||||
@policy.authorize_wsgi("mogan:server", "set_lock_state")
|
||||
@expose.expose(None, types.uuid, types.boolean,
|
||||
status_code=http_client.ACCEPTED)
|
||||
def lock(self, instance_uuid, target):
|
||||
"""Set the lock state of the instance.
|
||||
def lock(self, server_uuid, target):
|
||||
"""Set the lock state of the server.
|
||||
|
||||
:param instance_uuid: the UUID of a instance.
|
||||
:param server_uuid: the UUID of a server.
|
||||
:param target: the desired target to change lock state,
|
||||
true or false
|
||||
"""
|
||||
rpc_instance = self._resource or self._get_resource(instance_uuid)
|
||||
rpc_server = self._resource or self._get_resource(server_uuid)
|
||||
context = pecan.request.context
|
||||
|
||||
# Target is True, means lock an instance
|
||||
# Target is True, means lock a server
|
||||
if target:
|
||||
pecan.request.engine_api.lock(context, rpc_instance)
|
||||
pecan.request.engine_api.lock(context, rpc_server)
|
||||
|
||||
# Else, unlock the instance
|
||||
# Else, unlock the server
|
||||
else:
|
||||
# Try to unlock an instance with non-admin or non-owner
|
||||
# Try to unlock a server with non-admin or non-owner
|
||||
if not pecan.request.engine_api.is_expected_locked_by(
|
||||
context, rpc_instance):
|
||||
context, rpc_server):
|
||||
raise exception.Forbidden()
|
||||
pecan.request.engine_api.unlock(context, rpc_instance)
|
||||
pecan.request.engine_api.unlock(context, rpc_server)
|
||||
|
||||
@policy.authorize_wsgi("mogan:instance", "set_provision_state")
|
||||
@policy.authorize_wsgi("mogan:server", "set_provision_state")
|
||||
@expose.expose(None, types.uuid, wtypes.text,
|
||||
status_code=http_client.ACCEPTED)
|
||||
def provision(self, instance_uuid, target):
|
||||
"""Asynchronous trigger the provisioning of the instance.
|
||||
def provision(self, server_uuid, target):
|
||||
"""Asynchronous trigger the provisioning of the server.
|
||||
|
||||
This will set the target provision state of the instance, and
|
||||
This will set the target provision state of the server, and
|
||||
a background task will begin which actually applies the state
|
||||
change. This call will return a 202 (Accepted) indicating the
|
||||
request was accepted and is in progress; the client should
|
||||
continue to GET the status of this instance to observe the
|
||||
continue to GET the status of this server to observe the
|
||||
status of the requested action.
|
||||
|
||||
:param instance_uuid: UUID of an instance.
|
||||
:param target: The desired provision state of the instance or verb.
|
||||
:param server_uuid: UUID of a server.
|
||||
:param target: The desired provision state of the server or verb.
|
||||
"""
|
||||
|
||||
# Currently we only support rebuild target
|
||||
if target not in (states.REBUILD,):
|
||||
raise exception.InvalidActionParameterValue(
|
||||
value=target, action="provision",
|
||||
instance=instance_uuid)
|
||||
server=server_uuid)
|
||||
|
||||
rpc_instance = self._resource or self._get_resource(instance_uuid)
|
||||
rpc_server = self._resource or self._get_resource(server_uuid)
|
||||
if target == states.REBUILD:
|
||||
try:
|
||||
pecan.request.engine_api.rebuild(pecan.request.context,
|
||||
rpc_instance)
|
||||
except exception.InstanceNotFound:
|
||||
msg = (_("Instance %s could not be found") %
|
||||
instance_uuid)
|
||||
rpc_server)
|
||||
except exception.ServerNotFound:
|
||||
msg = (_("Server %s could not be found") %
|
||||
server_uuid)
|
||||
raise wsme.exc.ClientSideError(
|
||||
msg, status_code=http_client.NOT_FOUND)
|
||||
|
||||
# Set the HTTP Location Header
|
||||
url_args = '/'.join([instance_uuid, 'states'])
|
||||
pecan.response.location = link.build_url('instances', url_args)
|
||||
url_args = '/'.join([server_uuid, 'states'])
|
||||
pecan.response.location = link.build_url('servers', url_args)
|
||||
|
||||
|
||||
class FloatingIPController(InstanceControllerBase):
|
||||
"""REST controller for Instance floatingips."""
|
||||
class FloatingIPController(ServerControllerBase):
|
||||
"""REST controller for Server floatingips."""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(FloatingIPController, self).__init__(*args, **kwargs)
|
||||
self.network_api = network.API()
|
||||
|
||||
@policy.authorize_wsgi("mogan:instance", "associate_floatingip", False)
|
||||
@policy.authorize_wsgi("mogan:server", "associate_floatingip", False)
|
||||
@expose.expose(None, types.uuid, body=types.jsontype,
|
||||
status_code=http_client.NO_CONTENT)
|
||||
def post(self, instance_uuid, floatingip):
|
||||
def post(self, server_uuid, floatingip):
|
||||
"""Add(Associate) Floating Ip.
|
||||
|
||||
:param instance_uuid: UUID of a instance.
|
||||
:param server_uuid: UUID of a server.
|
||||
:param floatingip: The floating IP within the request body.
|
||||
"""
|
||||
validation.check_schema(floatingip, fip_schemas.add_floating_ip)
|
||||
|
||||
instance = self._resource or self._get_resource(instance_uuid)
|
||||
server = self._resource or self._get_resource(server_uuid)
|
||||
address = floatingip['address']
|
||||
instance_nics = instance.nics
|
||||
server_nics = server.nics
|
||||
|
||||
if not instance_nics:
|
||||
msg = _('No ports associated to instance')
|
||||
if not server_nics:
|
||||
msg = _('No ports associated to server')
|
||||
raise wsme.exc.ClientSideError(
|
||||
msg, status_code=http_client.BAD_REQUEST)
|
||||
|
||||
fixed_address = None
|
||||
if 'fixed_address' in floatingip:
|
||||
fixed_address = floatingip['fixed_address']
|
||||
for nic in instance_nics:
|
||||
for nic in server_nics:
|
||||
for port_address in nic.fixed_ips:
|
||||
if port_address['ip_address'] == fixed_address:
|
||||
break
|
||||
@ -229,12 +229,12 @@ class FloatingIPController(InstanceControllerBase):
|
||||
continue
|
||||
break
|
||||
else:
|
||||
msg = _('Specified fixed address not assigned to instance')
|
||||
msg = _('Specified fixed address not assigned to server')
|
||||
raise wsme.exc.ClientSideError(
|
||||
msg, status_code=http_client.BAD_REQUEST)
|
||||
|
||||
if not fixed_address:
|
||||
for nic in instance_nics:
|
||||
for nic in server_nics:
|
||||
for port_address in nic.fixed_ips:
|
||||
if netutils.is_valid_ipv4(port_address['ip_address']):
|
||||
fixed_address = port_address['ip_address']
|
||||
@ -244,13 +244,13 @@ class FloatingIPController(InstanceControllerBase):
|
||||
break
|
||||
else:
|
||||
msg = _('Unable to associate floating IP %(address)s '
|
||||
'to any fixed IPs for instance %(id)s. '
|
||||
'Instance has no fixed IPv4 addresses to '
|
||||
'to any fixed IPs for server %(id)s. '
|
||||
'Server has no fixed IPv4 addresses to '
|
||||
'associate.') % ({'address': address,
|
||||
'id': instance.uuid})
|
||||
'id': server.uuid})
|
||||
raise wsme.exc.ClientSideError(
|
||||
msg, status_code=http_client.BAD_REQUEST)
|
||||
if len(instance_nics) > 1:
|
||||
if len(server_nics) > 1:
|
||||
LOG.warning('multiple ports exist, using the first '
|
||||
'IPv4 fixed_ip: %s', fixed_address)
|
||||
|
||||
@ -266,21 +266,21 @@ class FloatingIPController(InstanceControllerBase):
|
||||
e.message, status_code=http_client.FORBIDDEN)
|
||||
except Exception as e:
|
||||
msg = _('Unable to associate floating IP %(address)s to '
|
||||
'fixed IP %(fixed_address)s for instance %(id)s. '
|
||||
'fixed IP %(fixed_address)s for server %(id)s. '
|
||||
'Error: %(error)s') % ({'address': address,
|
||||
'fixed_address': fixed_address,
|
||||
'id': instance.uuid, 'error': e})
|
||||
'id': server.uuid, 'error': e})
|
||||
LOG.exception(msg)
|
||||
raise wsme.exc.ClientSideError(
|
||||
msg, status_code=http_client.BAD_REQUEST)
|
||||
|
||||
@policy.authorize_wsgi("mogan:instance", "disassociate_floatingip")
|
||||
@policy.authorize_wsgi("mogan:server", "disassociate_floatingip")
|
||||
@expose.expose(None, types.uuid, wtypes.text,
|
||||
status_code=http_client.NO_CONTENT)
|
||||
def delete(self, instance_uuid, address):
|
||||
"""Dissociate floating_ip from an instance.
|
||||
def delete(self, server_uuid, address):
|
||||
"""Dissociate floating_ip from a server.
|
||||
|
||||
:param instance_uuid: UUID of a instance.
|
||||
:param server_uuid: UUID of a server.
|
||||
:param floatingip: The floating IP within the request body.
|
||||
"""
|
||||
if not netutils.is_valid_ipv4(address):
|
||||
@ -296,10 +296,10 @@ class FloatingIPController(InstanceControllerBase):
|
||||
raise wsme.exc.ClientSideError(
|
||||
msg, status_code=http_client.NOT_FOUND)
|
||||
|
||||
# get the associated instance object (if any)
|
||||
# get the associated server object (if any)
|
||||
try:
|
||||
instance_id =\
|
||||
self.network_api.get_instance_id_by_floating_address(
|
||||
server_id =\
|
||||
self.network_api.get_server_id_by_floating_address(
|
||||
pecan.request.context, address)
|
||||
except exception.FloatingIpNotFoundForAddress as e:
|
||||
raise wsme.exc.ClientSideError(
|
||||
@ -309,7 +309,7 @@ class FloatingIPController(InstanceControllerBase):
|
||||
e.message, status_code=http_client.CONFLICT)
|
||||
|
||||
# disassociate if associated
|
||||
if (floating_ip.get('port_id') and instance_id == instance_uuid):
|
||||
if (floating_ip.get('port_id') and server_id == server_uuid):
|
||||
try:
|
||||
self.network_api.disassociate_floating_ip(
|
||||
pecan.request.context, address)
|
||||
@ -325,91 +325,91 @@ class FloatingIPController(InstanceControllerBase):
|
||||
raise wsme.exc.ClientSideError(
|
||||
msg, status_code=http_client.BAD_REQUEST)
|
||||
else:
|
||||
msg = _("Floating IP %(address)s is not associated with instance "
|
||||
"%(id)s.") % {'address': address, 'id': instance_uuid}
|
||||
msg = _("Floating IP %(address)s is not associated with server "
|
||||
"%(id)s.") % {'address': address, 'id': server_uuid}
|
||||
raise wsme.exc.ClientSideError(
|
||||
msg, status_code=http_client.BAD_REQUEST)
|
||||
|
||||
|
||||
class InstanceNetworks(base.APIBase):
|
||||
"""API representation of the networks of an instance."""
|
||||
class ServerNetworks(base.APIBase):
|
||||
"""API representation of the networks of a server."""
|
||||
|
||||
ports = {wtypes.text: types.jsontype}
|
||||
"""The network information of the instance"""
|
||||
"""The network information of the server"""
|
||||
|
||||
|
||||
class InstanceNetworksController(InstanceControllerBase):
|
||||
"""REST controller for Instance networks."""
|
||||
class ServerNetworksController(ServerControllerBase):
|
||||
"""REST controller for Server networks."""
|
||||
|
||||
floatingips = FloatingIPController()
|
||||
"""Expose floatingip as a sub-element of networks"""
|
||||
|
||||
@policy.authorize_wsgi("mogan:instance", "get_networks")
|
||||
@expose.expose(InstanceNetworks, types.uuid)
|
||||
def get(self, instance_uuid):
|
||||
"""List the networks info of the instance.
|
||||
@policy.authorize_wsgi("mogan:server", "get_networks")
|
||||
@expose.expose(ServerNetworks, types.uuid)
|
||||
def get(self, server_uuid):
|
||||
"""List the networks info of the server.
|
||||
|
||||
:param instance_uuid: the UUID of a instance.
|
||||
:param server_uuid: the UUID of a server.
|
||||
"""
|
||||
rpc_instance = self._resource or self._get_resource(instance_uuid)
|
||||
rpc_server = self._resource or self._get_resource(server_uuid)
|
||||
|
||||
return InstanceNetworks(
|
||||
ports=rpc_instance.instance_nics.to_legacy_dict())
|
||||
return ServerNetworks(
|
||||
ports=rpc_server.server_nics.to_legacy_dict())
|
||||
|
||||
|
||||
class Instance(base.APIBase):
|
||||
"""API representation of a instance.
|
||||
class Server(base.APIBase):
|
||||
"""API representation of a server.
|
||||
|
||||
This class enforces type checking and value constraints, and converts
|
||||
between the internal object model and the API representation of
|
||||
a instance.
|
||||
a server.
|
||||
"""
|
||||
uuid = types.uuid
|
||||
"""The UUID of the instance"""
|
||||
"""The UUID of the server"""
|
||||
|
||||
name = wsme.wsattr(wtypes.text, mandatory=True)
|
||||
"""The name of the instance"""
|
||||
"""The name of the server"""
|
||||
|
||||
description = wtypes.text
|
||||
"""The description of the instance"""
|
||||
"""The description of the server"""
|
||||
|
||||
project_id = types.uuid
|
||||
"""The project UUID of the instance"""
|
||||
"""The project UUID of the server"""
|
||||
|
||||
user_id = types.uuid
|
||||
"""The user UUID of the instance"""
|
||||
"""The user UUID of the server"""
|
||||
|
||||
status = wtypes.text
|
||||
"""The status of the instance"""
|
||||
"""The status of the server"""
|
||||
|
||||
power_state = wtypes.text
|
||||
"""The power state of the instance"""
|
||||
"""The power state of the server"""
|
||||
|
||||
availability_zone = wtypes.text
|
||||
"""The availability zone of the instance"""
|
||||
"""The availability zone of the server"""
|
||||
|
||||
instance_type_uuid = types.uuid
|
||||
"""The instance type UUID of the instance"""
|
||||
flavor_uuid = types.uuid
|
||||
"""The server type UUID of the server"""
|
||||
|
||||
image_uuid = types.uuid
|
||||
"""The image UUID of the instance"""
|
||||
"""The image UUID of the server"""
|
||||
|
||||
network_info = {wtypes.text: types.jsontype}
|
||||
"""The network information of the instance"""
|
||||
"""The network information of the server"""
|
||||
|
||||
links = wsme.wsattr([link.Link], readonly=True)
|
||||
"""A list containing a self link"""
|
||||
|
||||
launched_at = datetime.datetime
|
||||
"""The UTC date and time of the instance launched"""
|
||||
"""The UTC date and time of the server launched"""
|
||||
|
||||
extra = {wtypes.text: types.jsontype}
|
||||
"""The meta data of the instance"""
|
||||
"""The meta data of the server"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(Instance, self).__init__(**kwargs)
|
||||
super(Server, self).__init__(**kwargs)
|
||||
self.fields = []
|
||||
for field in objects.Instance.fields:
|
||||
for field in objects.Server.fields:
|
||||
# TODO(liusheng) workaround to keep the output of API request same
|
||||
# as before
|
||||
if field == 'nics':
|
||||
@ -426,105 +426,105 @@ class Instance(base.APIBase):
|
||||
setattr(self, field, kwargs.get(field, wtypes.Unset))
|
||||
|
||||
@classmethod
|
||||
def convert_with_links(cls, instance_data, fields=None):
|
||||
instance = Instance(**instance_data)
|
||||
instance_uuid = instance.uuid
|
||||
def convert_with_links(cls, server_data, fields=None):
|
||||
server = Server(**server_data)
|
||||
server_uuid = server.uuid
|
||||
if fields is not None:
|
||||
instance.unset_fields_except(fields)
|
||||
server.unset_fields_except(fields)
|
||||
url = pecan.request.public_url
|
||||
instance.links = [link.Link.make_link('self',
|
||||
url,
|
||||
'instances', instance_uuid),
|
||||
link.Link.make_link('bookmark',
|
||||
url,
|
||||
'instances', instance_uuid,
|
||||
bookmark=True)
|
||||
]
|
||||
return instance
|
||||
server.links = [link.Link.make_link('self',
|
||||
url,
|
||||
'servers', server_uuid),
|
||||
link.Link.make_link('bookmark',
|
||||
url,
|
||||
'servers', server_uuid,
|
||||
bookmark=True)
|
||||
]
|
||||
return server
|
||||
|
||||
|
||||
class InstancePatchType(types.JsonPatchType):
|
||||
class ServerPatchType(types.JsonPatchType):
|
||||
|
||||
_api_base = Instance
|
||||
_api_base = Server
|
||||
|
||||
@staticmethod
|
||||
def internal_attrs():
|
||||
defaults = types.JsonPatchType.internal_attrs()
|
||||
return defaults + ['/project_id', '/user_id', '/status',
|
||||
'/power_state', '/availability_zone',
|
||||
'/instance_type_uuid', 'image_uuid',
|
||||
'/flavor_uuid', 'image_uuid',
|
||||
'/isntance_nics', '/launched_at']
|
||||
|
||||
|
||||
class InstanceCollection(base.APIBase):
|
||||
"""API representation of a collection of instance."""
|
||||
class ServerCollection(base.APIBase):
|
||||
"""API representation of a collection of server."""
|
||||
|
||||
instances = [Instance]
|
||||
"""A list containing instance objects"""
|
||||
servers = [Server]
|
||||
"""A list containing server objects"""
|
||||
|
||||
@staticmethod
|
||||
def convert_with_links(instances_data, fields=None):
|
||||
collection = InstanceCollection()
|
||||
collection.instances = [Instance.convert_with_links(inst, fields)
|
||||
for inst in instances_data]
|
||||
def convert_with_links(servers_data, fields=None):
|
||||
collection = ServerCollection()
|
||||
collection.servers = [Server.convert_with_links(server, fields)
|
||||
for server in servers_data]
|
||||
return collection
|
||||
|
||||
|
||||
class InstanceConsole(base.APIBase):
|
||||
"""API representation of the console of an instance."""
|
||||
class ServerConsole(base.APIBase):
|
||||
"""API representation of the console of a server."""
|
||||
|
||||
console = {wtypes.text: types.jsontype}
|
||||
"""The console information of the instance"""
|
||||
"""The console information of the server"""
|
||||
|
||||
|
||||
class InstanceSerialConsoleController(InstanceControllerBase):
|
||||
"""REST controller for Instance."""
|
||||
class ServerSerialConsoleController(ServerControllerBase):
|
||||
"""REST controller for Server."""
|
||||
|
||||
@policy.authorize_wsgi("mogan:instance", "get_serial_console")
|
||||
@expose.expose(InstanceConsole, types.uuid)
|
||||
def get(self, instance_uuid):
|
||||
"""Get the serial console info of the instance.
|
||||
@policy.authorize_wsgi("mogan:server", "get_serial_console")
|
||||
@expose.expose(ServerConsole, types.uuid)
|
||||
def get(self, server_uuid):
|
||||
"""Get the serial console info of the server.
|
||||
|
||||
:param instance_uuid: the UUID of a instance.
|
||||
:param server_uuid: the UUID of a server.
|
||||
"""
|
||||
instance_obj = self._resource or self._get_resource(instance_uuid)
|
||||
server_obj = self._resource or self._get_resource(server_uuid)
|
||||
console = pecan.request.engine_api.get_serial_console(
|
||||
pecan.request.context, instance_obj)
|
||||
return InstanceConsole(console=console)
|
||||
pecan.request.context, server_obj)
|
||||
return ServerConsole(console=console)
|
||||
|
||||
|
||||
class InstanceController(InstanceControllerBase):
|
||||
"""REST controller for Instance."""
|
||||
class ServerController(ServerControllerBase):
|
||||
"""REST controller for Server."""
|
||||
|
||||
states = InstanceStatesController()
|
||||
"""Expose the state controller action as a sub-element of instances"""
|
||||
states = ServerStatesController()
|
||||
"""Expose the state controller action as a sub-element of servers"""
|
||||
|
||||
networks = InstanceNetworksController()
|
||||
"""Expose the network controller action as a sub-element of instances"""
|
||||
networks = ServerNetworksController()
|
||||
"""Expose the network controller action as a sub-element of servers"""
|
||||
|
||||
serial_console = InstanceSerialConsoleController()
|
||||
"""Expose the console controller of instances"""
|
||||
serial_console = ServerSerialConsoleController()
|
||||
"""Expose the console controller of servers"""
|
||||
|
||||
_custom_actions = {
|
||||
'detail': ['GET']
|
||||
}
|
||||
|
||||
def _get_instance_collection(self, fields=None, all_tenants=False):
|
||||
def _get_server_collection(self, fields=None, all_tenants=False):
|
||||
context = pecan.request.context
|
||||
project_only = True
|
||||
if context.is_admin and all_tenants:
|
||||
project_only = False
|
||||
|
||||
instances = objects.Instance.list(pecan.request.context,
|
||||
project_only=project_only)
|
||||
instances_data = [instance.as_dict() for instance in instances]
|
||||
servers = objects.Server.list(pecan.request.context,
|
||||
project_only=project_only)
|
||||
servers_data = [server.as_dict() for server in servers]
|
||||
|
||||
return InstanceCollection.convert_with_links(instances_data,
|
||||
fields=fields)
|
||||
return ServerCollection.convert_with_links(servers_data,
|
||||
fields=fields)
|
||||
|
||||
@expose.expose(InstanceCollection, types.listtype, types.boolean)
|
||||
@expose.expose(ServerCollection, types.listtype, types.boolean)
|
||||
def get_all(self, fields=None, all_tenants=None):
|
||||
"""Retrieve a list of instance.
|
||||
"""Retrieve a list of server.
|
||||
|
||||
:param fields: Optional, a list with a specified set of fields
|
||||
of the resource to be returned.
|
||||
@ -534,57 +534,57 @@ class InstanceController(InstanceControllerBase):
|
||||
included in the response.
|
||||
"""
|
||||
if fields is None:
|
||||
fields = _DEFAULT_INSTANCE_RETURN_FIELDS
|
||||
return self._get_instance_collection(fields=fields,
|
||||
all_tenants=all_tenants)
|
||||
fields = _DEFAULT_SERVER_RETURN_FIELDS
|
||||
return self._get_server_collection(fields=fields,
|
||||
all_tenants=all_tenants)
|
||||
|
||||
@policy.authorize_wsgi("mogan:instance", "get")
|
||||
@expose.expose(Instance, types.uuid, types.listtype)
|
||||
def get_one(self, instance_uuid, fields=None):
|
||||
"""Retrieve information about the given instance.
|
||||
@policy.authorize_wsgi("mogan:server", "get")
|
||||
@expose.expose(Server, types.uuid, types.listtype)
|
||||
def get_one(self, server_uuid, fields=None):
|
||||
"""Retrieve information about the given server.
|
||||
|
||||
:param instance_uuid: UUID of a instance.
|
||||
:param server_uuid: UUID of a server.
|
||||
:param fields: Optional, a list with a specified set of fields
|
||||
of the resource to be returned.
|
||||
"""
|
||||
rpc_instance = self._resource or self._get_resource(instance_uuid)
|
||||
instance_data = rpc_instance.as_dict()
|
||||
rpc_server = self._resource or self._get_resource(server_uuid)
|
||||
server_data = rpc_server.as_dict()
|
||||
|
||||
return Instance.convert_with_links(instance_data, fields=fields)
|
||||
return Server.convert_with_links(server_data, fields=fields)
|
||||
|
||||
@expose.expose(InstanceCollection, types.boolean)
|
||||
@expose.expose(ServerCollection, types.boolean)
|
||||
def detail(self, all_tenants=None):
|
||||
"""Retrieve detail of a list of instances."""
|
||||
"""Retrieve detail of a list of servers."""
|
||||
# /detail should only work against collections
|
||||
parent = pecan.request.path.split('/')[:-1][-1]
|
||||
if parent != "instances":
|
||||
if parent != "servers":
|
||||
raise exception.NotFound()
|
||||
return self._get_instance_collection(all_tenants=all_tenants)
|
||||
return self._get_server_collection(all_tenants=all_tenants)
|
||||
|
||||
@policy.authorize_wsgi("mogan:instance", "create", False)
|
||||
@expose.expose(Instance, body=types.jsontype,
|
||||
@policy.authorize_wsgi("mogan:server", "create", False)
|
||||
@expose.expose(Server, body=types.jsontype,
|
||||
status_code=http_client.CREATED)
|
||||
def post(self, instance):
|
||||
"""Create a new instance.
|
||||
def post(self, server):
|
||||
"""Create a new server.
|
||||
|
||||
:param instance: a instance within the request body.
|
||||
:param server: a server within the request body.
|
||||
"""
|
||||
validation.check_schema(instance, inst_schemas.create_instance)
|
||||
validation.check_schema(server, server_schemas.create_server)
|
||||
|
||||
min_count = instance.get('min_count', 1)
|
||||
max_count = instance.get('max_count', min_count)
|
||||
min_count = server.get('min_count', 1)
|
||||
max_count = server.get('max_count', min_count)
|
||||
|
||||
if min_count > max_count:
|
||||
msg = _('min_count must be <= max_count')
|
||||
raise wsme.exc.ClientSideError(
|
||||
msg, status_code=http_client.BAD_REQUEST)
|
||||
|
||||
requested_networks = instance.pop('networks', None)
|
||||
instance_type_uuid = instance.get('instance_type_uuid')
|
||||
image_uuid = instance.get('image_uuid')
|
||||
user_data = instance.get('user_data')
|
||||
key_name = instance.get('key_name')
|
||||
personality = instance.pop('personality', None)
|
||||
requested_networks = server.pop('networks', None)
|
||||
flavor_uuid = server.get('flavor_uuid')
|
||||
image_uuid = server.get('image_uuid')
|
||||
user_data = server.get('user_data')
|
||||
key_name = server.get('key_name')
|
||||
personality = server.pop('personality', None)
|
||||
|
||||
injected_files = []
|
||||
if personality:
|
||||
@ -592,17 +592,16 @@ class InstanceController(InstanceControllerBase):
|
||||
injected_files.append((item['path'], item['contents']))
|
||||
|
||||
try:
|
||||
instance_type = objects.InstanceType.get(pecan.request.context,
|
||||
instance_type_uuid)
|
||||
flavor = objects.Flavor.get(pecan.request.context, flavor_uuid)
|
||||
|
||||
instances = pecan.request.engine_api.create(
|
||||
servers = pecan.request.engine_api.create(
|
||||
pecan.request.context,
|
||||
instance_type,
|
||||
flavor,
|
||||
image_uuid=image_uuid,
|
||||
name=instance.get('name'),
|
||||
description=instance.get('description'),
|
||||
availability_zone=instance.get('availability_zone'),
|
||||
extra=instance.get('extra'),
|
||||
name=server.get('name'),
|
||||
description=server.get('description'),
|
||||
availability_zone=server.get('availability_zone'),
|
||||
extra=server.get('extra'),
|
||||
requested_networks=requested_networks,
|
||||
user_data=user_data,
|
||||
injected_files=injected_files,
|
||||
@ -611,7 +610,7 @@ class InstanceController(InstanceControllerBase):
|
||||
max_count=max_count)
|
||||
except exception.FlavorNotFound:
|
||||
msg = (_("Flavor %s could not be found") %
|
||||
instance_type_uuid)
|
||||
flavor_uuid)
|
||||
raise wsme.exc.ClientSideError(
|
||||
msg, status_code=http_client.BAD_REQUEST)
|
||||
except exception.ImageNotFound:
|
||||
@ -630,57 +629,57 @@ class InstanceController(InstanceControllerBase):
|
||||
raise wsme.exc.ClientSideError(
|
||||
msg, status_code=http_client.BAD_REQUEST)
|
||||
except (exception.GlanceConnectionFailed,
|
||||
exception.InstanceUserDataMalformed,
|
||||
exception.InstanceUserDataTooLarge,
|
||||
exception.ServerUserDataMalformed,
|
||||
exception.ServerUserDataTooLarge,
|
||||
exception.Base64Exception,
|
||||
exception.NetworkRequiresSubnet,
|
||||
exception.NetworkNotFound) as e:
|
||||
raise wsme.exc.ClientSideError(
|
||||
e.message, status_code=http_client.BAD_REQUEST)
|
||||
|
||||
# Set the HTTP Location Header for the first instance.
|
||||
pecan.response.location = link.build_url('instance', instances[0].uuid)
|
||||
return Instance.convert_with_links(instances[0])
|
||||
# Set the HTTP Location Header for the first server.
|
||||
pecan.response.location = link.build_url('server', servers[0].uuid)
|
||||
return Server.convert_with_links(servers[0])
|
||||
|
||||
@policy.authorize_wsgi("mogan:instance", "update")
|
||||
@wsme.validate(types.uuid, [InstancePatchType])
|
||||
@expose.expose(Instance, types.uuid, body=[InstancePatchType])
|
||||
def patch(self, instance_uuid, patch):
|
||||
"""Update an instance.
|
||||
@policy.authorize_wsgi("mogan:server", "update")
|
||||
@wsme.validate(types.uuid, [ServerPatchType])
|
||||
@expose.expose(Server, types.uuid, body=[ServerPatchType])
|
||||
def patch(self, server_uuid, patch):
|
||||
"""Update a server.
|
||||
|
||||
:param instance_uuid: UUID of an instance.
|
||||
:param patch: a json PATCH document to apply to this instance.
|
||||
:param server_uuid: UUID of a server.
|
||||
:param patch: a json PATCH document to apply to this server.
|
||||
"""
|
||||
rpc_instance = self._resource or self._get_resource(instance_uuid)
|
||||
rpc_server = self._resource or self._get_resource(server_uuid)
|
||||
try:
|
||||
instance = Instance(
|
||||
**api_utils.apply_jsonpatch(rpc_instance.as_dict(), patch))
|
||||
server = Server(
|
||||
**api_utils.apply_jsonpatch(rpc_server.as_dict(), patch))
|
||||
|
||||
except api_utils.JSONPATCH_EXCEPTIONS as e:
|
||||
raise exception.PatchError(patch=patch, reason=e)
|
||||
|
||||
# Update only the fields that have changed
|
||||
for field in objects.Instance.fields:
|
||||
for field in objects.Server.fields:
|
||||
try:
|
||||
patch_val = getattr(instance, field)
|
||||
patch_val = getattr(server, field)
|
||||
except AttributeError:
|
||||
# Ignore fields that aren't exposed in the API
|
||||
continue
|
||||
if patch_val == wtypes.Unset:
|
||||
patch_val = None
|
||||
if rpc_instance[field] != patch_val:
|
||||
rpc_instance[field] = patch_val
|
||||
if rpc_server[field] != patch_val:
|
||||
rpc_server[field] = patch_val
|
||||
|
||||
rpc_instance.save()
|
||||
rpc_server.save()
|
||||
|
||||
return Instance.convert_with_links(rpc_instance)
|
||||
return Server.convert_with_links(rpc_server)
|
||||
|
||||
@policy.authorize_wsgi("mogan:instance", "delete")
|
||||
@policy.authorize_wsgi("mogan:server", "delete")
|
||||
@expose.expose(None, types.uuid, status_code=http_client.NO_CONTENT)
|
||||
def delete(self, instance_uuid):
|
||||
"""Delete a instance.
|
||||
def delete(self, server_uuid):
|
||||
"""Delete a server.
|
||||
|
||||
:param instance_uuid: UUID of a instance.
|
||||
:param server_uuid: UUID of a server.
|
||||
"""
|
||||
rpc_instance = self._resource or self._get_resource(instance_uuid)
|
||||
pecan.request.engine_api.delete(pecan.request.context, rpc_instance)
|
||||
rpc_server = self._resource or self._get_resource(server_uuid)
|
||||
pecan.request.engine_api.delete(pecan.request.context, rpc_server)
|
@ -35,7 +35,7 @@ class DBHook(hooks.PecanHook):
|
||||
"""Attach the dbapi object to the request so controllers can get to it."""
|
||||
|
||||
def before(self, state):
|
||||
state.request.dbapi = dbapi.get_instance()
|
||||
state.request.dbapi = dbapi.get_server()
|
||||
|
||||
|
||||
class EngineAPIHook(hooks.PecanHook):
|
||||
|
@ -53,7 +53,7 @@ port_type = {
|
||||
}
|
||||
|
||||
|
||||
instance_type_id = {
|
||||
flavor_id = {
|
||||
'type': 'string', 'format': 'uuid'
|
||||
}
|
||||
|
||||
|
@ -156,12 +156,12 @@ class FlavorNotFound(NotFound):
|
||||
_msg_fmt = _("Flavor %(type_id)s could not be found.")
|
||||
|
||||
|
||||
class InstanceAlreadyExists(MoganException):
|
||||
_msg_fmt = _("Instance with name %(name)s already exists.")
|
||||
class ServerAlreadyExists(MoganException):
|
||||
_msg_fmt = _("Server with name %(name)s already exists.")
|
||||
|
||||
|
||||
class InstanceNotFound(NotFound):
|
||||
_msg_fmt = _("Instance %(instance)s could not be found.")
|
||||
class ServerNotFound(NotFound):
|
||||
_msg_fmt = _("Server %(server)s could not be found.")
|
||||
|
||||
|
||||
class FlavorAccessExists(MoganException):
|
||||
@ -199,21 +199,21 @@ class ComputeDiskNotFound(NotFound):
|
||||
|
||||
|
||||
class NodeNotFound(NotFound):
|
||||
_msg_fmt = _("Node associated with instance %(instance)s "
|
||||
_msg_fmt = _("Node associated with server %(server)s "
|
||||
"could not be found.")
|
||||
|
||||
|
||||
class InvalidActionParameterValue(Invalid):
|
||||
_msg_fmt = _("The Parameter value: %(value)s for %(action) action of "
|
||||
"instance %(instance)s is invalid.")
|
||||
"server %(server)s is invalid.")
|
||||
|
||||
|
||||
class InstanceDeployFailure(Invalid):
|
||||
_msg_fmt = _("Failed to deploy instance: %(reason)s")
|
||||
class ServerDeployFailure(Invalid):
|
||||
_msg_fmt = _("Failed to deploy server: %(reason)s")
|
||||
|
||||
|
||||
class InstanceDeployAborted(Invalid):
|
||||
_msg_fmt = _("Instance deployment is aborted: %(reason)s")
|
||||
class ServerDeployAborted(Invalid):
|
||||
_msg_fmt = _("Server deployment is aborted: %(reason)s")
|
||||
|
||||
|
||||
class NoFreeEngineWorker(TemporaryFailure):
|
||||
@ -223,7 +223,7 @@ class NoFreeEngineWorker(TemporaryFailure):
|
||||
|
||||
|
||||
class DuplicateName(Conflict):
|
||||
_msg_fmt = _("A instance with name %(name)s already exists.")
|
||||
_msg_fmt = _("A server with name %(name)s already exists.")
|
||||
|
||||
|
||||
class KeystoneUnauthorized(MoganException):
|
||||
@ -325,15 +325,15 @@ class NetworkNotFound(NotFound):
|
||||
|
||||
class NetworkRequiresSubnet(Invalid):
|
||||
_msg_fmt = _("Network %(network_uuid)s requires a subnet in order to boot"
|
||||
" instances on.")
|
||||
" servers on.")
|
||||
|
||||
|
||||
class InstanceIsLocked(Invalid):
|
||||
_msg_fmt = _("Instance %(instance_uuid)s is locked")
|
||||
class ServerIsLocked(Invalid):
|
||||
_msg_fmt = _("Server %(server_uuid)s is locked")
|
||||
|
||||
|
||||
class InstanceInMaintenance(Invalid):
|
||||
_msg_fmt = _("Instance %(instance_uuid)s is in maintenance mode")
|
||||
class ServerInMaintenance(Invalid):
|
||||
_msg_fmt = _("Server %(server_uuid)s is in maintenance mode")
|
||||
|
||||
|
||||
class InvalidReservationExpiration(Invalid):
|
||||
@ -396,13 +396,13 @@ class ConfigDriveUnknownFormat(MoganException):
|
||||
"iso9660 or vfat.")
|
||||
|
||||
|
||||
class InstanceUserDataTooLarge(MoganException):
|
||||
class ServerUserDataTooLarge(MoganException):
|
||||
_msg_fmt = _("User data too large. User data must be no larger than "
|
||||
"%(maxsize)s bytes once base64 encoded. Your data is "
|
||||
"%(length)d bytes")
|
||||
|
||||
|
||||
class InstanceUserDataMalformed(MoganException):
|
||||
class ServerUserDataMalformed(MoganException):
|
||||
_msg_fmt = _("User data needs to be valid base 64.")
|
||||
|
||||
|
||||
|
@ -110,7 +110,7 @@ class IronicClientWrapper(object):
|
||||
:param retry_on_conflict: Boolean value. Whether the request should be
|
||||
retried in case of a conflict error
|
||||
(HTTP 409) or not. If retry_on_conflict is
|
||||
False the cached instance of the client
|
||||
False the cached server of the client
|
||||
won't be used. Defaults to True.
|
||||
"""
|
||||
retry_on_conflict = kwargs.pop('retry_on_conflict', True)
|
||||
|
@ -42,10 +42,10 @@ default_policies = [
|
||||
policy.RuleDefault('public_api',
|
||||
'is_public_api:True',
|
||||
description='Internal flag for public API routes'),
|
||||
# Generic default to hide instance secrets
|
||||
policy.RuleDefault('show_instance_secrets',
|
||||
# Generic default to hide server secrets
|
||||
policy.RuleDefault('show_server_secrets',
|
||||
'!',
|
||||
description='Show or mask secrets within instance information in API responses'), # noqa
|
||||
description='Show or mask secrets within server information in API responses'), # noqa
|
||||
# The policy check "@" will always accept an access. The empty list
|
||||
# (``[]``) or the empty string (``""``) is equivalent to the "@"
|
||||
policy.RuleDefault('allow',
|
||||
@ -74,43 +74,43 @@ default_policies = [
|
||||
# All of these may be overridden by configuration, but we can
|
||||
# depend on their existence throughout the code.
|
||||
|
||||
instance_policies = [
|
||||
policy.RuleDefault('mogan:instance:get',
|
||||
server_policies = [
|
||||
policy.RuleDefault('mogan:server:get',
|
||||
'rule:default',
|
||||
description='Retrieve Instance records'),
|
||||
policy.RuleDefault('mogan:instance:get_states',
|
||||
description='Retrieve Server records'),
|
||||
policy.RuleDefault('mogan:server:get_states',
|
||||
'rule:default',
|
||||
description='View Instance power and provision state'),
|
||||
policy.RuleDefault('mogan:instance:create',
|
||||
description='View Server power and provision state'),
|
||||
policy.RuleDefault('mogan:server:create',
|
||||
'rule:allow',
|
||||
description='Create Instance records'),
|
||||
policy.RuleDefault('mogan:instance:delete',
|
||||
description='Create Server records'),
|
||||
policy.RuleDefault('mogan:server:delete',
|
||||
'rule:default',
|
||||
description='Delete Instance records'),
|
||||
policy.RuleDefault('mogan:instance:update',
|
||||
description='Delete Server records'),
|
||||
policy.RuleDefault('mogan:server:update',
|
||||
'rule:default',
|
||||
description='Update Instance records'),
|
||||
policy.RuleDefault('mogan:instance:set_power_state',
|
||||
description='Update Server records'),
|
||||
policy.RuleDefault('mogan:server:set_power_state',
|
||||
'rule:default',
|
||||
description='Perform the power action on an instance'),
|
||||
policy.RuleDefault('mogan:instance:get_networks',
|
||||
description='Perform the power action on a server'),
|
||||
policy.RuleDefault('mogan:server:get_networks',
|
||||
'rule:default',
|
||||
description='Get Instance network information'),
|
||||
policy.RuleDefault('mogan:instance:associate_floatingip',
|
||||
description='Get Server network information'),
|
||||
policy.RuleDefault('mogan:server:associate_floatingip',
|
||||
'rule:default',
|
||||
description='Associate a floating ip with an instance'),
|
||||
policy.RuleDefault('mogan:instance:disassociate_floatingip',
|
||||
description='Associate a floating ip with a server'),
|
||||
policy.RuleDefault('mogan:server:disassociate_floatingip',
|
||||
'rule:default',
|
||||
description='Disassociate a floating ip'),
|
||||
policy.RuleDefault('mogan:instance:set_lock_state',
|
||||
policy.RuleDefault('mogan:server:set_lock_state',
|
||||
'rule:default',
|
||||
description='Lock/UnLock an instance'),
|
||||
policy.RuleDefault('mogan:instance:set_provision_state',
|
||||
description='Lock/UnLock a server'),
|
||||
policy.RuleDefault('mogan:server:set_provision_state',
|
||||
'rule:default',
|
||||
description='Set the provision state of an instance'),
|
||||
policy.RuleDefault('mogan:instance:get_serial_console',
|
||||
description='Set the provision state of a server'),
|
||||
policy.RuleDefault('mogan:server:get_serial_console',
|
||||
'rule:default',
|
||||
description='Get serial console for an instance'),
|
||||
description='Get serial console for a server'),
|
||||
policy.RuleDefault('mogan:availability_zone:get_all',
|
||||
'rule:default',
|
||||
description='Get the availability zone list'),
|
||||
@ -119,7 +119,7 @@ instance_policies = [
|
||||
|
||||
def list_policies():
|
||||
policies = (default_policies
|
||||
+ instance_policies)
|
||||
+ server_policies)
|
||||
return policies
|
||||
|
||||
|
||||
@ -155,7 +155,7 @@ def init_enforcer(policy_file=None, rules=None,
|
||||
|
||||
|
||||
def get_enforcer():
|
||||
"""Provides access to the single instance of Policy enforcer."""
|
||||
"""Provides access to the single server of Policy enforcer."""
|
||||
|
||||
if not _ENFORCER:
|
||||
init_enforcer()
|
||||
@ -196,9 +196,9 @@ def authorize_wsgi(api_name, act=None, need_target=True):
|
||||
when create some resource , maybe target is not needed.
|
||||
example:
|
||||
from mogan.common import policy
|
||||
class InstancesController(rest.RestController):
|
||||
class ServersController(rest.RestController):
|
||||
....
|
||||
@policy.authorize_wsgi("mogan:instance", "delete")
|
||||
@policy.authorize_wsgi("mogan:server", "delete")
|
||||
@wsme_pecan.wsexpose(None, types.uuid_or_name, status_code=204)
|
||||
def delete(self, bay_ident):
|
||||
...
|
||||
|
@ -14,11 +14,11 @@
|
||||
# under the License.
|
||||
|
||||
"""
|
||||
Mapping of bare metal instance states.
|
||||
Mapping of bare metal server states.
|
||||
|
||||
Setting the instance `power_state` is handled by the engine's power
|
||||
Setting the server `power_state` is handled by the engine's power
|
||||
synchronization thread. Based on the power state retrieved from the
|
||||
hypervisor for the instance.
|
||||
hypervisor for the server.
|
||||
"""
|
||||
|
||||
from oslo_log import log as logging
|
||||
@ -32,10 +32,10 @@ LOG = logging.getLogger(__name__)
|
||||
##############
|
||||
|
||||
POWER_ON = 'power on'
|
||||
""" Instance is powered on. """
|
||||
""" Server is powered on. """
|
||||
|
||||
POWER_OFF = 'power off'
|
||||
""" Instance is powered off. """
|
||||
""" Server is powered off. """
|
||||
|
||||
NOSTATE = None
|
||||
""" No state information """
|
||||
@ -61,7 +61,7 @@ provision_state via the REST API.
|
||||
|
||||
|
||||
#################
|
||||
# Instance states
|
||||
# Server states
|
||||
#################
|
||||
|
||||
""" Mapping of state-changing events that are PUT to the REST API
|
||||
|
@ -99,7 +99,7 @@ def validate_and_normalize_mac(address):
|
||||
def make_pretty_name(method):
|
||||
"""Makes a pretty name for a function/method."""
|
||||
meth_pieces = [method.__name__]
|
||||
# If its an instance method attempt to tack on the class name
|
||||
# If its a server method attempt to tack on the class name
|
||||
if hasattr(method, '__self__') and method.__self__ is not None:
|
||||
try:
|
||||
meth_pieces.insert(0, method.__self__.__class__.__name__)
|
||||
@ -122,10 +122,10 @@ def get_state_machine(start_state=None, target_state=None):
|
||||
return fsm
|
||||
|
||||
|
||||
def process_event(fsm, instance, event=None):
|
||||
def process_event(fsm, server, event=None):
|
||||
fsm.process_event(event)
|
||||
instance.status = fsm.current_state
|
||||
instance.save()
|
||||
server.status = fsm.current_state
|
||||
server.save()
|
||||
|
||||
|
||||
def get_wrapped_function(function):
|
||||
@ -196,8 +196,8 @@ def safe_truncate(value, length):
|
||||
return u_value
|
||||
|
||||
|
||||
def add_instance_fault_from_exc(context, instance, fault, exc_info=None,
|
||||
fault_message=None):
|
||||
def add_server_fault_from_exc(context, server, fault, exc_info=None,
|
||||
fault_message=None):
|
||||
"""Adds the specified fault to the database."""
|
||||
code = 500
|
||||
if hasattr(fault, "kwargs"):
|
||||
@ -216,8 +216,8 @@ def add_instance_fault_from_exc(context, instance, fault, exc_info=None,
|
||||
fault_dict = dict(exception=fault)
|
||||
fault_dict["message"] = message
|
||||
fault_dict["code"] = code
|
||||
fault_obj = objects.InstanceFault(context=context)
|
||||
fault_obj.instance_uuid = instance.uuid
|
||||
fault_obj = objects.ServerFault(context=context)
|
||||
fault_obj.server_uuid = server.uuid
|
||||
fault_obj.update(fault_dict)
|
||||
code = fault_obj.code
|
||||
fault_obj.detail = _get_fault_detail(exc_info, code)
|
||||
|
@ -48,13 +48,13 @@ opts = [
|
||||
"the service, this option should be False; note, you "
|
||||
"will want to change public API endpoint to represent "
|
||||
"SSL termination URL with 'public_endpoint' option.")),
|
||||
cfg.StrOpt('multi_instance_name_template',
|
||||
cfg.StrOpt('multi_server_name_template',
|
||||
default='%(name)s-%(count)d',
|
||||
help='When creating multiple instances with a single request '
|
||||
'this template will be used to build the instance name '
|
||||
'for each instance. The benefit is that the instances '
|
||||
help='When creating multiple servers with a single request '
|
||||
'this template will be used to build the server name '
|
||||
'for each server. The benefit is that the servers '
|
||||
'end up with different names. To restore legacy '
|
||||
'behavior of every instance having the same name, set '
|
||||
'behavior of every server having the same name, set '
|
||||
'this option to "%(name)s". Valid keys for the '
|
||||
'template are: name, uuid, count.'),
|
||||
]
|
||||
|
@ -22,7 +22,7 @@ opts = [
|
||||
default='iso9660',
|
||||
choices=('iso9660', 'vfat'),
|
||||
help=_('Configuration drive format that will contain '
|
||||
'metadata attached to the instance when it boots.')),
|
||||
'metadata attached to the server when it boots.')),
|
||||
cfg.StrOpt('mkisofs_cmd',
|
||||
default='genisoimage',
|
||||
help=_('Name or path of the tool used for ISO image '
|
||||
|
@ -33,7 +33,7 @@ opts = [
|
||||
cfg.ListOpt('scheduler_default_filters',
|
||||
default=[
|
||||
'AvailabilityZoneFilter',
|
||||
'InstanceTypeFilter',
|
||||
'FlavorFilter',
|
||||
'CapabilitiesFilter',
|
||||
'PortsFilter'
|
||||
],
|
||||
|
@ -29,7 +29,7 @@ The IP address which is used by the ``mogan-shellinaboxproxy`` service to
|
||||
listen for incoming requests.
|
||||
|
||||
The ``mogan-shellinaboxproxy`` service listens on this IP address for incoming
|
||||
connection requests to instances which expose shellinabox serial console.
|
||||
connection requests to servers which expose shellinabox serial console.
|
||||
|
||||
Possible values:
|
||||
|
||||
@ -55,7 +55,7 @@ The port number which is used by the ``mogan-shellinaboxproxy`` service to
|
||||
listen for incoming requests.
|
||||
|
||||
The ``mogan-shellinaboxproxy`` service listens on this port number for incoming
|
||||
connection requests to instances which expose shellinabox serial console.
|
||||
connection requests to servers which expose shellinabox serial console.
|
||||
|
||||
Possible values:
|
||||
|
||||
@ -78,7 +78,7 @@ The URL an end user would use to connect to the ``mogan-shellinaboxproxy``
|
||||
service.
|
||||
|
||||
The ``mogan-shellinaboxproxy`` service is called with this token enriched URL
|
||||
and establishes the connection to the proper instance.
|
||||
and establishes the connection to the proper server.
|
||||
|
||||
Possible values:
|
||||
|
||||
|
@ -42,7 +42,7 @@ class ConsoleAuthManager(object):
|
||||
self.topic = topic
|
||||
self._started = False
|
||||
self._cache = None
|
||||
self._cache_instance = None
|
||||
self._cache_server = None
|
||||
self.engine_rpcapi = rpcapi.EngineAPI()
|
||||
|
||||
def init_host(self):
|
||||
@ -74,25 +74,25 @@ class ConsoleAuthManager(object):
|
||||
return self._cache
|
||||
|
||||
@property
|
||||
def cache_instance(self):
|
||||
"""Init a permanent cache region for instance token storage."""
|
||||
if self._cache_instance is None:
|
||||
def cache_server(self):
|
||||
"""Init a permanent cache region for server token storage."""
|
||||
if self._cache_server is None:
|
||||
cache_ttl = CONF.cache.expiration_time
|
||||
try:
|
||||
CONF.set_override('expiration_time', None, 'cache')
|
||||
cache_region = oslo_cache.create_region()
|
||||
self._cache_instance = oslo_cache.configure_cache_region(
|
||||
self._cache_server = oslo_cache.configure_cache_region(
|
||||
CONF, cache_region)
|
||||
finally:
|
||||
CONF.set_override('expiration_time', cache_ttl, 'cache')
|
||||
return self._cache_instance
|
||||
return self._cache_server
|
||||
|
||||
def reset(self):
|
||||
LOG.info('Reloading Mogan engine RPC API')
|
||||
self.engine_rpcapi = rpcapi.EngineAPI()
|
||||
|
||||
def _get_tokens_for_instance(self, instance_uuid):
|
||||
tokens_str = self.cache_instance.get(instance_uuid.encode('UTF-8'))
|
||||
def _get_tokens_for_server(self, server_uuid):
|
||||
tokens_str = self.cache_server.get(server_uuid.encode('UTF-8'))
|
||||
if not tokens_str:
|
||||
tokens = []
|
||||
else:
|
||||
@ -100,11 +100,11 @@ class ConsoleAuthManager(object):
|
||||
return tokens
|
||||
|
||||
def authorize_console(self, context, token, console_type, host, port,
|
||||
internal_access_path, instance_uuid,
|
||||
internal_access_path, server_uuid,
|
||||
access_url=None):
|
||||
|
||||
token_dict = {'token': token,
|
||||
'instance_uuid': instance_uuid,
|
||||
'server_uuid': server_uuid,
|
||||
'console_type': console_type,
|
||||
'host': host,
|
||||
'port': port,
|
||||
@ -114,7 +114,7 @@ class ConsoleAuthManager(object):
|
||||
data = jsonutils.dumps(token_dict)
|
||||
|
||||
self.cache.set(token.encode('UTF-8'), data)
|
||||
tokens = self._get_tokens_for_instance(instance_uuid)
|
||||
tokens = self._get_tokens_for_server(server_uuid)
|
||||
|
||||
# Remove the expired tokens from cache.
|
||||
token_values = self.cache.get_multi(
|
||||
@ -123,20 +123,20 @@ class ConsoleAuthManager(object):
|
||||
if value]
|
||||
tokens.append(token)
|
||||
|
||||
self.cache_instance.set(instance_uuid.encode('UTF-8'),
|
||||
jsonutils.dumps(tokens))
|
||||
self.cache_server.set(server_uuid.encode('UTF-8'),
|
||||
jsonutils.dumps(tokens))
|
||||
|
||||
LOG.info("Received Token: %(token)s, %(token_dict)s",
|
||||
{'token': token, 'token_dict': token_dict})
|
||||
|
||||
def _validate_token(self, context, token):
|
||||
instance_uuid = token['instance_uuid']
|
||||
if instance_uuid is None:
|
||||
server_uuid = token['server_uuid']
|
||||
if server_uuid is None:
|
||||
return False
|
||||
return True
|
||||
# TODO(need to validate the console port)
|
||||
# return self.compute_rpcapi.validate_console_port(
|
||||
# context, instance, token['port'], token['console_type'])
|
||||
# context, server, token['port'], token['console_type'])
|
||||
|
||||
def check_token(self, context, token):
|
||||
token_str = self.cache.get(token.encode('UTF-8'))
|
||||
@ -148,8 +148,8 @@ class ConsoleAuthManager(object):
|
||||
if self._validate_token(context, token):
|
||||
return token
|
||||
|
||||
def delete_tokens_for_instance(self, context, instance_uuid):
|
||||
tokens = self._get_tokens_for_instance(instance_uuid)
|
||||
def delete_tokens_for_server(self, context, server_uuid):
|
||||
tokens = self._get_tokens_for_server(server_uuid)
|
||||
self.cache.delete_multi(
|
||||
[tok.encode('UTF-8') for tok in tokens])
|
||||
self.cache_instance.delete(instance_uuid.encode('UTF-8'))
|
||||
self.cache_server.delete(server_uuid.encode('UTF-8'))
|
||||
|
@ -51,14 +51,14 @@ class ConsoleAuthAPI(object):
|
||||
serializer=serializer)
|
||||
|
||||
def authorize_console(self, ctxt, token, console_type, host, port,
|
||||
internal_access_path, instance_uuid,
|
||||
internal_access_path, server_uuid,
|
||||
access_url):
|
||||
# The remote side doesn't return anything, but we want to block
|
||||
# until it completes.'
|
||||
msg_args = dict(token=token, console_type=console_type,
|
||||
host=host, port=port,
|
||||
internal_access_path=internal_access_path,
|
||||
instance_uuid=instance_uuid,
|
||||
server_uuid=server_uuid,
|
||||
access_url=access_url)
|
||||
|
||||
cctxt = self.client.prepare()
|
||||
@ -68,8 +68,8 @@ class ConsoleAuthAPI(object):
|
||||
cctxt = self.client.prepare()
|
||||
return cctxt.call(ctxt, 'check_token', token=token)
|
||||
|
||||
def delete_tokens_for_instance(self, ctxt, instance_uuid):
|
||||
def delete_tokens_for_server(self, ctxt, server_uuid):
|
||||
cctxt = self.client.prepare()
|
||||
return cctxt.cast(ctxt,
|
||||
'delete_tokens_for_instance',
|
||||
instance_uuid=instance_uuid)
|
||||
'delete_tokens_for_server',
|
||||
server_uuid=server_uuid)
|
||||
|
@ -28,8 +28,8 @@ IMPL = db_api.DBAPI.from_config(cfg.CONF, backend_mapping=_BACKEND_MAPPING,
|
||||
lazy=True)
|
||||
|
||||
|
||||
def get_instance():
|
||||
"""Return a DB API instance."""
|
||||
def get_server():
|
||||
"""Return a DB API server."""
|
||||
return IMPL
|
||||
|
||||
|
||||
@ -41,46 +41,46 @@ class Connection(object):
|
||||
def __init__(self):
|
||||
"""Constructor."""
|
||||
|
||||
# Instance Types
|
||||
# Flavors
|
||||
@abc.abstractmethod
|
||||
def instance_type_create(self, context, values):
|
||||
"""Create a new instance type."""
|
||||
def flavor_create(self, context, values):
|
||||
"""Create a new server type."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def instance_type_get(self, context, instance_type_uuid):
|
||||
"""Get instance type by uuid."""
|
||||
def flavor_get(self, context, flavor_uuid):
|
||||
"""Get server type by uuid."""
|
||||
|
||||
def instance_type_update(self, context, instance_type_id, values):
|
||||
"""Update an instance type."""
|
||||
def flavor_update(self, context, flavor_id, values):
|
||||
"""Update a server type."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def instance_type_get_all(self, context):
|
||||
"""Get all instance types."""
|
||||
def flavor_get_all(self, context):
|
||||
"""Get all server types."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def instance_type_destroy(self, context, instance_type_uuid):
|
||||
"""Delete an instance type."""
|
||||
def flavor_destroy(self, context, flavor_uuid):
|
||||
"""Delete a server type."""
|
||||
|
||||
# Instances
|
||||
# Servers
|
||||
@abc.abstractmethod
|
||||
def instance_create(self, context, values):
|
||||
"""Create a new instance."""
|
||||
def server_create(self, context, values):
|
||||
"""Create a new server."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def instance_get(self, context, instance_id):
|
||||
"""Get instance by name."""
|
||||
def server_get(self, context, server_id):
|
||||
"""Get server by name."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def instance_get_all(self, context, project_only):
|
||||
"""Get all instances."""
|
||||
def server_get_all(self, context, project_only):
|
||||
"""Get all servers."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def instance_destroy(self, context, instance_id):
|
||||
"""Delete an instance."""
|
||||
def server_destroy(self, context, server_id):
|
||||
"""Delete a server."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def instance_update(self, context, instance_id, values):
|
||||
"""Update an instance."""
|
||||
def server_update(self, context, server_id, values):
|
||||
"""Update a server."""
|
||||
|
||||
# Compute nodes
|
||||
@abc.abstractmethod
|
||||
@ -157,23 +157,23 @@ class Connection(object):
|
||||
def compute_disk_update(self, context, disk_uuid, values):
|
||||
"""Update a compute disk."""
|
||||
|
||||
# Instance Type extra specs
|
||||
# Flavor extra specs
|
||||
@abc.abstractmethod
|
||||
def extra_specs_update_or_create(self, context,
|
||||
instance_type_uuid, extra_specs):
|
||||
"""Create or update instance type extra specs.
|
||||
flavor_uuid, extra_specs):
|
||||
"""Create or update server type extra specs.
|
||||
|
||||
This adds or modifies the key/value pairs specified in the
|
||||
extra specs dict argument
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def instance_type_extra_specs_get(self, context, type_id):
|
||||
"""Get instance type extra specs"""
|
||||
def flavor_extra_specs_get(self, context, type_id):
|
||||
"""Get server type extra specs"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def type_extra_specs_delete(self, context, instance_type_uuid, key):
|
||||
"""Delete instance type extra specs.
|
||||
def type_extra_specs_delete(self, context, flavor_uuid, key):
|
||||
"""Delete server type extra specs.
|
||||
|
||||
This deletes the key/value pairs specified in the
|
||||
extra specs dict argument
|
||||
@ -193,25 +193,25 @@ class Connection(object):
|
||||
"""Remove flavor access for project."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def instance_nics_get_by_instance_uuid(self, context, instance_uuid):
|
||||
"""Get the Nics info of an instnace.
|
||||
def server_nics_get_by_server_uuid(self, context, server_uuid):
|
||||
"""Get the Nics info of a server.
|
||||
|
||||
This query the Nics info of the specified instance.
|
||||
This query the Nics info of the specified server.
|
||||
"""
|
||||
|
||||
def instance_nic_update_or_create(self, context, port_id, values):
|
||||
def server_nic_update_or_create(self, context, port_id, values):
|
||||
"""Update/Create a nic db entry.
|
||||
|
||||
This creates or updates a nic db entry.
|
||||
"""
|
||||
# Instances Faults
|
||||
# Servers Faults
|
||||
@abc.abstractmethod
|
||||
def instance_fault_create(self, context, values):
|
||||
"""Create a new Instance Fault."""
|
||||
def server_fault_create(self, context, values):
|
||||
"""Create a new Server Fault."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def instance_fault_get_by_instance_uuids(self, context, instance_uuids):
|
||||
"""Get all instance faults for the provided instance_uuids."""
|
||||
def server_fault_get_by_server_uuids(self, context, server_uuids):
|
||||
"""Get all server faults for the provided server_uuids."""
|
||||
|
||||
@abc.abstractmethod
|
||||
def quota_get(self, context, project_id, resource_name):
|
||||
|
@ -29,7 +29,7 @@ import sqlalchemy as sa
|
||||
|
||||
def upgrade():
|
||||
op.create_table(
|
||||
'instance_types',
|
||||
'flavors',
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('uuid', sa.String(length=36), nullable=False),
|
||||
@ -41,34 +41,34 @@ def upgrade():
|
||||
mysql_DEFAULT_CHARSET='UTF8'
|
||||
)
|
||||
op.create_table(
|
||||
'instance_type_extra_specs',
|
||||
'flavor_extra_specs',
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('instance_type_uuid', sa.String(length=36), nullable=False),
|
||||
sa.Column('flavor_uuid', sa.String(length=36), nullable=False),
|
||||
sa.Column('key', sa.String(length=255), nullable=False),
|
||||
sa.Column('value', sa.String(length=255), nullable=False),
|
||||
sa.ForeignKeyConstraint(['instance_type_uuid'],
|
||||
['instance_types.uuid']),
|
||||
sa.ForeignKeyConstraint(['flavor_uuid'],
|
||||
['flavors.uuid']),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
mysql_ENGINE='InnoDB',
|
||||
mysql_DEFAULT_CHARSET='UTF8'
|
||||
)
|
||||
op.create_table(
|
||||
'instance_type_projects',
|
||||
'flavor_projects',
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('instance_type_uuid', sa.String(length=36), nullable=True),
|
||||
sa.Column('flavor_uuid', sa.String(length=36), nullable=True),
|
||||
sa.Column('project_id', sa.String(length=36), nullable=True),
|
||||
sa.ForeignKeyConstraint(['instance_type_uuid'],
|
||||
['instance_types.uuid']),
|
||||
sa.ForeignKeyConstraint(['flavor_uuid'],
|
||||
['flavors.uuid']),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
mysql_ENGINE='InnoDB',
|
||||
mysql_DEFAULT_CHARSET='UTF8'
|
||||
)
|
||||
op.create_table(
|
||||
'instances',
|
||||
'servers',
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('uuid', sa.String(length=36), nullable=True),
|
||||
@ -79,7 +79,7 @@ def upgrade():
|
||||
sa.Column('description', sa.String(length=255), nullable=True),
|
||||
sa.Column('status', sa.String(length=255), nullable=True),
|
||||
sa.Column('power_state', sa.String(length=15), nullable=True),
|
||||
sa.Column('instance_type_uuid', sa.String(length=36), nullable=True),
|
||||
sa.Column('flavor_uuid', sa.String(length=36), nullable=True),
|
||||
sa.Column('image_uuid', sa.String(length=36), nullable=True),
|
||||
sa.Column('launched_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('availability_zone', sa.String(length=255), nullable=True),
|
||||
@ -88,7 +88,7 @@ def upgrade():
|
||||
sa.Column('locked', sa.Boolean(), nullable=True),
|
||||
sa.Column('locked_by', sa.Enum('admin', 'owner'), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
sa.UniqueConstraint('uuid', name='uniq_instances0uuid'),
|
||||
sa.UniqueConstraint('uuid', name='uniq_servers0uuid'),
|
||||
mysql_ENGINE='InnoDB',
|
||||
mysql_DEFAULT_CHARSET='UTF8'
|
||||
)
|
||||
@ -143,31 +143,31 @@ def upgrade():
|
||||
mysql_DEFAULT_CHARSET='UTF8'
|
||||
)
|
||||
op.create_table(
|
||||
'instance_nics',
|
||||
'server_nics',
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('instance_uuid', sa.String(length=36), nullable=False),
|
||||
sa.Column('server_uuid', sa.String(length=36), nullable=False),
|
||||
sa.Column('port_id', sa.String(length=36), nullable=False),
|
||||
sa.Column('mac_address', sa.String(length=36), nullable=True),
|
||||
sa.Column('network_id', sa.String(length=36), nullable=True),
|
||||
sa.Column('port_type', sa.String(length=64), nullable=True),
|
||||
sa.Column('floating_ip', sa.String(length=64), nullable=True),
|
||||
sa.Column('fixed_ips', sa.Text(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['instance_uuid'], ['instances.uuid'], ),
|
||||
sa.ForeignKeyConstraint(['server_uuid'], ['servers.uuid'], ),
|
||||
sa.PrimaryKeyConstraint('port_id'),
|
||||
mysql_ENGINE='InnoDB',
|
||||
mysql_DEFAULT_CHARSET='UTF8'
|
||||
)
|
||||
op.create_table(
|
||||
'instance_faults',
|
||||
'server_faults',
|
||||
sa.Column('id', sa.Integer(), nullable=False),
|
||||
sa.Column('instance_uuid', sa.String(length=36), nullable=True),
|
||||
sa.Column('server_uuid', sa.String(length=36), nullable=True),
|
||||
sa.Column('code', sa.Integer(), nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('message', sa.String(length=255), nullable=True),
|
||||
sa.Column('detail', sa.Text(), nullable=True),
|
||||
sa.ForeignKeyConstraint(['instance_uuid'], ['instances.uuid']),
|
||||
sa.ForeignKeyConstraint(['server_uuid'], ['servers.uuid']),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
mysql_ENGINE='InnoDB',
|
||||
mysql_DEFAULT_CHARSET='UTF8'
|
||||
|
@ -94,164 +94,164 @@ def add_identity_filter(query, value):
|
||||
raise exception.InvalidParameterValue(identity=value)
|
||||
|
||||
|
||||
def _dict_with_extra_specs(inst_type_query):
|
||||
"""Takes an instance type query and returns it as a dictionary."""
|
||||
inst_type_dict = dict(inst_type_query)
|
||||
def _dict_with_extra_specs(flavor_query):
|
||||
"""Takes a server type query and returns it as a dictionary."""
|
||||
flavor_dict = dict(flavor_query)
|
||||
extra_specs = {x['key']: x['value']
|
||||
for x in inst_type_query['extra_specs']}
|
||||
inst_type_dict['extra_specs'] = extra_specs
|
||||
return inst_type_dict
|
||||
for x in flavor_query['extra_specs']}
|
||||
flavor_dict['extra_specs'] = extra_specs
|
||||
return flavor_dict
|
||||
|
||||
|
||||
class Connection(api.Connection):
|
||||
"""SqlAlchemy connection."""
|
||||
|
||||
def __init__(self):
|
||||
self.QUOTA_SYNC_FUNCTIONS = {'_sync_instances': self._sync_instances}
|
||||
self.QUOTA_SYNC_FUNCTIONS = {'_sync_servers': self._sync_servers}
|
||||
pass
|
||||
|
||||
def instance_type_create(self, context, values):
|
||||
def flavor_create(self, context, values):
|
||||
if not values.get('uuid'):
|
||||
values['uuid'] = uuidutils.generate_uuid()
|
||||
|
||||
if not values.get('description'):
|
||||
values['description'] = ""
|
||||
|
||||
instance_type = models.InstanceTypes()
|
||||
instance_type.update(values)
|
||||
flavor = models.Flavors()
|
||||
flavor.update(values)
|
||||
|
||||
with _session_for_write() as session:
|
||||
try:
|
||||
session.add(instance_type)
|
||||
session.add(flavor)
|
||||
session.flush()
|
||||
except db_exc.DBDuplicateEntry:
|
||||
raise exception.FlavorAlreadyExists(uuid=values['uuid'])
|
||||
return _dict_with_extra_specs(instance_type)
|
||||
return _dict_with_extra_specs(flavor)
|
||||
|
||||
def instance_type_get(self, context, instance_type_uuid):
|
||||
query = model_query(context, models.InstanceTypes).filter_by(
|
||||
uuid=instance_type_uuid).options(joinedload('extra_specs'))
|
||||
def flavor_get(self, context, flavor_uuid):
|
||||
query = model_query(context, models.Flavors).filter_by(
|
||||
uuid=flavor_uuid).options(joinedload('extra_specs'))
|
||||
try:
|
||||
return _dict_with_extra_specs(query.one())
|
||||
except NoResultFound:
|
||||
raise exception.FlavorNotFound(
|
||||
type_id=instance_type_uuid)
|
||||
type_id=flavor_uuid)
|
||||
|
||||
def instance_type_update(self, context, instance_type_id, values):
|
||||
def flavor_update(self, context, flavor_id, values):
|
||||
with _session_for_write():
|
||||
query = model_query(context, models.InstanceTypes)
|
||||
query = add_identity_filter(query, instance_type_id)
|
||||
query = model_query(context, models.Flavors)
|
||||
query = add_identity_filter(query, flavor_id)
|
||||
try:
|
||||
ref = query.with_lockmode('update').one()
|
||||
except NoResultFound:
|
||||
raise exception.FlavorNotFound(
|
||||
type_id=instance_type_id)
|
||||
type_id=flavor_id)
|
||||
|
||||
ref.update(values)
|
||||
return ref
|
||||
|
||||
def instance_type_get_all(self, context):
|
||||
results = model_query(context, models.InstanceTypes)
|
||||
def flavor_get_all(self, context):
|
||||
results = model_query(context, models.Flavors)
|
||||
return [_dict_with_extra_specs(i) for i in results]
|
||||
|
||||
def instance_type_destroy(self, context, instance_type_uuid):
|
||||
def flavor_destroy(self, context, flavor_uuid):
|
||||
with _session_for_write():
|
||||
# First clean up all extra specs related to this type
|
||||
type_id = _type_get_id_from_type(context, instance_type_uuid)
|
||||
type_id = _type_get_id_from_type(context, flavor_uuid)
|
||||
extra_query = model_query(
|
||||
context,
|
||||
models.InstanceTypeExtraSpecs).filter_by(
|
||||
instance_type_uuid=type_id)
|
||||
models.FlavorExtraSpecs).filter_by(
|
||||
flavor_uuid=type_id)
|
||||
extra_query.delete()
|
||||
|
||||
# Clean up all access related to this flavor
|
||||
project_query = model_query(
|
||||
context,
|
||||
models.InstanceTypeProjects).filter_by(
|
||||
instance_type_uuid=type_id)
|
||||
models.FlavorProjects).filter_by(
|
||||
flavor_uuid=type_id)
|
||||
project_query.delete()
|
||||
|
||||
# Then delete the type record
|
||||
query = model_query(context, models.InstanceTypes)
|
||||
query = add_identity_filter(query, instance_type_uuid)
|
||||
query = model_query(context, models.Flavors)
|
||||
query = add_identity_filter(query, flavor_uuid)
|
||||
|
||||
count = query.delete()
|
||||
if count != 1:
|
||||
raise exception.FlavorNotFound(
|
||||
type_id=instance_type_uuid)
|
||||
type_id=flavor_uuid)
|
||||
|
||||
def instance_create(self, context, values):
|
||||
def server_create(self, context, values):
|
||||
if not values.get('uuid'):
|
||||
values['uuid'] = uuidutils.generate_uuid()
|
||||
|
||||
instance_nics = values.pop('nics', [])
|
||||
instance = models.Instance()
|
||||
instance.update(values)
|
||||
server_nics = values.pop('nics', [])
|
||||
server = models.Server()
|
||||
server.update(values)
|
||||
nic_refs = []
|
||||
for nic in instance_nics:
|
||||
nic_ref = models.InstanceNic()
|
||||
for nic in server_nics:
|
||||
nic_ref = models.ServerNic()
|
||||
nic_ref.update(nic)
|
||||
nic_refs.append(nic_ref)
|
||||
with _session_for_write() as session:
|
||||
try:
|
||||
session.add(instance)
|
||||
session.add(server)
|
||||
for nic_r in nic_refs:
|
||||
session.add(nic_r)
|
||||
session.flush()
|
||||
except db_exc.DBDuplicateEntry:
|
||||
raise exception.InstanceAlreadyExists(name=values['name'])
|
||||
return instance
|
||||
raise exception.ServerAlreadyExists(name=values['name'])
|
||||
return server
|
||||
|
||||
def instance_get(self, context, instance_id):
|
||||
def server_get(self, context, server_id):
|
||||
query = model_query(
|
||||
context,
|
||||
models.Instance,
|
||||
instance=True).filter_by(uuid=instance_id)
|
||||
models.Server,
|
||||
server=True).filter_by(uuid=server_id)
|
||||
try:
|
||||
return query.one()
|
||||
except NoResultFound:
|
||||
raise exception.InstanceNotFound(instance=instance_id)
|
||||
raise exception.ServerNotFound(server=server_id)
|
||||
|
||||
def instance_get_all(self, context, project_only):
|
||||
return model_query(context, models.Instance,
|
||||
instance=True, project_only=project_only)
|
||||
def server_get_all(self, context, project_only):
|
||||
return model_query(context, models.Server,
|
||||
server=True, project_only=project_only)
|
||||
|
||||
def instance_destroy(self, context, instance_id):
|
||||
def server_destroy(self, context, server_id):
|
||||
with _session_for_write():
|
||||
query = model_query(context, models.Instance)
|
||||
query = add_identity_filter(query, instance_id)
|
||||
query = model_query(context, models.Server)
|
||||
query = add_identity_filter(query, server_id)
|
||||
|
||||
nics_query = model_query(context, models.InstanceNic).filter_by(
|
||||
instance_uuid=instance_id)
|
||||
nics_query = model_query(context, models.ServerNic).filter_by(
|
||||
server_uuid=server_id)
|
||||
nics_query.delete()
|
||||
|
||||
faults_query = model_query(
|
||||
context,
|
||||
models.InstanceFault).filter_by(instance_uuid=instance_id)
|
||||
models.ServerFault).filter_by(server_uuid=server_id)
|
||||
faults_query.delete()
|
||||
count = query.delete()
|
||||
if count != 1:
|
||||
raise exception.InstanceNotFound(instance=instance_id)
|
||||
raise exception.ServerNotFound(server=server_id)
|
||||
|
||||
def instance_update(self, context, instance_id, values):
|
||||
def server_update(self, context, server_id, values):
|
||||
if 'uuid' in values:
|
||||
msg = _("Cannot overwrite UUID for an existing Instance.")
|
||||
msg = _("Cannot overwrite UUID for an existing Server.")
|
||||
raise exception.InvalidParameterValue(err=msg)
|
||||
|
||||
try:
|
||||
return self._do_update_instance(context, instance_id, values)
|
||||
return self._do_update_server(context, server_id, values)
|
||||
except db_exc.DBDuplicateEntry as e:
|
||||
if 'name' in e.columns:
|
||||
raise exception.DuplicateName(name=values['name'])
|
||||
|
||||
def _do_update_instance(self, context, instance_id, values):
|
||||
def _do_update_server(self, context, server_id, values):
|
||||
with _session_for_write():
|
||||
query = model_query(context, models.Instance, instance=True)
|
||||
query = add_identity_filter(query, instance_id)
|
||||
query = model_query(context, models.Server, server=True)
|
||||
query = add_identity_filter(query, server_id)
|
||||
try:
|
||||
ref = query.with_lockmode('update').one()
|
||||
except NoResultFound:
|
||||
raise exception.InstanceNotFound(instance=instance_id)
|
||||
raise exception.ServerNotFound(server=server_id)
|
||||
|
||||
ref.update(values)
|
||||
return ref
|
||||
@ -423,9 +423,9 @@ class Connection(api.Connection):
|
||||
return ref
|
||||
|
||||
def extra_specs_update_or_create(self, context,
|
||||
instance_type_uuid, specs,
|
||||
flavor_uuid, specs,
|
||||
max_retries=10):
|
||||
"""Create or update instance type extra specs.
|
||||
"""Create or update server type extra specs.
|
||||
|
||||
This adds or modifies the key/value pairs specified in the
|
||||
extra specs dict argument
|
||||
@ -434,9 +434,9 @@ class Connection(api.Connection):
|
||||
with _session_for_write() as session:
|
||||
try:
|
||||
spec_refs = model_query(
|
||||
context, models.InstanceTypeExtraSpecs). \
|
||||
filter_by(instance_type_uuid=instance_type_uuid). \
|
||||
filter(models.InstanceTypeExtraSpecs.key.in_(
|
||||
context, models.FlavorExtraSpecs). \
|
||||
filter_by(flavor_uuid=flavor_uuid). \
|
||||
filter(models.FlavorExtraSpecs.key.in_(
|
||||
specs.keys())).with_lockmode('update').all()
|
||||
|
||||
existing_keys = set()
|
||||
@ -448,10 +448,10 @@ class Connection(api.Connection):
|
||||
for key, value in specs.items():
|
||||
if key in existing_keys:
|
||||
continue
|
||||
spec_ref = models.InstanceTypeExtraSpecs()
|
||||
spec_ref = models.FlavorExtraSpecs()
|
||||
spec_ref.update(
|
||||
{"key": key, "value": value,
|
||||
"instance_type_uuid": instance_type_uuid})
|
||||
"flavor_uuid": flavor_uuid})
|
||||
|
||||
session.add(spec_ref)
|
||||
session.flush()
|
||||
@ -462,15 +462,15 @@ class Connection(api.Connection):
|
||||
# try again unless this was the last attempt
|
||||
if attempt == max_retries - 1:
|
||||
raise exception.FlavorExtraSpecUpdateCreateFailed(
|
||||
id=instance_type_uuid, retries=max_retries)
|
||||
id=flavor_uuid, retries=max_retries)
|
||||
|
||||
def instance_type_extra_specs_get(self, context, type_id):
|
||||
def flavor_extra_specs_get(self, context, type_id):
|
||||
rows = _type_extra_specs_get_query(context, type_id).all()
|
||||
return {row['key']: row['value'] for row in rows}
|
||||
|
||||
def type_extra_specs_delete(self, context, type_id, key):
|
||||
result = _type_extra_specs_get_query(context, type_id). \
|
||||
filter(models.InstanceTypeExtraSpecs.key == key). \
|
||||
filter(models.FlavorExtraSpecs.key == key). \
|
||||
delete(synchronize_session=False)
|
||||
# did not find the extra spec
|
||||
if result == 0:
|
||||
@ -481,8 +481,8 @@ class Connection(api.Connection):
|
||||
return _flavor_access_query(context, flavor_id)
|
||||
|
||||
def flavor_access_add(self, context, flavor_id, project_id):
|
||||
access_ref = models.InstanceTypeProjects()
|
||||
access_ref.update({"instance_type_uuid": flavor_id,
|
||||
access_ref = models.FlavorProjects()
|
||||
access_ref.update({"flavor_uuid": flavor_id,
|
||||
"project_id": project_id})
|
||||
with _session_for_write() as session:
|
||||
try:
|
||||
@ -502,27 +502,27 @@ class Connection(api.Connection):
|
||||
raise exception.FlavorAccessNotFound(flavor_id=flavor_id,
|
||||
project_id=project_id)
|
||||
|
||||
def instance_nic_update_or_create(self, context, port_id, values):
|
||||
def server_nic_update_or_create(self, context, port_id, values):
|
||||
with _session_for_write() as session:
|
||||
query = model_query(context, models.InstanceNic).filter_by(
|
||||
query = model_query(context, models.ServerNic).filter_by(
|
||||
port_id=port_id)
|
||||
nic = query.first()
|
||||
if not nic:
|
||||
nic = models.InstanceNic()
|
||||
nic = models.ServerNic()
|
||||
values.update(port_id=port_id)
|
||||
nic.update(values)
|
||||
session.add(nic)
|
||||
session.flush()
|
||||
return nic
|
||||
|
||||
def instance_nics_get_by_instance_uuid(self, context, instance_uuid):
|
||||
return model_query(context, models.InstanceNic).filter_by(
|
||||
instance_uuid=instance_uuid).all()
|
||||
def server_nics_get_by_server_uuid(self, context, server_uuid):
|
||||
return model_query(context, models.ServerNic).filter_by(
|
||||
server_uuid=server_uuid).all()
|
||||
|
||||
def instance_fault_create(self, context, values):
|
||||
"""Create a new InstanceFault."""
|
||||
def server_fault_create(self, context, values):
|
||||
"""Create a new ServerFault."""
|
||||
|
||||
fault = models.InstanceFault()
|
||||
fault = models.ServerFault()
|
||||
fault.update(values)
|
||||
|
||||
with _session_for_write() as session:
|
||||
@ -530,22 +530,22 @@ class Connection(api.Connection):
|
||||
session.flush()
|
||||
return fault
|
||||
|
||||
def instance_fault_get_by_instance_uuids(self, context, instance_uuids):
|
||||
"""Get all instance faults for the provided instance_uuids."""
|
||||
if not instance_uuids:
|
||||
def server_fault_get_by_server_uuids(self, context, server_uuids):
|
||||
"""Get all server faults for the provided server_uuids."""
|
||||
if not server_uuids:
|
||||
return {}
|
||||
|
||||
rows = model_query(context, models.InstanceFault).\
|
||||
filter(models.InstanceFault.instance_uuid.in_(instance_uuids)).\
|
||||
rows = model_query(context, models.ServerFault).\
|
||||
filter(models.ServerFault.server_uuid.in_(server_uuids)).\
|
||||
order_by(desc("created_at"), desc("id")).all()
|
||||
|
||||
output = {}
|
||||
for instance_uuid in instance_uuids:
|
||||
output[instance_uuid] = []
|
||||
for server_uuid in server_uuids:
|
||||
output[server_uuid] = []
|
||||
|
||||
for row in rows:
|
||||
data = dict(row)
|
||||
output[row['instance_uuid']].append(data)
|
||||
output[row['server_uuid']].append(data)
|
||||
|
||||
return output
|
||||
|
||||
@ -679,10 +679,10 @@ class Connection(api.Connection):
|
||||
project_id=project_id)
|
||||
return reservation_ref
|
||||
|
||||
def _sync_instances(self, context, project_id):
|
||||
query = model_query(context, models.Instance, instance=True).\
|
||||
def _sync_servers(self, context, project_id):
|
||||
query = model_query(context, models.Server, server=True).\
|
||||
filter_by(project_id=project_id).all()
|
||||
return {'instances': len(query) or 0}
|
||||
return {'servers': len(query) or 0}
|
||||
|
||||
def quota_reserve(self, context, resources, quotas, deltas, expire,
|
||||
until_refresh, max_age, project_id,
|
||||
@ -902,7 +902,7 @@ class Connection(api.Connection):
|
||||
|
||||
|
||||
def _type_get_id_from_type_query(context, type_id):
|
||||
return model_query(context, models.InstanceTypes). \
|
||||
return model_query(context, models.Flavors). \
|
||||
filter_by(uuid=type_id)
|
||||
|
||||
|
||||
@ -914,10 +914,10 @@ def _type_get_id_from_type(context, type_id):
|
||||
|
||||
|
||||
def _type_extra_specs_get_query(context, type_id):
|
||||
return model_query(context, models.InstanceTypeExtraSpecs). \
|
||||
filter_by(instance_type_uuid=type_id)
|
||||
return model_query(context, models.FlavorExtraSpecs). \
|
||||
filter_by(flavor_uuid=type_id)
|
||||
|
||||
|
||||
def _flavor_access_query(context, flavor_id):
|
||||
return model_query(context, models.InstanceTypeProjects). \
|
||||
filter_by(instance_type_uuid=flavor_id)
|
||||
return model_query(context, models.FlavorProjects). \
|
||||
filter_by(flavor_uuid=flavor_id)
|
||||
|
@ -63,12 +63,12 @@ class MoganBase(models.TimestampMixin,
|
||||
Base = declarative_base(cls=MoganBase)
|
||||
|
||||
|
||||
class Instance(Base):
|
||||
"""Represents possible types for instances."""
|
||||
class Server(Base):
|
||||
"""Represents possible types for servers."""
|
||||
|
||||
__tablename__ = 'instances'
|
||||
__tablename__ = 'servers'
|
||||
__table_args__ = (
|
||||
schema.UniqueConstraint('uuid', name='uniq_instances0uuid'),
|
||||
schema.UniqueConstraint('uuid', name='uniq_servers0uuid'),
|
||||
table_args()
|
||||
)
|
||||
id = Column(Integer, primary_key=True)
|
||||
@ -79,7 +79,7 @@ class Instance(Base):
|
||||
user_id = Column(String(36), nullable=True)
|
||||
status = Column(String(255), nullable=True)
|
||||
power_state = Column(String(15), nullable=True)
|
||||
instance_type_uuid = Column(String(36), nullable=True)
|
||||
flavor_uuid = Column(String(36), nullable=True)
|
||||
availability_zone = Column(String(255), nullable=True)
|
||||
image_uuid = Column(String(36), nullable=True)
|
||||
node_uuid = Column(String(36), nullable=True)
|
||||
@ -153,100 +153,99 @@ class ComputeDisk(Base):
|
||||
primaryjoin='ComputeNode.node_uuid == ComputeDisk.node_uuid')
|
||||
|
||||
|
||||
class InstanceNic(Base):
|
||||
"""Represents the NIC info for instances."""
|
||||
class ServerNic(Base):
|
||||
"""Represents the NIC info for servers."""
|
||||
|
||||
__tablename__ = 'instance_nics'
|
||||
instance_uuid = Column(String(36), nullable=True)
|
||||
__tablename__ = 'server_nics'
|
||||
server_uuid = Column(String(36), nullable=True)
|
||||
port_id = Column(String(36), primary_key=True)
|
||||
mac_address = Column(String(32), nullable=False)
|
||||
network_id = Column(String(36), nullable=True)
|
||||
fixed_ips = Column(db_types.JsonEncodedList)
|
||||
port_type = Column(String(64), nullable=True)
|
||||
floating_ip = Column(String(64), nullable=True)
|
||||
_instance = orm.relationship(
|
||||
Instance,
|
||||
backref=orm.backref('instance_nics', uselist=False),
|
||||
foreign_keys=instance_uuid,
|
||||
primaryjoin='Instance.uuid == InstanceNic.instance_uuid')
|
||||
_server = orm.relationship(
|
||||
Server,
|
||||
backref=orm.backref('server_nics', uselist=False),
|
||||
foreign_keys=server_uuid,
|
||||
primaryjoin='Server.uuid == ServerNic.server_uuid')
|
||||
|
||||
|
||||
class InstanceTypes(Base):
|
||||
"""Represents possible types for instances."""
|
||||
class Flavors(Base):
|
||||
"""Represents possible types for servers."""
|
||||
|
||||
__tablename__ = 'instance_types'
|
||||
__tablename__ = 'flavors'
|
||||
uuid = Column(String(36), primary_key=True)
|
||||
name = Column(String(255), nullable=False)
|
||||
description = Column(String(255), nullable=True)
|
||||
is_public = Column(Boolean, default=True)
|
||||
instances = orm.relationship(
|
||||
Instance,
|
||||
backref=orm.backref('instance_type', uselist=False),
|
||||
servers = orm.relationship(
|
||||
Server,
|
||||
backref=orm.backref('flavor', uselist=False),
|
||||
foreign_keys=uuid,
|
||||
primaryjoin='Instance.instance_type_uuid == InstanceTypes.uuid')
|
||||
primaryjoin='Server.flavor_uuid == Flavors.uuid')
|
||||
|
||||
|
||||
class InstanceTypeProjects(Base):
|
||||
"""Represents projects associated instance_types."""
|
||||
class FlavorProjects(Base):
|
||||
"""Represents projects associated flavors."""
|
||||
|
||||
__tablename__ = 'instance_type_projects'
|
||||
__tablename__ = 'flavor_projects'
|
||||
__table_args__ = (
|
||||
schema.UniqueConstraint(
|
||||
'instance_type_uuid', 'project_id',
|
||||
name='uniq_instance_type_projects0instance_type_uuid0project_id'
|
||||
'flavor_uuid', 'project_id',
|
||||
name='uniq_flavor_projects0flavor_uuid0project_id'
|
||||
),
|
||||
table_args()
|
||||
)
|
||||
id = Column(Integer, primary_key=True)
|
||||
instance_type_uuid = Column(Integer, nullable=True)
|
||||
flavor_uuid = Column(Integer, nullable=True)
|
||||
project_id = Column(String(36), nullable=True)
|
||||
instances = orm.relationship(
|
||||
InstanceTypes,
|
||||
servers = orm.relationship(
|
||||
Flavors,
|
||||
backref=orm.backref('projects', uselist=False),
|
||||
foreign_keys=instance_type_uuid,
|
||||
primaryjoin='InstanceTypeProjects.instance_type_uuid'
|
||||
' == InstanceTypes.uuid')
|
||||
foreign_keys=flavor_uuid,
|
||||
primaryjoin='FlavorProjects.flavor_uuid'
|
||||
' == Flavors.uuid')
|
||||
|
||||
|
||||
class InstanceTypeExtraSpecs(Base):
|
||||
"""Represents additional specs as key/value pairs for an instance_type."""
|
||||
__tablename__ = 'instance_type_extra_specs'
|
||||
class FlavorExtraSpecs(Base):
|
||||
"""Represents additional specs as key/value pairs for an flavor."""
|
||||
__tablename__ = 'flavor_extra_specs'
|
||||
__table_args__ = (
|
||||
schema.UniqueConstraint(
|
||||
"instance_type_uuid", "key",
|
||||
name=("uniq_instance_type_extra_specs0"
|
||||
"instance_type_uuid")
|
||||
"flavor_uuid", "key",
|
||||
name=("uniq_flavor_extra_specs0"
|
||||
"flavor_uuid")
|
||||
),
|
||||
{'mysql_collate': 'utf8_bin'},
|
||||
)
|
||||
id = Column(Integer, primary_key=True)
|
||||
key = Column(String(255))
|
||||
value = Column(String(255))
|
||||
instance_type_uuid = Column(String(36), ForeignKey('instance_types.uuid'),
|
||||
nullable=False)
|
||||
instance_type = orm.relationship(
|
||||
InstanceTypes, backref="extra_specs",
|
||||
foreign_keys=instance_type_uuid,
|
||||
primaryjoin='InstanceTypeExtraSpecs.instance_type_uuid '
|
||||
'== InstanceTypes.uuid')
|
||||
flavor_uuid = Column(String(36), ForeignKey('flavors.uuid'),
|
||||
nullable=False)
|
||||
flavor = orm.relationship(
|
||||
Flavors, backref="extra_specs",
|
||||
foreign_keys=flavor_uuid,
|
||||
primaryjoin='FlavorExtraSpecs.flavor_uuid '
|
||||
'== Flavors.uuid')
|
||||
|
||||
|
||||
class InstanceFault(Base):
|
||||
"""Represents fault info for instance"""
|
||||
class ServerFault(Base):
|
||||
"""Represents fault info for server"""
|
||||
|
||||
__tablename__ = "instance_faults"
|
||||
__tablename__ = "server_faults"
|
||||
|
||||
id = Column(Integer, primary_key=True, nullable=False)
|
||||
instance_uuid = Column(String(36),
|
||||
ForeignKey('instances.uuid'))
|
||||
server_uuid = Column(String(36), ForeignKey('servers.uuid'))
|
||||
code = Column(Integer(), nullable=False)
|
||||
message = Column(String(255))
|
||||
detail = Column(MediumText())
|
||||
instance = orm.relationship(
|
||||
Instance,
|
||||
backref=orm.backref('instance_faults', uselist=False),
|
||||
foreign_keys=instance_uuid,
|
||||
primaryjoin='Instance.uuid == InstanceFault.instance_uuid')
|
||||
server = orm.relationship(
|
||||
Server,
|
||||
backref=orm.backref('server_faults', uselist=False),
|
||||
foreign_keys=server_uuid,
|
||||
primaryjoin='Server.uuid == ServerFault.server_uuid')
|
||||
|
||||
|
||||
class Quota(Base):
|
||||
|
@ -42,21 +42,21 @@ LOG = log.getLogger(__name__)
|
||||
MAX_USERDATA_SIZE = 65535
|
||||
|
||||
|
||||
def check_instance_lock(function):
|
||||
def check_server_lock(function):
|
||||
@six.wraps(function)
|
||||
def inner(self, context, instance, *args, **kwargs):
|
||||
if instance.locked and not context.is_admin:
|
||||
raise exception.InstanceIsLocked(instance_uuid=instance.uuid)
|
||||
return function(self, context, instance, *args, **kwargs)
|
||||
def inner(self, context, server, *args, **kwargs):
|
||||
if server.locked and not context.is_admin:
|
||||
raise exception.ServerIsLocked(server_uuid=server.uuid)
|
||||
return function(self, context, server, *args, **kwargs)
|
||||
return inner
|
||||
|
||||
|
||||
def check_instance_maintenance(function):
|
||||
def check_server_maintenance(function):
|
||||
@six.wraps(function)
|
||||
def inner(self, context, instance, *args, **kwargs):
|
||||
if instance.status == states.MAINTENANCE:
|
||||
raise exception.InstanceInMaintenance(instance_uuid=instance.uuid)
|
||||
return function(self, context, instance, *args, **kwargs)
|
||||
def inner(self, context, server, *args, **kwargs):
|
||||
if server.status == states.MAINTENANCE:
|
||||
raise exception.ServerInMaintenance(server_uuid=server.uuid)
|
||||
return function(self, context, server, *args, **kwargs)
|
||||
return inner
|
||||
|
||||
|
||||
@ -69,13 +69,13 @@ class API(object):
|
||||
self.engine_rpcapi = rpcapi.EngineAPI()
|
||||
self.network_api = network.API()
|
||||
self.quota = quota.Quota()
|
||||
self.quota.register_resource(objects.quota.InstanceResource())
|
||||
self.quota.register_resource(objects.quota.ServerResource())
|
||||
self.consoleauth_rpcapi = consoleauth_rpcapi.ConsoleAuthAPI()
|
||||
|
||||
def _get_image(self, context, image_uuid):
|
||||
return self.image_api.get(context, image_uuid)
|
||||
|
||||
def _validate_and_build_base_options(self, context, instance_type,
|
||||
def _validate_and_build_base_options(self, context, flavor,
|
||||
image_uuid, name, description,
|
||||
availability_zone, extra,
|
||||
requested_networks, user_data,
|
||||
@ -85,16 +85,16 @@ class API(object):
|
||||
if user_data:
|
||||
l = len(user_data)
|
||||
if l > MAX_USERDATA_SIZE:
|
||||
raise exception.InstanceUserDataTooLarge(
|
||||
raise exception.ServerUserDataTooLarge(
|
||||
length=l, maxsize=MAX_USERDATA_SIZE)
|
||||
|
||||
try:
|
||||
base64utils.decode_as_bytes(user_data)
|
||||
except TypeError:
|
||||
raise exception.InstanceUserDataMalformed()
|
||||
raise exception.ServerUserDataMalformed()
|
||||
|
||||
# Note: max_count is the number of instances requested by the user,
|
||||
# max_network_count is the maximum number of instances taking into
|
||||
# Note: max_count is the number of servers requested by the user,
|
||||
# max_network_count is the maximum number of servers taking into
|
||||
# account any network quotas
|
||||
max_network_count = self._check_requested_networks(context,
|
||||
requested_networks,
|
||||
@ -113,7 +113,7 @@ class API(object):
|
||||
'user_id': context.user,
|
||||
'project_id': context.tenant,
|
||||
'power_state': states.NOSTATE,
|
||||
'instance_type_uuid': instance_type['uuid'],
|
||||
'flavor_uuid': flavor['uuid'],
|
||||
'name': name,
|
||||
'description': description,
|
||||
'locked': False,
|
||||
@ -123,15 +123,15 @@ class API(object):
|
||||
# return the validated options
|
||||
return base_options, max_network_count, key_pair
|
||||
|
||||
def _new_instance_name_from_template(self, uuid, name, index):
|
||||
"""Apply the template to instance name.
|
||||
def _new_server_name_from_template(self, uuid, name, index):
|
||||
"""Apply the template to server name.
|
||||
|
||||
Apply name template for multi-instance scenario.
|
||||
Apply name template for multi-server scenario.
|
||||
|
||||
:param uuid: The uuid of instance.
|
||||
:param name: The name of instance.
|
||||
:param index: The index of instance.
|
||||
:return: The new name of instance.
|
||||
:param uuid: The uuid of server.
|
||||
:param name: The name of server.
|
||||
:param index: The index of server.
|
||||
:return: The new name of server.
|
||||
"""
|
||||
params = {
|
||||
'uuid': uuid,
|
||||
@ -139,46 +139,46 @@ class API(object):
|
||||
'count': index + 1,
|
||||
}
|
||||
try:
|
||||
new_name = (CONF.api.multi_instance_name_template %
|
||||
new_name = (CONF.api.multi_server_name_template %
|
||||
params)
|
||||
except (KeyError, TypeError):
|
||||
LOG.exception('Failed to set instance name using '
|
||||
'multi_instance_name_template.')
|
||||
LOG.exception('Failed to set server name using '
|
||||
'multi_server_name_template.')
|
||||
new_name = name
|
||||
return new_name
|
||||
|
||||
def _populate_instance_names(self, instance, num_instances, index):
|
||||
"""Rename the instance name in multi-instance scenario.
|
||||
def _populate_server_names(self, server, num_servers, index):
|
||||
"""Rename the server name in multi-server scenario.
|
||||
|
||||
This is for rename instance in multi-instance scenario.
|
||||
This is for rename server in multi-server scenario.
|
||||
|
||||
:param instance: The instance object.
|
||||
:param num_instances: The number of instances
|
||||
:param index: the index of the instance
|
||||
:return: The instance object
|
||||
:param server: The server object.
|
||||
:param num_servers: The number of servers
|
||||
:param index: the index of the server
|
||||
:return: The server object
|
||||
"""
|
||||
if num_instances > 1:
|
||||
instance.name = self._new_instance_name_from_template(
|
||||
instance.uuid, instance.name, index)
|
||||
if num_servers > 1:
|
||||
server.name = self._new_server_name_from_template(
|
||||
server.uuid, server.name, index)
|
||||
|
||||
return instance
|
||||
return server
|
||||
|
||||
def _check_num_instances_quota(self, context, min_count, max_count):
|
||||
ins_resource = self.quota.resources['instances']
|
||||
def _check_num_servers_quota(self, context, min_count, max_count):
|
||||
ins_resource = self.quota.resources['servers']
|
||||
quotas = self.quota.get_quota_limit_and_usage(context,
|
||||
{'instances':
|
||||
{'servers':
|
||||
ins_resource},
|
||||
context.tenant)
|
||||
limit = quotas['instances']['limit']
|
||||
in_use = quotas['instances']['in_use']
|
||||
reserved = quotas['instances']['reserved']
|
||||
limit = quotas['servers']['limit']
|
||||
in_use = quotas['servers']['in_use']
|
||||
reserved = quotas['servers']['reserved']
|
||||
available_quota = limit - in_use - reserved
|
||||
if max_count <= available_quota:
|
||||
return max_count
|
||||
elif min_count <= available_quota and max_count > available_quota:
|
||||
return available_quota
|
||||
else:
|
||||
raise exception.OverQuota(overs='instances')
|
||||
raise exception.OverQuota(overs='servers')
|
||||
|
||||
def _decode_files(self, injected_files):
|
||||
"""Base64 decode the list of files to inject."""
|
||||
@ -196,45 +196,45 @@ class API(object):
|
||||
|
||||
return [_decode(f) for f in injected_files]
|
||||
|
||||
def _provision_instances(self, context, base_options,
|
||||
min_count, max_count):
|
||||
# Return num_instances according quota
|
||||
num_instances = self._check_num_instances_quota(
|
||||
def _provision_servers(self, context, base_options,
|
||||
min_count, max_count):
|
||||
# Return num_servers according quota
|
||||
num_servers = self._check_num_servers_quota(
|
||||
context, min_count, max_count)
|
||||
|
||||
# Create the instances reservations
|
||||
reserve_opts = {'instances': num_instances}
|
||||
# Create the servers reservations
|
||||
reserve_opts = {'servers': num_servers}
|
||||
reservations = self.quota.reserve(context, **reserve_opts)
|
||||
|
||||
LOG.debug("Going to run %s instances...", num_instances)
|
||||
LOG.debug("Going to run %s servers...", num_servers)
|
||||
|
||||
instances = []
|
||||
servers = []
|
||||
try:
|
||||
for num in range(num_instances):
|
||||
instance = objects.Instance(context=context)
|
||||
instance.update(base_options)
|
||||
instance.uuid = uuidutils.generate_uuid()
|
||||
# Refactor name of the instance.
|
||||
self._populate_instance_names(instance, num_instances, num)
|
||||
for num in range(num_servers):
|
||||
server = objects.Server(context=context)
|
||||
server.update(base_options)
|
||||
server.uuid = uuidutils.generate_uuid()
|
||||
# Refactor name of the server.
|
||||
self._populate_server_names(server, num_servers, num)
|
||||
|
||||
instance.create()
|
||||
instances.append(instance)
|
||||
server.create()
|
||||
servers.append(server)
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
try:
|
||||
for instance in instances:
|
||||
for server in servers:
|
||||
try:
|
||||
instance.destroy()
|
||||
server.destroy()
|
||||
except exception.ObjectActionError:
|
||||
pass
|
||||
finally:
|
||||
self.quota.rollback(context, reservations)
|
||||
|
||||
# Commit instances reservations
|
||||
# Commit servers reservations
|
||||
if reservations:
|
||||
self.quota.commit(context, reservations)
|
||||
|
||||
return instances
|
||||
return servers
|
||||
|
||||
def _check_requested_networks(self, context, requested_networks,
|
||||
max_count):
|
||||
@ -246,10 +246,10 @@ class API(object):
|
||||
return self.network_api.validate_networks(context, requested_networks,
|
||||
max_count)
|
||||
|
||||
def _create_instance(self, context, instance_type, image_uuid,
|
||||
name, description, availability_zone, extra,
|
||||
requested_networks, user_data, injected_files,
|
||||
key_name, min_count, max_count):
|
||||
def _create_server(self, context, flavor, image_uuid,
|
||||
name, description, availability_zone, extra,
|
||||
requested_networks, user_data, injected_files,
|
||||
key_name, min_count, max_count):
|
||||
"""Verify all the input parameters"""
|
||||
|
||||
# Verify the specified image exists
|
||||
@ -258,11 +258,11 @@ class API(object):
|
||||
|
||||
base_options, max_net_count, key_pair = \
|
||||
self._validate_and_build_base_options(
|
||||
context, instance_type, image_uuid, name, description,
|
||||
context, flavor, image_uuid, name, description,
|
||||
availability_zone, extra, requested_networks, user_data,
|
||||
key_name, max_count)
|
||||
|
||||
# max_net_count is the maximum number of instances requested by the
|
||||
# max_net_count is the maximum number of servers requested by the
|
||||
# user adjusted for any network quota constraints, including
|
||||
# consideration of connections to each requested network
|
||||
if max_net_count < min_count:
|
||||
@ -278,43 +278,43 @@ class API(object):
|
||||
# b64 decode the files to inject:
|
||||
decoded_files = self._decode_files(injected_files)
|
||||
|
||||
instances = self._provision_instances(context, base_options,
|
||||
min_count, max_count)
|
||||
servers = self._provision_servers(context, base_options,
|
||||
min_count, max_count)
|
||||
|
||||
if not availability_zone:
|
||||
availability_zone = CONF.engine.default_schedule_zone
|
||||
request_spec = {
|
||||
'instance_id': instances[0].uuid,
|
||||
'instance_properties': {
|
||||
'instance_type_uuid': instances[0].instance_type_uuid,
|
||||
'server_id': servers[0].uuid,
|
||||
'server_properties': {
|
||||
'flavor_uuid': servers[0].flavor_uuid,
|
||||
'networks': requested_networks,
|
||||
},
|
||||
'instance_type': dict(instance_type),
|
||||
'flavor': dict(flavor),
|
||||
'availability_zone': availability_zone,
|
||||
}
|
||||
|
||||
for instance in instances:
|
||||
self.engine_rpcapi.create_instance(context, instance,
|
||||
requested_networks,
|
||||
user_data,
|
||||
decoded_files,
|
||||
key_pair,
|
||||
request_spec,
|
||||
filter_properties=None)
|
||||
for server in servers:
|
||||
self.engine_rpcapi.create_server(context, server,
|
||||
requested_networks,
|
||||
user_data,
|
||||
decoded_files,
|
||||
key_pair,
|
||||
request_spec,
|
||||
filter_properties=None)
|
||||
|
||||
return instances
|
||||
return servers
|
||||
|
||||
def create(self, context, instance_type, image_uuid,
|
||||
def create(self, context, flavor, image_uuid,
|
||||
name=None, description=None, availability_zone=None,
|
||||
extra=None, requested_networks=None, user_data=None,
|
||||
injected_files=None, key_name=None, min_count=None,
|
||||
max_count=None):
|
||||
"""Provision instances
|
||||
"""Provision servers
|
||||
|
||||
Sending instance information to the engine and will handle
|
||||
Sending server information to the engine and will handle
|
||||
creating the DB entries.
|
||||
|
||||
Returns an instance object
|
||||
Returns a server object
|
||||
"""
|
||||
|
||||
# check availability zone
|
||||
@ -323,65 +323,65 @@ class API(object):
|
||||
if availability_zone not in azs['availability_zones']:
|
||||
raise exception.AZNotFound
|
||||
|
||||
return self._create_instance(context, instance_type,
|
||||
image_uuid, name, description,
|
||||
availability_zone, extra,
|
||||
requested_networks, user_data,
|
||||
injected_files, key_name,
|
||||
min_count, max_count)
|
||||
return self._create_server(context, flavor,
|
||||
image_uuid, name, description,
|
||||
availability_zone, extra,
|
||||
requested_networks, user_data,
|
||||
injected_files, key_name,
|
||||
min_count, max_count)
|
||||
|
||||
def _delete_instance(self, context, instance):
|
||||
def _delete_server(self, context, server):
|
||||
|
||||
fsm = utils.get_state_machine(start_state=instance.status)
|
||||
fsm = utils.get_state_machine(start_state=server.status)
|
||||
|
||||
try:
|
||||
utils.process_event(fsm, instance, event='delete')
|
||||
except exception.InstanceNotFound:
|
||||
LOG.debug("Instance is not found while deleting",
|
||||
instance=instance)
|
||||
utils.process_event(fsm, server, event='delete')
|
||||
except exception.ServerNotFound:
|
||||
LOG.debug("Server is not found while deleting",
|
||||
server=server)
|
||||
return
|
||||
reserve_opts = {'instances': -1}
|
||||
reserve_opts = {'servers': -1}
|
||||
reservations = self.quota.reserve(context, **reserve_opts)
|
||||
if reservations:
|
||||
self.quota.commit(context, reservations)
|
||||
self.engine_rpcapi.delete_instance(context, instance)
|
||||
self.engine_rpcapi.delete_server(context, server)
|
||||
|
||||
@check_instance_lock
|
||||
def delete(self, context, instance):
|
||||
"""Delete an instance."""
|
||||
LOG.debug("Going to try to delete instance %s", instance.uuid)
|
||||
self._delete_instance(context, instance)
|
||||
@check_server_lock
|
||||
def delete(self, context, server):
|
||||
"""Delete a server."""
|
||||
LOG.debug("Going to try to delete server %s", server.uuid)
|
||||
self._delete_server(context, server)
|
||||
|
||||
@check_instance_lock
|
||||
@check_instance_maintenance
|
||||
def power(self, context, instance, target):
|
||||
"""Set power state of an instance."""
|
||||
LOG.debug("Going to try to set instance power state to %s",
|
||||
target, instance=instance)
|
||||
fsm = utils.get_state_machine(start_state=instance.status)
|
||||
@check_server_lock
|
||||
@check_server_maintenance
|
||||
def power(self, context, server, target):
|
||||
"""Set power state of a server."""
|
||||
LOG.debug("Going to try to set server power state to %s",
|
||||
target, server=server)
|
||||
fsm = utils.get_state_machine(start_state=server.status)
|
||||
try:
|
||||
utils.process_event(fsm, instance,
|
||||
utils.process_event(fsm, server,
|
||||
event=states.POWER_ACTION_MAP[target])
|
||||
except exception.InstanceNotFound:
|
||||
LOG.debug("Instance is not found while setting power state",
|
||||
instance=instance)
|
||||
except exception.ServerNotFound:
|
||||
LOG.debug("Server is not found while setting power state",
|
||||
server=server)
|
||||
return
|
||||
|
||||
self.engine_rpcapi.set_power_state(context, instance, target)
|
||||
self.engine_rpcapi.set_power_state(context, server, target)
|
||||
|
||||
@check_instance_lock
|
||||
@check_instance_maintenance
|
||||
def rebuild(self, context, instance):
|
||||
"""Rebuild an instance."""
|
||||
fsm = utils.get_state_machine(start_state=instance.status)
|
||||
@check_server_lock
|
||||
@check_server_maintenance
|
||||
def rebuild(self, context, server):
|
||||
"""Rebuild a server."""
|
||||
fsm = utils.get_state_machine(start_state=server.status)
|
||||
try:
|
||||
utils.process_event(fsm, instance, event='rebuild')
|
||||
except exception.InstanceNotFound:
|
||||
LOG.debug("Instance is not found while rebuilding",
|
||||
instance=instance)
|
||||
utils.process_event(fsm, server, event='rebuild')
|
||||
except exception.ServerNotFound:
|
||||
LOG.debug("Server is not found while rebuilding",
|
||||
server=server)
|
||||
return
|
||||
|
||||
self.engine_rpcapi.rebuild_instance(context, instance)
|
||||
self.engine_rpcapi.rebuild_server(context, server)
|
||||
|
||||
def list_availability_zones(self, context):
|
||||
"""Get availability zone list."""
|
||||
@ -396,43 +396,43 @@ class API(object):
|
||||
|
||||
return {'availability_zones': list(azs)}
|
||||
|
||||
def lock(self, context, instance):
|
||||
"""Lock the given instance."""
|
||||
def lock(self, context, server):
|
||||
"""Lock the given server."""
|
||||
|
||||
is_owner = instance.project_id == context.project_id
|
||||
if instance.locked and is_owner:
|
||||
is_owner = server.project_id == context.project_id
|
||||
if server.locked and is_owner:
|
||||
return
|
||||
|
||||
LOG.debug('Locking', instance=instance)
|
||||
instance.locked = True
|
||||
instance.locked_by = 'owner' if is_owner else 'admin'
|
||||
instance.save()
|
||||
LOG.debug('Locking', server=server)
|
||||
server.locked = True
|
||||
server.locked_by = 'owner' if is_owner else 'admin'
|
||||
server.save()
|
||||
|
||||
def unlock(self, context, instance):
|
||||
"""Unlock the given instance."""
|
||||
def unlock(self, context, server):
|
||||
"""Unlock the given server."""
|
||||
|
||||
LOG.debug('Unlocking', instance=instance)
|
||||
instance.locked = False
|
||||
instance.locked_by = None
|
||||
instance.save()
|
||||
LOG.debug('Unlocking', server=server)
|
||||
server.locked = False
|
||||
server.locked_by = None
|
||||
server.save()
|
||||
|
||||
def is_expected_locked_by(self, context, instance):
|
||||
is_owner = instance.project_id == context.project_id
|
||||
def is_expected_locked_by(self, context, server):
|
||||
is_owner = server.project_id == context.project_id
|
||||
expect_locked_by = 'owner' if is_owner else 'admin'
|
||||
locked_by = instance.locked_by
|
||||
locked_by = server.locked_by
|
||||
if locked_by and locked_by != expect_locked_by:
|
||||
return False
|
||||
return True
|
||||
|
||||
def get_serial_console(self, context, instance):
|
||||
"""Get a url to an instance Console."""
|
||||
def get_serial_console(self, context, server):
|
||||
"""Get a url to a server Console."""
|
||||
connect_info = self.engine_rpcapi.get_serial_console(
|
||||
context, instance=instance)
|
||||
context, server=server)
|
||||
self.consoleauth_rpcapi.authorize_console(
|
||||
context,
|
||||
connect_info['token'], 'serial',
|
||||
connect_info['host'], connect_info['port'],
|
||||
connect_info['internal_access_path'], instance.uuid,
|
||||
connect_info['internal_access_path'], server.uuid,
|
||||
access_url=connect_info['access_url'])
|
||||
|
||||
return {'url': connect_info['access_url']}
|
||||
|
@ -52,10 +52,10 @@ class BaseEngineDriver(object):
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_power_state(self, context, instance_uuid):
|
||||
"""Return a node's power state by passing instance uuid.
|
||||
def get_power_state(self, context, server_uuid):
|
||||
"""Return a node's power state by passing server uuid.
|
||||
|
||||
:param instance_uuid: mogan instance uuid to get power state.
|
||||
:param server_uuid: moga server uuid to get power state.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
@ -84,40 +84,40 @@ class BaseEngineDriver(object):
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def unplug_vifs(self, context, instance):
|
||||
def unplug_vifs(self, context, server):
|
||||
"""Unplug network interfaces.
|
||||
|
||||
:param instance: the instance object.
|
||||
:param server: the server object.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def spawn(self, context, instance, configdrive_value):
|
||||
"""Create a new instance on the provision platform.
|
||||
def spawn(self, context, server, configdrive_value):
|
||||
"""Create a new server on the provision platform.
|
||||
|
||||
:param context: security context
|
||||
:param instance: mogan instance object.
|
||||
:param server: moga server object.
|
||||
:param configdrive_value: The configdrive value to be injected.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def destroy(self, context, instance):
|
||||
def destroy(self, context, server):
|
||||
"""Trigger node destroy process.
|
||||
|
||||
:param instance: the instance to destory.
|
||||
:param server: the server to destory.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def rebuild(self, context, instance):
|
||||
def rebuild(self, context, server):
|
||||
"""Trigger node deploy process.
|
||||
|
||||
:param instance: instance to rebuild.
|
||||
:param server: server to rebuild.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_serial_console_by_instance(self, context, instance):
|
||||
"""Get console info by instance.
|
||||
def get_serial_console_by_server(self, context, server):
|
||||
"""Get console info by server.
|
||||
|
||||
:param instance: instance to get its console info.
|
||||
:param server: server to get its console info.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
@ -130,7 +130,7 @@ def load_engine_driver(engine_driver):
|
||||
argument.
|
||||
|
||||
:param engine_driver: a engine driver name to override the config opt
|
||||
:returns: a EngineDriver instance
|
||||
:returns: a EngineDriver server
|
||||
"""
|
||||
|
||||
if not engine_driver:
|
||||
|
@ -53,7 +53,7 @@ def map_power_state(state):
|
||||
return states.NOSTATE
|
||||
|
||||
|
||||
def _log_ironic_polling(what, node, instance):
|
||||
def _log_ironic_polling(what, node, server):
|
||||
power_state = (None if node.power_state is None else
|
||||
'"%s"' % node.power_state)
|
||||
tgt_power_state = (None if node.target_power_state is None else
|
||||
@ -73,7 +73,7 @@ def _log_ironic_polling(what, node, instance):
|
||||
tgt_power_state=tgt_power_state,
|
||||
prov_state=prov_state,
|
||||
tgt_prov_state=tgt_prov_state),
|
||||
instance=instance)
|
||||
server=server)
|
||||
|
||||
|
||||
class IronicDriver(base_driver.BaseEngineDriver):
|
||||
@ -87,17 +87,17 @@ class IronicDriver(base_driver.BaseEngineDriver):
|
||||
return self.ironicclient.call('node.get', node_uuid,
|
||||
fields=_NODE_FIELDS)
|
||||
|
||||
def _validate_instance_and_node(self, instance):
|
||||
"""Get the node associated with the instance.
|
||||
def _validate_server_and_node(self, server):
|
||||
"""Get the node associated with the server.
|
||||
|
||||
Check with the Ironic service that this instance is associated with a
|
||||
Check with the Ironic service that this server is associated with a
|
||||
node, and return the node.
|
||||
"""
|
||||
try:
|
||||
return self.ironicclient.call('node.get_by_instance_uuid',
|
||||
instance.uuid, fields=_NODE_FIELDS)
|
||||
server.uuid, fields=_NODE_FIELDS)
|
||||
except ironic_exc.NotFound:
|
||||
raise exception.InstanceNotFound(instance=instance.uuid)
|
||||
raise exception.ServerNotFound(server=server.uuid)
|
||||
|
||||
def _parse_node_properties(self, node):
|
||||
"""Helper method to parse the node's properties."""
|
||||
@ -168,15 +168,15 @@ class IronicDriver(base_driver.BaseEngineDriver):
|
||||
}
|
||||
return dic
|
||||
|
||||
def _add_instance_info_to_node(self, node, instance):
|
||||
def _add_server_info_to_node(self, node, server):
|
||||
|
||||
patch = list()
|
||||
# Associate the node with an instance
|
||||
# Associate the node with a server
|
||||
patch.append({'path': '/instance_uuid', 'op': 'add',
|
||||
'value': instance.uuid})
|
||||
'value': server.uuid})
|
||||
# Add the required fields to deploy a node.
|
||||
patch.append({'path': '/instance_info/image_source', 'op': 'add',
|
||||
'value': instance.image_uuid})
|
||||
'value': server.image_uuid})
|
||||
# TODO(zhenguo) Add partition support
|
||||
patch.append({'path': '/instance_info/root_gb', 'op': 'add',
|
||||
'value': str(node.properties.get('local_gb', 0))})
|
||||
@ -185,68 +185,68 @@ class IronicDriver(base_driver.BaseEngineDriver):
|
||||
# FIXME(lucasagomes): The "retry_on_conflict" parameter was added
|
||||
# to basically causes the deployment to fail faster in case the
|
||||
# node picked by the scheduler is already associated with another
|
||||
# instance due bug #1341420.
|
||||
# server due bug #1341420.
|
||||
self.ironicclient.call('node.update', node.uuid, patch,
|
||||
retry_on_conflict=False)
|
||||
except ironic_exc.BadRequest:
|
||||
msg = (_("Failed to add deploy parameters on node %(node)s "
|
||||
"when provisioning the instance %(instance)s")
|
||||
% {'node': node.uuid, 'instance': instance.uuid})
|
||||
"when provisioning the server %(server)s")
|
||||
% {'node': node.uuid, 'server': server.uuid})
|
||||
LOG.error(msg)
|
||||
raise exception.InstanceDeployFailure(msg)
|
||||
raise exception.ServerDeployFailure(msg)
|
||||
|
||||
def _remove_instance_info_from_node(self, node, instance):
|
||||
def _remove_server_info_from_node(self, node, server):
|
||||
patch = [{'path': '/instance_info', 'op': 'remove'},
|
||||
{'path': '/instance_uuid', 'op': 'remove'}]
|
||||
try:
|
||||
self.ironicclient.call('node.update', node.uuid, patch)
|
||||
except ironic_exc.BadRequest as e:
|
||||
LOG.warning("Failed to remove deploy parameters from node "
|
||||
"%(node)s when unprovisioning the instance "
|
||||
"%(instance)s: %(reason)s",
|
||||
{'node': node.uuid, 'instance': instance.uuid,
|
||||
"%(node)s when unprovisioning the server "
|
||||
"%(server)s: %(reason)s",
|
||||
{'node': node.uuid, 'server': server.uuid,
|
||||
'reason': six.text_type(e)})
|
||||
|
||||
def _wait_for_active(self, instance):
|
||||
def _wait_for_active(self, server):
|
||||
"""Wait for the node to be marked as ACTIVE in Ironic."""
|
||||
instance.refresh()
|
||||
if instance.status in (states.DELETING, states.ERROR, states.DELETED):
|
||||
raise exception.InstanceDeployAborted(
|
||||
_("Instance %s provisioning was aborted") % instance.uuid)
|
||||
server.refresh()
|
||||
if server.status in (states.DELETING, states.ERROR, states.DELETED):
|
||||
raise exception.ServerDeployAborted(
|
||||
_("Server %s provisioning was aborted") % server.uuid)
|
||||
|
||||
node = self._validate_instance_and_node(instance)
|
||||
node = self._validate_server_and_node(server)
|
||||
if node.provision_state == ironic_states.ACTIVE:
|
||||
# job is done
|
||||
LOG.debug("Ironic node %(node)s is now ACTIVE",
|
||||
dict(node=node.uuid), instance=instance)
|
||||
dict(node=node.uuid), server=server)
|
||||
raise loopingcall.LoopingCallDone()
|
||||
|
||||
if node.target_provision_state in (ironic_states.DELETED,
|
||||
ironic_states.AVAILABLE):
|
||||
# ironic is trying to delete it now
|
||||
raise exception.InstanceNotFound(instance=instance.uuid)
|
||||
raise exception.ServerNotFound(server=server.uuid)
|
||||
|
||||
if node.provision_state in (ironic_states.NOSTATE,
|
||||
ironic_states.AVAILABLE):
|
||||
# ironic already deleted it
|
||||
raise exception.InstanceNotFound(instance=instance.uuid)
|
||||
raise exception.ServerNotFound(server=server.uuid)
|
||||
|
||||
if node.provision_state == ironic_states.DEPLOYFAIL:
|
||||
# ironic failed to deploy
|
||||
msg = (_("Failed to provision instance %(inst)s: %(reason)s")
|
||||
% {'inst': instance.uuid, 'reason': node.last_error})
|
||||
raise exception.InstanceDeployFailure(msg)
|
||||
msg = (_("Failed to provision server %(server)s: %(reason)s")
|
||||
% {'server': server.uuid, 'reason': node.last_error})
|
||||
raise exception.ServerDeployFailure(msg)
|
||||
|
||||
_log_ironic_polling('become ACTIVE', node, instance)
|
||||
_log_ironic_polling('become ACTIVE', node, server)
|
||||
|
||||
def _wait_for_power_state(self, instance, message):
|
||||
def _wait_for_power_state(self, server, message):
|
||||
"""Wait for the node to complete a power state change."""
|
||||
node = self._validate_instance_and_node(instance)
|
||||
node = self._validate_server_and_node(server)
|
||||
|
||||
if node.target_power_state == ironic_states.NOSTATE:
|
||||
raise loopingcall.LoopingCallDone()
|
||||
|
||||
_log_ironic_polling(message, node, instance)
|
||||
_log_ironic_polling(message, node, server)
|
||||
|
||||
def _get_hypervisor_type(self):
|
||||
"""Get hypervisor type."""
|
||||
@ -266,14 +266,14 @@ class IronicDriver(base_driver.BaseEngineDriver):
|
||||
'value': port_id}]
|
||||
self.ironicclient.call("port.update", ironic_port_id, patch)
|
||||
|
||||
def unplug_vifs(self, context, instance):
|
||||
LOG.debug("unplug: instance_uuid=%(uuid)s vif=%(instance_nics)s",
|
||||
{'uuid': instance.uuid,
|
||||
'instance_nics': str(instance.nics)})
|
||||
def unplug_vifs(self, context, server):
|
||||
LOG.debug("unplug: server_uuid=%(uuid)s vif=%(server_nics)s",
|
||||
{'uuid': server.uuid,
|
||||
'server_nics': str(server.nics)})
|
||||
patch = [{'op': 'remove',
|
||||
'path': '/extra/vif_port_id'}]
|
||||
|
||||
ports = self.get_ports_from_node(instance.node_uuid)
|
||||
ports = self.get_ports_from_node(server.node_uuid)
|
||||
|
||||
for port in ports:
|
||||
try:
|
||||
@ -283,42 +283,42 @@ class IronicDriver(base_driver.BaseEngineDriver):
|
||||
except client_e.BadRequest:
|
||||
pass
|
||||
|
||||
def _cleanup_deploy(self, context, node, instance):
|
||||
def _cleanup_deploy(self, context, node, server):
|
||||
# NOTE(liusheng): here we may need to stop firewall if we have
|
||||
# implemented in ironic like what Nova dose.
|
||||
self.unplug_vifs(context, instance)
|
||||
self.unplug_vifs(context, server)
|
||||
|
||||
def spawn(self, context, instance, configdrive_value):
|
||||
"""Deploy an instance.
|
||||
def spawn(self, context, server, configdrive_value):
|
||||
"""Deploy a server.
|
||||
|
||||
:param context: The security context.
|
||||
:param instance: The instance object.
|
||||
:param server: The server object.
|
||||
:param configdrive_value: The configdrive value to be injected.
|
||||
"""
|
||||
LOG.debug('Spawn called for instance', instance=instance)
|
||||
LOG.debug('Spawn called for server', server=server)
|
||||
|
||||
# The engine manager is meant to know the node uuid, so missing uuid
|
||||
# is a significant issue. It may mean we've been passed the wrong data.
|
||||
node_uuid = instance.node_uuid
|
||||
node_uuid = server.node_uuid
|
||||
if not node_uuid:
|
||||
raise ironic_exc.BadRequest(
|
||||
_("Ironic node uuid not supplied to "
|
||||
"driver for instance %s.") % instance.uuid)
|
||||
"driver for server %s.") % server.uuid)
|
||||
|
||||
# add instance info to node
|
||||
# add server info to node
|
||||
node = self._get_node(node_uuid)
|
||||
self._add_instance_info_to_node(node, instance)
|
||||
self._add_server_info_to_node(node, server)
|
||||
|
||||
# validate we are ready to do the deploy
|
||||
validate_chk = self.ironicclient.call("node.validate", node_uuid)
|
||||
if (not validate_chk.deploy.get('result')
|
||||
or not validate_chk.power.get('result')):
|
||||
# something is wrong. undo what we have done
|
||||
self._cleanup_deploy(context, node, instance)
|
||||
self._cleanup_deploy(context, node, server)
|
||||
raise exception.ValidationError(_(
|
||||
"Ironic node: %(id)s failed to validate."
|
||||
" (deploy: %(deploy)s, power: %(power)s)")
|
||||
% {'id': instance.node_uuid,
|
||||
% {'id': server.node_uuid,
|
||||
'deploy': validate_chk.deploy,
|
||||
'power': validate_chk.power})
|
||||
|
||||
@ -329,26 +329,26 @@ class IronicDriver(base_driver.BaseEngineDriver):
|
||||
configdrive=configdrive_value)
|
||||
except Exception as e:
|
||||
with excutils.save_and_reraise_exception():
|
||||
msg = ("Failed to request Ironic to provision instance "
|
||||
"%(inst)s: %(reason)s",
|
||||
{'inst': instance.uuid,
|
||||
msg = ("Failed to request Ironic to provision server "
|
||||
"%(server)s: %(reason)s",
|
||||
{'server': server.uuid,
|
||||
'reason': six.text_type(e)})
|
||||
LOG.error(msg)
|
||||
|
||||
timer = loopingcall.FixedIntervalLoopingCall(self._wait_for_active,
|
||||
instance)
|
||||
server)
|
||||
try:
|
||||
timer.start(interval=CONF.ironic.api_retry_interval).wait()
|
||||
LOG.info('Successfully provisioned Ironic node %s',
|
||||
node.uuid, instance=instance)
|
||||
node.uuid, server=server)
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error("Error deploying instance %(instance)s on "
|
||||
LOG.error("Error deploying server %(server)s on "
|
||||
"baremetal node %(node)s.",
|
||||
{'instance': instance.uuid,
|
||||
{'server': server.uuid,
|
||||
'node': node_uuid})
|
||||
|
||||
def _unprovision(self, instance, node):
|
||||
def _unprovision(self, server, node):
|
||||
"""This method is called from destroy() to unprovision
|
||||
already provisioned node after required checks.
|
||||
"""
|
||||
@ -361,7 +361,7 @@ class IronicDriver(base_driver.BaseEngineDriver):
|
||||
# TODO(deva): This exception should be added to
|
||||
# python-ironicclient and matched directly,
|
||||
# rather than via __name__.
|
||||
if getattr(e, '__name__', None) != 'InstanceDeployFailure':
|
||||
if getattr(e, '__name__', None) != 'ServerDeployFailure':
|
||||
raise
|
||||
|
||||
# using a dict because this is modified in the local method
|
||||
@ -369,10 +369,10 @@ class IronicDriver(base_driver.BaseEngineDriver):
|
||||
|
||||
def _wait_for_provision_state():
|
||||
try:
|
||||
node = self._validate_instance_and_node(instance)
|
||||
except exception.InstanceNotFound:
|
||||
LOG.debug("Instance already removed from Ironic",
|
||||
instance=instance)
|
||||
node = self._validate_server_and_node(server)
|
||||
except exception.ServerNotFound:
|
||||
LOG.debug("Server already removed from Ironic",
|
||||
server=server)
|
||||
raise loopingcall.LoopingCallDone()
|
||||
if node.provision_state in (ironic_states.NOSTATE,
|
||||
ironic_states.CLEANING,
|
||||
@ -381,15 +381,15 @@ class IronicDriver(base_driver.BaseEngineDriver):
|
||||
ironic_states.AVAILABLE):
|
||||
# From a user standpoint, the node is unprovisioned. If a node
|
||||
# gets into CLEANFAIL state, it must be fixed in Ironic, but we
|
||||
# can consider the instance unprovisioned.
|
||||
# can consider the server unprovisioned.
|
||||
LOG.debug("Ironic node %(node)s is in state %(state)s, "
|
||||
"instance is now unprovisioned.",
|
||||
"server is now unprovisioned.",
|
||||
dict(node=node.uuid, state=node.provision_state),
|
||||
instance=instance)
|
||||
server=server)
|
||||
raise loopingcall.LoopingCallDone()
|
||||
|
||||
if data['tries'] >= CONF.ironic.api_max_retries + 1:
|
||||
msg = (_("Error destroying the instance on node %(node)s. "
|
||||
msg = (_("Error destroying the server on node %(node)s. "
|
||||
"Provision state still '%(state)s'.")
|
||||
% {'state': node.provision_state,
|
||||
'node': node.uuid})
|
||||
@ -398,36 +398,36 @@ class IronicDriver(base_driver.BaseEngineDriver):
|
||||
else:
|
||||
data['tries'] += 1
|
||||
|
||||
_log_ironic_polling('unprovision', node, instance)
|
||||
_log_ironic_polling('unprovision', node, server)
|
||||
|
||||
# wait for the state transition to finish
|
||||
timer = loopingcall.FixedIntervalLoopingCall(_wait_for_provision_state)
|
||||
timer.start(interval=CONF.ironic.api_retry_interval).wait()
|
||||
|
||||
def destroy(self, context, instance):
|
||||
"""Destroy the specified instance, if it can be found.
|
||||
def destroy(self, context, server):
|
||||
"""Destroy the specified server, if it can be found.
|
||||
|
||||
:param context: The security context.
|
||||
:param instance: The instance object.
|
||||
:param server: The server object.
|
||||
"""
|
||||
LOG.debug('Destroy called for instance', instance=instance)
|
||||
LOG.debug('Destroy called for server', server=server)
|
||||
try:
|
||||
node = self._validate_instance_and_node(instance)
|
||||
except exception.InstanceNotFound:
|
||||
LOG.warning("Destroy called on non-existing instance %s.",
|
||||
instance.uuid)
|
||||
node = self._validate_server_and_node(server)
|
||||
except exception.ServerNotFound:
|
||||
LOG.warning("Destroy called on non-existing server %s.",
|
||||
server.uuid)
|
||||
return
|
||||
|
||||
if node.provision_state in _UNPROVISION_STATES:
|
||||
self._unprovision(instance, node)
|
||||
self._unprovision(server, node)
|
||||
else:
|
||||
# NOTE(hshiina): if spawn() fails before ironic starts
|
||||
# provisioning, instance information should be
|
||||
# provisioning, server information should be
|
||||
# removed from ironic node.
|
||||
self._remove_instance_info_from_node(node, instance)
|
||||
self._remove_server_info_from_node(node, server)
|
||||
|
||||
LOG.info('Successfully unprovisioned Ironic node %s',
|
||||
node.uuid, instance=instance)
|
||||
node.uuid, server=server)
|
||||
|
||||
def get_available_resources(self):
|
||||
"""Helper function to return the list of resources.
|
||||
@ -518,22 +518,22 @@ class IronicDriver(base_driver.BaseEngineDriver):
|
||||
node_list = []
|
||||
return node_list
|
||||
|
||||
def get_power_state(self, context, instance_uuid):
|
||||
def get_power_state(self, context, server_uuid):
|
||||
try:
|
||||
node = self.ironicclient.call('node.get_by_instance_uuid',
|
||||
instance_uuid,
|
||||
server_uuid,
|
||||
fields=('power_state',))
|
||||
return map_power_state(node.power_state)
|
||||
except client_e.NotFound:
|
||||
return map_power_state(ironic_states.NOSTATE)
|
||||
|
||||
def set_power_state(self, context, instance, state):
|
||||
"""Set power state on the specified instance.
|
||||
def set_power_state(self, context, server, state):
|
||||
"""Set power state on the specified server.
|
||||
|
||||
:param context: The security context.
|
||||
:param instance: The instance object.
|
||||
:param server: The server object.
|
||||
"""
|
||||
node = self._validate_instance_and_node(instance)
|
||||
node = self._validate_server_and_node(server)
|
||||
if state == "soft_off":
|
||||
self.ironicclient.call("node.set_power_state",
|
||||
node.uuid, "off", soft=True)
|
||||
@ -544,38 +544,38 @@ class IronicDriver(base_driver.BaseEngineDriver):
|
||||
self.ironicclient.call("node.set_power_state",
|
||||
node.uuid, state)
|
||||
timer = loopingcall.FixedIntervalLoopingCall(
|
||||
self._wait_for_power_state, instance, state)
|
||||
self._wait_for_power_state, server, state)
|
||||
timer.start(interval=CONF.ironic.api_retry_interval).wait()
|
||||
|
||||
def rebuild(self, context, instance):
|
||||
"""Rebuild/redeploy an instance.
|
||||
def rebuild(self, context, server):
|
||||
"""Rebuild/redeploy a server.
|
||||
|
||||
:param context: The security context.
|
||||
:param instance: The instance object.
|
||||
:param server: The server object.
|
||||
"""
|
||||
LOG.debug('Rebuild called for instance', instance=instance)
|
||||
LOG.debug('Rebuild called for server', server=server)
|
||||
|
||||
# trigger the node rebuild
|
||||
try:
|
||||
self.ironicclient.call("node.set_provision_state",
|
||||
instance.node_uuid,
|
||||
server.node_uuid,
|
||||
ironic_states.REBUILD)
|
||||
except (ironic_exc.InternalServerError,
|
||||
ironic_exc.BadRequest) as e:
|
||||
msg = (_("Failed to request Ironic to rebuild instance "
|
||||
"%(inst)s: %(reason)s") % {'inst': instance.uuid,
|
||||
'reason': six.text_type(e)})
|
||||
raise exception.InstanceDeployFailure(msg)
|
||||
msg = (_("Failed to request Ironic to rebuild server "
|
||||
"%(server)s: %(reason)s") % {'server': server.uuid,
|
||||
'reason': six.text_type(e)})
|
||||
raise exception.ServerDeployFailure(msg)
|
||||
|
||||
# Although the target provision state is REBUILD, it will actually go
|
||||
# to ACTIVE once the redeploy is finished.
|
||||
timer = loopingcall.FixedIntervalLoopingCall(self._wait_for_active,
|
||||
instance)
|
||||
server)
|
||||
timer.start(interval=CONF.ironic.api_retry_interval).wait()
|
||||
LOG.info('Instance was successfully rebuilt', instance=instance)
|
||||
LOG.info('Server was successfully rebuilt', server=server)
|
||||
|
||||
def get_serial_console_by_instance(self, context, instance):
|
||||
node = self._validate_instance_and_node(instance)
|
||||
def get_serial_console_by_server(self, context, server):
|
||||
node = self._validate_server_and_node(server)
|
||||
node_uuid = node.uuid
|
||||
|
||||
def _get_console():
|
||||
@ -585,8 +585,8 @@ class IronicDriver(base_driver.BaseEngineDriver):
|
||||
except (ironic_exc.InternalServerError,
|
||||
ironic_exc.BadRequest) as e:
|
||||
LOG.error('Failed to acquire console information for '
|
||||
'node %(inst)s: %(reason)s',
|
||||
{'inst': node_uuid,
|
||||
'node %(server)s: %(reason)s',
|
||||
{'server': node_uuid,
|
||||
'reason': e})
|
||||
raise exception.ConsoleNotAvailable()
|
||||
|
||||
@ -596,7 +596,7 @@ class IronicDriver(base_driver.BaseEngineDriver):
|
||||
if console['console_enabled'] == state:
|
||||
raise loopingcall.LoopingCallDone(retvalue=console)
|
||||
|
||||
_log_ironic_polling('set console mode', node, instance)
|
||||
_log_ironic_polling('set console mode', node, server)
|
||||
|
||||
# Return False to start backing off
|
||||
return False
|
||||
|
@ -58,7 +58,7 @@ This state is replacing the NOSTATE state used prior to Kilo.
|
||||
"""
|
||||
|
||||
ACTIVE = 'active'
|
||||
""" Node is successfully deployed and associated with an instance. """
|
||||
""" Node is successfully deployed and associated with a server. """
|
||||
|
||||
DEPLOYWAIT = 'wait call-back'
|
||||
""" Node is waiting to be deployed.
|
||||
|
@ -54,7 +54,7 @@ class BaseEngineManager(periodic_task.PeriodicTasks):
|
||||
raise RuntimeError(_('Attempt to start an already running '
|
||||
'engine manager'))
|
||||
|
||||
self.dbapi = dbapi.get_instance()
|
||||
self.dbapi = dbapi.get_server()
|
||||
|
||||
self._worker_pool = greenpool.GreenPool(
|
||||
size=CONF.engine.workers_pool_size)
|
||||
|
@ -35,12 +35,12 @@ CONFIGDRIVESIZE_BYTES = 64 * units.Mi
|
||||
class ConfigDriveBuilder(object):
|
||||
"""Build config drives, optionally as a context manager."""
|
||||
|
||||
def __init__(self, instance_md=None):
|
||||
def __init__(self, server_md=None):
|
||||
self.imagefile = None
|
||||
self.mdfiles = []
|
||||
|
||||
if instance_md is not None:
|
||||
self.add_instance_metadata(instance_md)
|
||||
if server_md is not None:
|
||||
self.add_server_metadata(server_md)
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
@ -64,8 +64,8 @@ class ConfigDriveBuilder(object):
|
||||
data = data.encode('utf-8')
|
||||
f.write(data)
|
||||
|
||||
def add_instance_metadata(self, instance_md):
|
||||
for (path, data) in instance_md.metadata_for_config_drive():
|
||||
def add_server_metadata(self, server_md):
|
||||
for (path, data) in server_md.metadata_for_config_drive():
|
||||
self.mdfiles.append((path, data))
|
||||
|
||||
def _write_md_files(self, basedir):
|
||||
|
@ -32,36 +32,36 @@ from mogan.common import flow_utils
|
||||
from mogan.common.i18n import _
|
||||
from mogan.common import utils
|
||||
from mogan.engine import configdrive
|
||||
from mogan.engine import metadata as instance_metadata
|
||||
from mogan.engine import metadata as server_metadata
|
||||
from mogan import objects
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
ACTION = 'instance:create'
|
||||
ACTION = 'server:create'
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
class OnFailureRescheduleTask(flow_utils.MoganTask):
|
||||
"""Triggers a rescheduling request to be sent when reverting occurs.
|
||||
|
||||
If rescheduling doesn't occur this task errors out the instance.
|
||||
If rescheduling doesn't occur this task errors out the server.
|
||||
"""
|
||||
|
||||
def __init__(self, engine_rpcapi):
|
||||
requires = ['filter_properties', 'request_spec', 'instance',
|
||||
requires = ['filter_properties', 'request_spec', 'server',
|
||||
'requested_networks', 'user_data', 'injected_files',
|
||||
'key_pair', 'context']
|
||||
super(OnFailureRescheduleTask, self).__init__(addons=[ACTION],
|
||||
requires=requires)
|
||||
self.engine_rpcapi = engine_rpcapi
|
||||
# These exception types will trigger the instance to be set into error
|
||||
# These exception types will trigger the server to be set into error
|
||||
# status rather than being rescheduled.
|
||||
self.no_reschedule_exc_types = [
|
||||
# The instance has been removed from the database, that can not
|
||||
# The server has been removed from the database, that can not
|
||||
# be fixed by rescheduling.
|
||||
exception.InstanceNotFound,
|
||||
exception.InstanceDeployAborted,
|
||||
exception.ServerNotFound,
|
||||
exception.ServerDeployAborted,
|
||||
exception.NetworkError,
|
||||
]
|
||||
|
||||
@ -69,11 +69,11 @@ class OnFailureRescheduleTask(flow_utils.MoganTask):
|
||||
pass
|
||||
|
||||
def _reschedule(self, context, cause, request_spec, filter_properties,
|
||||
instance, requested_networks, user_data, injected_files,
|
||||
server, requested_networks, user_data, injected_files,
|
||||
key_pair):
|
||||
"""Actions that happen during the rescheduling attempt occur here."""
|
||||
|
||||
create_instance = self.engine_rpcapi.create_instance
|
||||
create_server = self.engine_rpcapi.create_server
|
||||
if not filter_properties:
|
||||
filter_properties = {}
|
||||
if 'retry' not in filter_properties:
|
||||
@ -82,10 +82,10 @@ class OnFailureRescheduleTask(flow_utils.MoganTask):
|
||||
retry_info = filter_properties['retry']
|
||||
num_attempts = retry_info.get('num_attempts', 0)
|
||||
|
||||
LOG.debug("Instance %(instance_id)s: re-scheduling %(method)s "
|
||||
LOG.debug("Server %(server_id)s: re-scheduling %(method)s "
|
||||
"attempt %(num)d due to %(reason)s",
|
||||
{'instance_id': instance.uuid,
|
||||
'method': utils.make_pretty_name(create_instance),
|
||||
{'server_id': server.uuid,
|
||||
'method': utils.make_pretty_name(create_server),
|
||||
'num': num_attempts,
|
||||
'reason': cause.exception_str})
|
||||
|
||||
@ -93,55 +93,55 @@ class OnFailureRescheduleTask(flow_utils.MoganTask):
|
||||
# Stringify to avoid circular ref problem in json serialization
|
||||
retry_info['exc'] = traceback.format_exception(*cause.exc_info)
|
||||
|
||||
return create_instance(context, instance, requested_networks,
|
||||
user_data=user_data,
|
||||
injected_files=injected_files,
|
||||
key_pair=key_pair,
|
||||
request_spec=request_spec,
|
||||
filter_properties=filter_properties)
|
||||
return create_server(context, server, requested_networks,
|
||||
user_data=user_data,
|
||||
injected_files=injected_files,
|
||||
key_pair=key_pair,
|
||||
request_spec=request_spec,
|
||||
filter_properties=filter_properties)
|
||||
|
||||
def revert(self, context, result, flow_failures, instance, **kwargs):
|
||||
# Cleanup associated instance node uuid
|
||||
if instance.node_uuid:
|
||||
def revert(self, context, result, flow_failures, server, **kwargs):
|
||||
# Cleanup associated server node uuid
|
||||
if server.node_uuid:
|
||||
# If the compute node is still in DB, release it.
|
||||
try:
|
||||
cn = objects.ComputeNode.get(context, instance.node_uuid)
|
||||
cn = objects.ComputeNode.get(context, server.node_uuid)
|
||||
except exception.ComputeNodeNotFound:
|
||||
pass
|
||||
else:
|
||||
cn.destroy()
|
||||
instance.node_uuid = None
|
||||
instance.save()
|
||||
server.node_uuid = None
|
||||
server.save()
|
||||
|
||||
# Check if we have a cause which can tell us not to reschedule and
|
||||
# set the instance's status to error.
|
||||
# set the server's status to error.
|
||||
for failure in flow_failures.values():
|
||||
if failure.check(*self.no_reschedule_exc_types):
|
||||
LOG.error("Instance %s: create failed and no reschedule.",
|
||||
instance.uuid)
|
||||
LOG.error("Server %s: create failed and no reschedule.",
|
||||
server.uuid)
|
||||
return False
|
||||
|
||||
cause = list(flow_failures.values())[0]
|
||||
try:
|
||||
self._reschedule(context, cause, instance=instance, **kwargs)
|
||||
self._reschedule(context, cause, server=server, **kwargs)
|
||||
return True
|
||||
except exception.MoganException:
|
||||
LOG.exception("Instance %s: rescheduling failed",
|
||||
instance.uuid)
|
||||
LOG.exception("Server %s: rescheduling failed",
|
||||
server.uuid)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
class BuildNetworkTask(flow_utils.MoganTask):
|
||||
"""Build network for the instance."""
|
||||
"""Build network for the server."""
|
||||
|
||||
def __init__(self, manager):
|
||||
requires = ['instance', 'requested_networks', 'ports', 'context']
|
||||
requires = ['server', 'requested_networks', 'ports', 'context']
|
||||
super(BuildNetworkTask, self).__init__(addons=[ACTION],
|
||||
requires=requires)
|
||||
self.manager = manager
|
||||
|
||||
def _build_networks(self, context, instance, requested_networks, ports):
|
||||
def _build_networks(self, context, server, requested_networks, ports):
|
||||
|
||||
# TODO(zhenguo): This seems not needed as our scheduler has already
|
||||
# guaranteed this.
|
||||
@ -150,18 +150,18 @@ class BuildNetworkTask(flow_utils.MoganTask):
|
||||
"Ironic node: %(id)s virtual to physical interface count"
|
||||
" mismatch"
|
||||
" (Vif count: %(vif_count)d, Pif count: %(pif_count)d)")
|
||||
% {'id': instance.node_uuid,
|
||||
% {'id': server.node_uuid,
|
||||
'vif_count': len(requested_networks),
|
||||
'pif_count': len(ports)})
|
||||
|
||||
nics_obj = objects.InstanceNics(context)
|
||||
nics_obj = objects.ServerNics(context)
|
||||
for vif in requested_networks:
|
||||
for pif in ports:
|
||||
# Match the specified port type with physical interface type
|
||||
if vif.get('port_type', 'None') == pif.port_type:
|
||||
try:
|
||||
port = self.manager.network_api.create_port(
|
||||
context, vif['net_id'], pif.address, instance.uuid)
|
||||
context, vif['net_id'], pif.address, server.uuid)
|
||||
port_dict = port['port']
|
||||
|
||||
self.manager.driver.plug_vif(pif.port_uuid,
|
||||
@ -171,61 +171,61 @@ class BuildNetworkTask(flow_utils.MoganTask):
|
||||
'mac_address': port_dict['mac_address'],
|
||||
'fixed_ips': port_dict['fixed_ips'],
|
||||
'port_type': vif.get('port_type'),
|
||||
'instance_uuid': instance.uuid}
|
||||
nics_obj.objects.append(objects.InstanceNic(
|
||||
'server_uuid': server.uuid}
|
||||
nics_obj.objects.append(objects.ServerNic(
|
||||
context, **nic_dict))
|
||||
|
||||
except Exception:
|
||||
# Set nics here, so we can clean up the
|
||||
# created networks during reverting.
|
||||
instance.nics = nics_obj
|
||||
LOG.error("Instance %s: create network failed",
|
||||
instance.uuid)
|
||||
server.nics = nics_obj
|
||||
LOG.error("Server %s: create network failed",
|
||||
server.uuid)
|
||||
raise exception.NetworkError(_(
|
||||
"Build network for instance failed."))
|
||||
"Build network for server failed."))
|
||||
return nics_obj
|
||||
|
||||
def execute(self, context, instance, requested_networks, ports):
|
||||
instance_nics = self._build_networks(
|
||||
def execute(self, context, server, requested_networks, ports):
|
||||
server_nics = self._build_networks(
|
||||
context,
|
||||
instance,
|
||||
server,
|
||||
requested_networks,
|
||||
ports)
|
||||
|
||||
instance.nics = instance_nics
|
||||
instance.save()
|
||||
server.nics = server_nics
|
||||
server.save()
|
||||
|
||||
def revert(self, context, result, flow_failures, instance, **kwargs):
|
||||
def revert(self, context, result, flow_failures, server, **kwargs):
|
||||
# Check if we need to clean up networks.
|
||||
if instance.nics:
|
||||
LOG.debug("Instance %s: cleaning up node networks",
|
||||
instance.uuid)
|
||||
self.manager.destroy_networks(context, instance)
|
||||
if server.nics:
|
||||
LOG.debug("Server %s: cleaning up node networks",
|
||||
server.uuid)
|
||||
self.manager.destroy_networks(context, server)
|
||||
# Unset nics here as we have destroyed it.
|
||||
instance.nics = None
|
||||
server.nics = None
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
class GenerateConfigDriveTask(flow_utils.MoganTask):
|
||||
"""Generate ConfigDrive value the instance."""
|
||||
"""Generate ConfigDrive value the server."""
|
||||
|
||||
def __init__(self):
|
||||
requires = ['instance', 'user_data', 'injected_files', 'key_pair',
|
||||
requires = ['server', 'user_data', 'injected_files', 'key_pair',
|
||||
'configdrive', 'context']
|
||||
super(GenerateConfigDriveTask, self).__init__(addons=[ACTION],
|
||||
requires=requires)
|
||||
|
||||
def _generate_configdrive(self, context, instance, user_data=None,
|
||||
def _generate_configdrive(self, context, server, user_data=None,
|
||||
files=None, key_pair=None):
|
||||
"""Generate a config drive."""
|
||||
|
||||
i_meta = instance_metadata.InstanceMetadata(
|
||||
instance, content=files, user_data=user_data, key_pair=key_pair)
|
||||
i_meta = server_metadata.ServerMetadata(
|
||||
server, content=files, user_data=user_data, key_pair=key_pair)
|
||||
|
||||
with tempfile.NamedTemporaryFile() as uncompressed:
|
||||
with configdrive.ConfigDriveBuilder(instance_md=i_meta) as cdb:
|
||||
with configdrive.ConfigDriveBuilder(server_md=i_meta) as cdb:
|
||||
cdb.make_drive(uncompressed.name)
|
||||
|
||||
with tempfile.NamedTemporaryFile() as compressed:
|
||||
@ -238,55 +238,55 @@ class GenerateConfigDriveTask(flow_utils.MoganTask):
|
||||
compressed.seek(0)
|
||||
return base64.b64encode(compressed.read())
|
||||
|
||||
def execute(self, context, instance, user_data, injected_files, key_pair,
|
||||
def execute(self, context, server, user_data, injected_files, key_pair,
|
||||
configdrive):
|
||||
|
||||
try:
|
||||
configdrive['value'] = self._generate_configdrive(
|
||||
context, instance, user_data=user_data, files=injected_files,
|
||||
context, server, user_data=user_data, files=injected_files,
|
||||
key_pair=key_pair)
|
||||
except Exception as e:
|
||||
with excutils.save_and_reraise_exception():
|
||||
msg = ("Failed to build configdrive: %s" %
|
||||
six.text_type(e))
|
||||
LOG.error(msg, instance=instance)
|
||||
LOG.error(msg, server=server)
|
||||
|
||||
LOG.info("Config drive for instance %(instance)s created.",
|
||||
{'instance': instance.uuid})
|
||||
LOG.info("Config drive for server %(server)s created.",
|
||||
{'server': server.uuid})
|
||||
|
||||
|
||||
class CreateInstanceTask(flow_utils.MoganTask):
|
||||
"""Build and deploy the instance."""
|
||||
class CreateServerTask(flow_utils.MoganTask):
|
||||
"""Build and deploy the server."""
|
||||
|
||||
def __init__(self, driver):
|
||||
requires = ['instance', 'configdrive', 'context']
|
||||
super(CreateInstanceTask, self).__init__(addons=[ACTION],
|
||||
requires=requires)
|
||||
requires = ['server', 'configdrive', 'context']
|
||||
super(CreateServerTask, self).__init__(addons=[ACTION],
|
||||
requires=requires)
|
||||
self.driver = driver
|
||||
# These exception types will trigger the instance to be cleaned.
|
||||
self.instance_cleaned_exc_types = [
|
||||
exception.InstanceDeployFailure,
|
||||
# These exception types will trigger the server to be cleaned.
|
||||
self.server_cleaned_exc_types = [
|
||||
exception.ServerDeployFailure,
|
||||
loopingcall.LoopingCallTimeOut,
|
||||
]
|
||||
|
||||
def execute(self, context, instance, configdrive):
|
||||
def execute(self, context, server, configdrive):
|
||||
configdrive_value = configdrive.get('value')
|
||||
self.driver.spawn(context, instance, configdrive_value)
|
||||
self.driver.spawn(context, server, configdrive_value)
|
||||
LOG.info('Successfully provisioned Ironic node %s',
|
||||
instance.node_uuid)
|
||||
server.node_uuid)
|
||||
|
||||
def revert(self, context, result, flow_failures, instance, **kwargs):
|
||||
# Check if we have a cause which need to clean up instance.
|
||||
def revert(self, context, result, flow_failures, server, **kwargs):
|
||||
# Check if we have a cause which need to clean up server.
|
||||
for failure in flow_failures.values():
|
||||
if failure.check(*self.instance_cleaned_exc_types):
|
||||
LOG.debug("Instance %s: destroy ironic node", instance.uuid)
|
||||
self.driver.destroy(context, instance)
|
||||
if failure.check(*self.server_cleaned_exc_types):
|
||||
LOG.debug("Server %s: destroy ironic node", server.uuid)
|
||||
self.driver.destroy(context, server)
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def get_flow(context, manager, instance, requested_networks, user_data,
|
||||
def get_flow(context, manager, server, requested_networks, user_data,
|
||||
injected_files, key_pair, ports, request_spec,
|
||||
filter_properties):
|
||||
|
||||
@ -294,14 +294,14 @@ def get_flow(context, manager, instance, requested_networks, user_data,
|
||||
|
||||
This flow will do the following:
|
||||
|
||||
1. Build networks for the instance and set port id back to baremetal port
|
||||
2. Generate configdrive value for instance.
|
||||
1. Build networks for the server and set port id back to baremetal port
|
||||
2. Generate configdrive value for server.
|
||||
3. Do node deploy and handle errors.
|
||||
4. Reschedule if the tasks are on failure.
|
||||
"""
|
||||
|
||||
flow_name = ACTION.replace(":", "_") + "_manager"
|
||||
instance_flow = linear_flow.Flow(flow_name)
|
||||
server_flow = linear_flow.Flow(flow_name)
|
||||
|
||||
# This injects the initial starting flow values into the workflow so that
|
||||
# the dependency order of the tasks provides/requires can be correctly
|
||||
@ -310,7 +310,7 @@ def get_flow(context, manager, instance, requested_networks, user_data,
|
||||
'context': context,
|
||||
'filter_properties': filter_properties,
|
||||
'request_spec': request_spec,
|
||||
'instance': instance,
|
||||
'server': server,
|
||||
'requested_networks': requested_networks,
|
||||
'user_data': user_data,
|
||||
'injected_files': injected_files,
|
||||
@ -319,10 +319,10 @@ def get_flow(context, manager, instance, requested_networks, user_data,
|
||||
'configdrive': {}
|
||||
}
|
||||
|
||||
instance_flow.add(OnFailureRescheduleTask(manager.engine_rpcapi),
|
||||
BuildNetworkTask(manager),
|
||||
GenerateConfigDriveTask(),
|
||||
CreateInstanceTask(manager.driver))
|
||||
server_flow.add(OnFailureRescheduleTask(manager.engine_rpcapi),
|
||||
BuildNetworkTask(manager),
|
||||
GenerateConfigDriveTask(),
|
||||
CreateServerTask(manager.driver))
|
||||
|
||||
# Now load (but do not run) the flow using the provided initial data.
|
||||
return taskflow.engines.load(instance_flow, store=create_what)
|
||||
return taskflow.engines.load(server_flow, store=create_what)
|
@ -31,7 +31,7 @@ from mogan.common import states
|
||||
from mogan.common import utils
|
||||
from mogan.conf import CONF
|
||||
from mogan.engine import base_manager
|
||||
from mogan.engine.flows import create_instance
|
||||
from mogan.engine.flows import create_server
|
||||
from mogan.notifications import base as notifications
|
||||
from mogan import objects
|
||||
from mogan.objects import fields
|
||||
@ -40,27 +40,27 @@ from mogan.objects import quota
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
@utils.expects_func_args('instance')
|
||||
def wrap_instance_fault(function):
|
||||
"""Wraps a method to catch exceptions related to instances.
|
||||
@utils.expects_func_args('server')
|
||||
def wrap_server_fault(function):
|
||||
"""Wraps a method to catch exceptions related to servers.
|
||||
|
||||
This decorator wraps a method to catch any exceptions having to do with
|
||||
an instance that may get thrown. It then logs an instance fault in the db.
|
||||
a server that may get thrown. It then logs a server fault in the db.
|
||||
"""
|
||||
|
||||
@functools.wraps(function)
|
||||
def decorated_function(self, context, *args, **kwargs):
|
||||
try:
|
||||
return function(self, context, *args, **kwargs)
|
||||
except exception.InstanceNotFound:
|
||||
except exception.ServerNotFound:
|
||||
raise
|
||||
except Exception as e:
|
||||
kwargs.update(dict(zip(function.__code__.co_varnames[2:], args)))
|
||||
|
||||
with excutils.save_and_reraise_exception():
|
||||
utils.add_instance_fault_from_exc(context,
|
||||
kwargs['instance'],
|
||||
e, sys.exc_info())
|
||||
utils.add_server_fault_from_exc(context,
|
||||
kwargs['server'],
|
||||
e, sys.exc_info())
|
||||
|
||||
return decorated_function
|
||||
|
||||
@ -75,7 +75,7 @@ class EngineManager(base_manager.BaseEngineManager):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(EngineManager, self).__init__(*args, **kwargs)
|
||||
self.quota = quota.Quota()
|
||||
self.quota.register_resource(objects.quota.InstanceResource())
|
||||
self.quota.register_resource(objects.quota.ServerResource())
|
||||
|
||||
def _get_compute_port(self, context, port_uuid):
|
||||
"""Gets compute port by the uuid."""
|
||||
@ -189,93 +189,93 @@ class EngineManager(base_manager.BaseEngineManager):
|
||||
if node.target_power_state is None}
|
||||
|
||||
if not node_dict:
|
||||
LOG.warning("While synchronizing instance power states, "
|
||||
"found none instance with stable power state "
|
||||
LOG.warning("While synchronizing server power states, "
|
||||
"found none server with stable power state "
|
||||
"on the hypervisor.")
|
||||
return
|
||||
|
||||
def _sync(db_instance, node_power_state):
|
||||
def _sync(db_server, node_power_state):
|
||||
# This must be synchronized as we query state from two separate
|
||||
# sources, the driver (ironic) and the database. They are set
|
||||
# (in stop_instance) and read, in sync.
|
||||
@utils.synchronized(db_instance.uuid)
|
||||
def sync_instance_power_state():
|
||||
self._sync_instance_power_state(context, db_instance,
|
||||
node_power_state)
|
||||
# (in stop_server) and read, in sync.
|
||||
@utils.synchronized(db_server.uuid)
|
||||
def sync_server_power_state():
|
||||
self._sync_server_power_state(context, db_server,
|
||||
node_power_state)
|
||||
|
||||
try:
|
||||
sync_instance_power_state()
|
||||
sync_server_power_state()
|
||||
except Exception:
|
||||
LOG.exception("Periodic sync_power_state task had an "
|
||||
"error while processing an instance.",
|
||||
instance=db_instance)
|
||||
"error while processing a server.",
|
||||
server=db_server)
|
||||
|
||||
self._syncs_in_progress.pop(db_instance.uuid)
|
||||
self._syncs_in_progress.pop(db_server.uuid)
|
||||
|
||||
db_instances = objects.Instance.list(context)
|
||||
for db_instance in db_instances:
|
||||
# process syncs asynchronously - don't want instance locking to
|
||||
db_servers = objects.Server.list(context)
|
||||
for db_server in db_servers:
|
||||
# process syncs asynchronously - don't want server locking to
|
||||
# block entire periodic task thread
|
||||
uuid = db_instance.uuid
|
||||
uuid = db_server.uuid
|
||||
if uuid in self._syncs_in_progress:
|
||||
LOG.debug('Sync power state already in progress for %s', uuid)
|
||||
continue
|
||||
|
||||
if db_instance.status not in (states.ACTIVE, states.STOPPED):
|
||||
if db_instance.status in states.UNSTABLE_STATES:
|
||||
LOG.info("During sync_power_state the instance has a "
|
||||
if db_server.status not in (states.ACTIVE, states.STOPPED):
|
||||
if db_server.status in states.UNSTABLE_STATES:
|
||||
LOG.info("During sync_power_state the server has a "
|
||||
"pending task (%(task)s). Skip.",
|
||||
{'task': db_instance.status},
|
||||
instance=db_instance)
|
||||
{'task': db_server.status},
|
||||
server=db_server)
|
||||
continue
|
||||
|
||||
if uuid not in node_dict:
|
||||
continue
|
||||
|
||||
node_power_state = node_dict[uuid].power_state
|
||||
if db_instance.power_state != node_power_state:
|
||||
if db_server.power_state != node_power_state:
|
||||
LOG.debug('Triggering sync for uuid %s', uuid)
|
||||
self._syncs_in_progress[uuid] = True
|
||||
self._sync_power_pool.spawn_n(_sync, db_instance,
|
||||
self._sync_power_pool.spawn_n(_sync, db_server,
|
||||
node_power_state)
|
||||
|
||||
def _sync_instance_power_state(self, context, db_instance,
|
||||
node_power_state):
|
||||
"""Align instance power state between the database and hypervisor.
|
||||
def _sync_server_power_state(self, context, db_server,
|
||||
node_power_state):
|
||||
"""Align server power state between the database and hypervisor.
|
||||
|
||||
If the instance is not found on the hypervisor, but is in the database,
|
||||
then a stop() API will be called on the instance.
|
||||
If the server is not found on the hypervisor, but is in the database,
|
||||
then a stop() API will be called on the server.
|
||||
"""
|
||||
|
||||
# We re-query the DB to get the latest instance info to minimize
|
||||
# We re-query the DB to get the latest server info to minimize
|
||||
# (not eliminate) race condition.
|
||||
db_instance.refresh()
|
||||
db_power_state = db_instance.power_state
|
||||
db_server.refresh()
|
||||
db_power_state = db_server.power_state
|
||||
|
||||
if db_instance.status not in (states.ACTIVE, states.STOPPED):
|
||||
if db_server.status not in (states.ACTIVE, states.STOPPED):
|
||||
# on the receiving end of mogan-engine, it could happen
|
||||
# that the DB instance already report the new resident
|
||||
# that the DB server already report the new resident
|
||||
# but the actual BM has not showed up on the hypervisor
|
||||
# yet. In this case, let's allow the loop to continue
|
||||
# and run the state sync in a later round
|
||||
LOG.info("During sync_power_state the instance has a "
|
||||
LOG.info("During sync_power_state the server has a "
|
||||
"pending task (%(task)s). Skip.",
|
||||
{'task': db_instance.task_state},
|
||||
instance=db_instance)
|
||||
{'task': db_server.task_state},
|
||||
server=db_server)
|
||||
return
|
||||
|
||||
if node_power_state != db_power_state:
|
||||
LOG.info('During _sync_instance_power_state the DB '
|
||||
LOG.info('During _sync_server_power_state the DB '
|
||||
'power_state (%(db_power_state)s) does not match '
|
||||
'the node_power_state from the hypervisor '
|
||||
'(%(node_power_state)s). Updating power_state in the '
|
||||
'DB to match the hypervisor.',
|
||||
{'db_power_state': db_power_state,
|
||||
'node_power_state': node_power_state},
|
||||
instance=db_instance)
|
||||
server=db_server)
|
||||
# power_state is always updated from hypervisor to db
|
||||
db_instance.power_state = node_power_state
|
||||
db_instance.save()
|
||||
db_server.power_state = node_power_state
|
||||
db_server.save()
|
||||
|
||||
@periodic_task.periodic_task(spacing=CONF.engine.sync_maintenance_interval,
|
||||
run_immediately=True)
|
||||
@ -291,26 +291,26 @@ class EngineManager(base_manager.BaseEngineManager):
|
||||
# Just retrun if we fail to get nodes maintenance state.
|
||||
return
|
||||
|
||||
node_dict = {node.instance_uuid: node for node in nodes}
|
||||
node_dict = {node.server_uuid: node for node in nodes}
|
||||
|
||||
if not node_dict:
|
||||
LOG.warning("While synchronizing instance maintenance states, "
|
||||
"found none node with instance associated on the "
|
||||
LOG.warning("While synchronizing server maintenance states, "
|
||||
"found none node with server associated on the "
|
||||
"hypervisor.")
|
||||
return
|
||||
|
||||
db_instances = objects.Instance.list(context)
|
||||
for instance in db_instances:
|
||||
uuid = instance.uuid
|
||||
db_servers = objects.Server.list(context)
|
||||
for server in db_servers:
|
||||
uuid = server.uuid
|
||||
|
||||
# If instance in unstable states and the node goes to maintenance,
|
||||
# If server in unstable states and the node goes to maintenance,
|
||||
# just skip the syncing process as the pending task should be goes
|
||||
# to error state instead.
|
||||
if instance.status in states.UNSTABLE_STATES:
|
||||
LOG.info("During sync_maintenance_state the instance "
|
||||
if server.status in states.UNSTABLE_STATES:
|
||||
LOG.info("During sync_maintenance_state the server "
|
||||
"has a pending task (%(task)s). Skip.",
|
||||
{'task': instance.status},
|
||||
instance=instance)
|
||||
{'task': server.status},
|
||||
server=server)
|
||||
continue
|
||||
|
||||
if uuid not in node_dict:
|
||||
@ -318,40 +318,40 @@ class EngineManager(base_manager.BaseEngineManager):
|
||||
|
||||
node_maintenance = node_dict[uuid].maintenance
|
||||
|
||||
if instance.status == states.MAINTENANCE and not node_maintenance:
|
||||
if server.status == states.MAINTENANCE and not node_maintenance:
|
||||
# TODO(zhenguo): need to check whether we need states machine
|
||||
# transition here, and currently we just move to ACTIVE state
|
||||
# regardless of it's real power state which may need sync power
|
||||
# state periodic task to correct it.
|
||||
instance.status = states.ACTIVE
|
||||
instance.save()
|
||||
elif node_maintenance and instance.status != states.MAINTENANCE:
|
||||
instance.status = states.MAINTENANCE
|
||||
instance.save()
|
||||
server.status = states.ACTIVE
|
||||
server.save()
|
||||
elif node_maintenance and server.status != states.MAINTENANCE:
|
||||
server.status = states.MAINTENANCE
|
||||
server.save()
|
||||
|
||||
def destroy_networks(self, context, instance):
|
||||
ports = instance.nics.get_port_ids()
|
||||
def destroy_networks(self, context, server):
|
||||
ports = server.nics.get_port_ids()
|
||||
for port in ports:
|
||||
self.network_api.delete_port(context, port, instance.uuid)
|
||||
self.network_api.delete_port(context, port, server.uuid)
|
||||
|
||||
def _rollback_instances_quota(self, context, number):
|
||||
reserve_opts = {'instances': number}
|
||||
def _rollback_servers_quota(self, context, number):
|
||||
reserve_opts = {'servers': number}
|
||||
reservations = self.quota.reserve(context, **reserve_opts)
|
||||
if reservations:
|
||||
self.quota.commit(context, reservations)
|
||||
|
||||
@wrap_instance_fault
|
||||
def create_instance(self, context, instance, requested_networks,
|
||||
user_data, injected_files, key_pair, request_spec=None,
|
||||
filter_properties=None):
|
||||
@wrap_server_fault
|
||||
def create_server(self, context, server, requested_networks,
|
||||
user_data, injected_files, key_pair, request_spec=None,
|
||||
filter_properties=None):
|
||||
"""Perform a deployment."""
|
||||
LOG.debug("Starting instance...", instance=instance)
|
||||
notifications.notify_about_instance_action(
|
||||
context, instance, self.host,
|
||||
LOG.debug("Starting server...", server=server)
|
||||
notifications.notify_about_server_action(
|
||||
context, server, self.host,
|
||||
action=fields.NotificationAction.CREATE,
|
||||
phase=fields.NotificationPhase.START)
|
||||
|
||||
fsm = utils.get_state_machine(start_state=instance.status,
|
||||
fsm = utils.get_state_machine(start_state=server.status,
|
||||
target_state=states.ACTIVE)
|
||||
|
||||
if filter_properties is None:
|
||||
@ -372,24 +372,24 @@ class EngineManager(base_manager.BaseEngineManager):
|
||||
try:
|
||||
node = self.scheduler_rpcapi.select_destinations(
|
||||
context, request_spec, filter_properties)
|
||||
instance.node_uuid = node['node_uuid']
|
||||
instance.save()
|
||||
server.node_uuid = node['node_uuid']
|
||||
server.save()
|
||||
# Add a retry entry for the selected node
|
||||
nodes = retry['nodes']
|
||||
nodes.append(node['node_uuid'])
|
||||
except Exception as e:
|
||||
with excutils.save_and_reraise_exception():
|
||||
utils.process_event(fsm, instance, event='error')
|
||||
LOG.error("Created instance %(uuid)s failed. "
|
||||
utils.process_event(fsm, server, event='error')
|
||||
LOG.error("Created server %(uuid)s failed. "
|
||||
"Exception: %(exception)s",
|
||||
{"uuid": instance.uuid,
|
||||
{"uuid": server.uuid,
|
||||
"exception": e})
|
||||
|
||||
try:
|
||||
flow_engine = create_instance.get_flow(
|
||||
flow_engine = create_server.get_flow(
|
||||
context,
|
||||
self,
|
||||
instance,
|
||||
server,
|
||||
requested_networks,
|
||||
user_data,
|
||||
injected_files,
|
||||
@ -400,13 +400,13 @@ class EngineManager(base_manager.BaseEngineManager):
|
||||
)
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
utils.process_event(fsm, instance, event='error')
|
||||
self._rollback_instances_quota(context, -1)
|
||||
msg = _("Create manager instance flow failed.")
|
||||
utils.process_event(fsm, server, event='error')
|
||||
self._rollback_servers_quota(context, -1)
|
||||
msg = _("Create manager server flow failed.")
|
||||
LOG.exception(msg)
|
||||
|
||||
def _run_flow():
|
||||
# This code executes create instance flow. If something goes wrong,
|
||||
# This code executes create server flow. If something goes wrong,
|
||||
# flow reverts all job that was done and reraises an exception.
|
||||
# Otherwise, all data that was generated by flow becomes available
|
||||
# in flow engine's storage.
|
||||
@ -417,130 +417,130 @@ class EngineManager(base_manager.BaseEngineManager):
|
||||
_run_flow()
|
||||
except Exception as e:
|
||||
with excutils.save_and_reraise_exception():
|
||||
instance.power_state = states.NOSTATE
|
||||
utils.process_event(fsm, instance, event='error')
|
||||
self._rollback_instances_quota(context, -1)
|
||||
LOG.error("Created instance %(uuid)s failed."
|
||||
server.power_state = states.NOSTATE
|
||||
utils.process_event(fsm, server, event='error')
|
||||
self._rollback_servers_quota(context, -1)
|
||||
LOG.error("Created server %(uuid)s failed."
|
||||
"Exception: %(exception)s",
|
||||
{"uuid": instance.uuid,
|
||||
{"uuid": server.uuid,
|
||||
"exception": e})
|
||||
else:
|
||||
# Advance the state model for the given event. Note that this
|
||||
# doesn't alter the instance in any way. This may raise
|
||||
# doesn't alter the server in any way. This may raise
|
||||
# InvalidState, if this event is not allowed in the current state.
|
||||
instance.power_state = self.driver.get_power_state(context,
|
||||
instance.uuid)
|
||||
instance.launched_at = timeutils.utcnow()
|
||||
utils.process_event(fsm, instance, event='done')
|
||||
LOG.info("Created instance %s successfully.", instance.uuid)
|
||||
server.power_state = self.driver.get_power_state(context,
|
||||
server.uuid)
|
||||
server.launched_at = timeutils.utcnow()
|
||||
utils.process_event(fsm, server, event='done')
|
||||
LOG.info("Created server %s successfully.", server.uuid)
|
||||
|
||||
def _delete_instance(self, context, instance):
|
||||
"""Delete an instance
|
||||
def _delete_server(self, context, server):
|
||||
"""Delete a server
|
||||
|
||||
:param context: mogan request context
|
||||
:param instance: instance object
|
||||
:param server: server object
|
||||
"""
|
||||
# TODO(zhenguo): Add delete notification
|
||||
|
||||
try:
|
||||
self.destroy_networks(context, instance)
|
||||
self.destroy_networks(context, server)
|
||||
except Exception as e:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error("Destroy networks for instance %(uuid)s failed. "
|
||||
LOG.error("Destroy networks for server %(uuid)s failed. "
|
||||
"Exception: %(exception)s",
|
||||
{"uuid": instance.uuid, "exception": e})
|
||||
{"uuid": server.uuid, "exception": e})
|
||||
|
||||
self.driver.unplug_vifs(context, instance)
|
||||
self.driver.destroy(context, instance)
|
||||
self.driver.unplug_vifs(context, server)
|
||||
self.driver.destroy(context, server)
|
||||
|
||||
@wrap_instance_fault
|
||||
def delete_instance(self, context, instance):
|
||||
"""Delete an instance."""
|
||||
LOG.debug("Deleting instance...")
|
||||
@wrap_server_fault
|
||||
def delete_server(self, context, server):
|
||||
"""Delete a server."""
|
||||
LOG.debug("Deleting server...")
|
||||
|
||||
fsm = utils.get_state_machine(start_state=instance.status,
|
||||
fsm = utils.get_state_machine(start_state=server.status,
|
||||
target_state=states.DELETED)
|
||||
|
||||
@utils.synchronized(instance.uuid)
|
||||
def do_delete_instance(instance):
|
||||
@utils.synchronized(server.uuid)
|
||||
def do_delete_server(server):
|
||||
try:
|
||||
self._delete_instance(context, instance)
|
||||
except exception.InstanceNotFound:
|
||||
LOG.info("Instance disappeared during terminate",
|
||||
instance=instance)
|
||||
self._delete_server(context, server)
|
||||
except exception.ServerNotFound:
|
||||
LOG.info("Server disappeared during terminate",
|
||||
server=server)
|
||||
except Exception:
|
||||
# As we're trying to delete always go to Error if something
|
||||
# goes wrong that _delete_instance can't handle.
|
||||
# goes wrong that _delete_server can't handle.
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.exception('Setting instance status to ERROR',
|
||||
instance=instance)
|
||||
instance.power_state = states.NOSTATE
|
||||
utils.process_event(fsm, instance, event='error')
|
||||
self._rollback_instances_quota(context, 1)
|
||||
LOG.exception('Setting server status to ERROR',
|
||||
server=server)
|
||||
server.power_state = states.NOSTATE
|
||||
utils.process_event(fsm, server, event='error')
|
||||
self._rollback_servers_quota(context, 1)
|
||||
|
||||
# Issue delete request to driver only if instance is associated with
|
||||
# Issue delete request to driver only if server is associated with
|
||||
# a underlying node.
|
||||
if instance.node_uuid:
|
||||
do_delete_instance(instance)
|
||||
if server.node_uuid:
|
||||
do_delete_server(server)
|
||||
|
||||
instance.power_state = states.NOSTATE
|
||||
utils.process_event(fsm, instance, event='done')
|
||||
instance.destroy()
|
||||
server.power_state = states.NOSTATE
|
||||
utils.process_event(fsm, server, event='done')
|
||||
server.destroy()
|
||||
|
||||
def set_power_state(self, context, instance, state):
|
||||
"""Set power state for the specified instance."""
|
||||
def set_power_state(self, context, server, state):
|
||||
"""Set power state for the specified server."""
|
||||
|
||||
fsm = utils.get_state_machine(start_state=instance.status)
|
||||
fsm = utils.get_state_machine(start_state=server.status)
|
||||
|
||||
@utils.synchronized(instance.uuid)
|
||||
@utils.synchronized(server.uuid)
|
||||
def do_set_power_state():
|
||||
LOG.debug('Power %(state)s called for instance %(instance)s',
|
||||
LOG.debug('Power %(state)s called for server %(server)s',
|
||||
{'state': state,
|
||||
'instance': instance})
|
||||
self.driver.set_power_state(context, instance, state)
|
||||
'server': server})
|
||||
self.driver.set_power_state(context, server, state)
|
||||
|
||||
do_set_power_state()
|
||||
instance.power_state = self.driver.get_power_state(context,
|
||||
instance.uuid)
|
||||
utils.process_event(fsm, instance, event='done')
|
||||
server.power_state = self.driver.get_power_state(context,
|
||||
server.uuid)
|
||||
utils.process_event(fsm, server, event='done')
|
||||
LOG.info('Successfully set node power state: %s',
|
||||
state, instance=instance)
|
||||
state, server=server)
|
||||
|
||||
def _rebuild_instance(self, context, instance):
|
||||
"""Perform rebuild action on the specified instance."""
|
||||
def _rebuild_server(self, context, server):
|
||||
"""Perform rebuild action on the specified server."""
|
||||
|
||||
# TODO(zhenguo): Add delete notification
|
||||
|
||||
self.driver.rebuild(context, instance)
|
||||
self.driver.rebuild(context, server)
|
||||
|
||||
@wrap_instance_fault
|
||||
def rebuild_instance(self, context, instance):
|
||||
"""Destroy and re-make this instance.
|
||||
@wrap_server_fault
|
||||
def rebuild_server(self, context, server):
|
||||
"""Destroy and re-make this server.
|
||||
|
||||
:param context: mogan request context
|
||||
:param instance: instance object
|
||||
:param server: server object
|
||||
"""
|
||||
|
||||
LOG.debug('Rebuilding instance', instance=instance)
|
||||
LOG.debug('Rebuilding server', server=server)
|
||||
|
||||
fsm = utils.get_state_machine(start_state=instance.status)
|
||||
fsm = utils.get_state_machine(start_state=server.status)
|
||||
|
||||
try:
|
||||
self._rebuild_instance(context, instance)
|
||||
self._rebuild_server(context, server)
|
||||
except Exception as e:
|
||||
with excutils.save_and_reraise_exception():
|
||||
utils.process_event(fsm, instance, event='error')
|
||||
LOG.error("Rebuild instance %(uuid)s failed."
|
||||
utils.process_event(fsm, server, event='error')
|
||||
LOG.error("Rebuild server %(uuid)s failed."
|
||||
"Exception: %(exception)s",
|
||||
{"uuid": instance.uuid,
|
||||
{"uuid": server.uuid,
|
||||
"exception": e})
|
||||
|
||||
utils.process_event(fsm, instance, event='done')
|
||||
LOG.info('Instance was successfully rebuilt', instance=instance)
|
||||
utils.process_event(fsm, server, event='done')
|
||||
LOG.info('Server was successfully rebuilt', server=server)
|
||||
|
||||
def get_serial_console(self, context, instance):
|
||||
node_console_info = self.driver.get_serial_console_by_instance(
|
||||
context, instance)
|
||||
def get_serial_console(self, context, server):
|
||||
node_console_info = self.driver.get_serial_console_by_server(
|
||||
context, server)
|
||||
token = uuidutils.generate_uuid()
|
||||
access_url = '%s?token=%s' % (
|
||||
CONF.shellinabox_console.shellinabox_base_url, token)
|
||||
|
@ -14,7 +14,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Instance Metadata information."""
|
||||
"""Server Metadata information."""
|
||||
|
||||
import posixpath
|
||||
|
||||
@ -47,39 +47,39 @@ class InvalidMetadataPath(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class InstanceMetadata(object):
|
||||
"""Instance metadata."""
|
||||
class ServerMetadata(object):
|
||||
"""Server metadata."""
|
||||
|
||||
def __init__(self, instance, content=None, user_data=None,
|
||||
def __init__(self, server, content=None, user_data=None,
|
||||
key_pair=None, extra_md=None):
|
||||
"""Creation of this object should basically cover all time consuming
|
||||
collection. Methods after that should not cause time delays due to
|
||||
network operations or lengthy cpu operations.
|
||||
|
||||
The user should then get a single instance and make multiple method
|
||||
The user should then get a single server and make multiple method
|
||||
calls on it.
|
||||
"""
|
||||
if not content:
|
||||
content = []
|
||||
|
||||
self.instance = instance
|
||||
self.server = server
|
||||
self.extra_md = extra_md
|
||||
self.availability_zone = instance.availability_zone
|
||||
self.availability_zone = server.availability_zone
|
||||
|
||||
if user_data is not None:
|
||||
self.userdata_raw = base64.decode_as_bytes(user_data)
|
||||
else:
|
||||
self.userdata_raw = None
|
||||
|
||||
# TODO(zhenguo): Add hostname to instance object
|
||||
self.hostname = instance.name
|
||||
self.uuid = instance.uuid
|
||||
# TODO(zhenguo): Add hostname to server object
|
||||
self.hostname = server.name
|
||||
self.uuid = server.uuid
|
||||
self.content = {}
|
||||
self.files = []
|
||||
self.keypair = key_pair
|
||||
|
||||
# 'content' is passed in from the configdrive code in
|
||||
# mogan/engine/flows/create_instance.py. That's how we get the
|
||||
# mogan/engine/flows/create_server.py. That's how we get the
|
||||
# injected files (personalities) in.
|
||||
for (path, contents) in content:
|
||||
key = "%04i" % len(self.content)
|
||||
@ -125,7 +125,7 @@ class InstanceMetadata(object):
|
||||
]
|
||||
|
||||
metadata['hostname'] = self.hostname
|
||||
metadata['name'] = self.instance.name
|
||||
metadata['name'] = self.server.name
|
||||
metadata['availability_zone'] = self.availability_zone
|
||||
|
||||
return jsonutils.dump_as_bytes(metadata)
|
||||
@ -170,7 +170,7 @@ class InstanceMetadata(object):
|
||||
if OPENSTACK_VERSIONS != versions:
|
||||
LOG.debug("future versions %s hidden in version list",
|
||||
[v for v in OPENSTACK_VERSIONS
|
||||
if v not in versions], instance=self.instance)
|
||||
if v not in versions], server=self.server)
|
||||
versions += ["latest"]
|
||||
return versions
|
||||
|
||||
|
@ -49,12 +49,12 @@ class EngineAPI(object):
|
||||
version_cap=self.RPC_API_VERSION,
|
||||
serializer=serializer)
|
||||
|
||||
def create_instance(self, context, instance, requested_networks,
|
||||
user_data, injected_files, key_pair, request_spec,
|
||||
filter_properties):
|
||||
def create_server(self, context, server, requested_networks,
|
||||
user_data, injected_files, key_pair, request_spec,
|
||||
filter_properties):
|
||||
"""Signal to engine service to perform a deployment."""
|
||||
cctxt = self.client.prepare(topic=self.topic, server=CONF.host)
|
||||
cctxt.cast(context, 'create_instance', instance=instance,
|
||||
cctxt.cast(context, 'create_server', server=server,
|
||||
requested_networks=requested_networks,
|
||||
user_data=user_data,
|
||||
injected_files=injected_files,
|
||||
@ -62,23 +62,23 @@ class EngineAPI(object):
|
||||
request_spec=request_spec,
|
||||
filter_properties=filter_properties)
|
||||
|
||||
def delete_instance(self, context, instance):
|
||||
"""Signal to engine service to delete an instance."""
|
||||
def delete_server(self, context, server):
|
||||
"""Signal to engine service to delete a server."""
|
||||
cctxt = self.client.prepare(topic=self.topic, server=CONF.host)
|
||||
cctxt.cast(context, 'delete_instance', instance=instance)
|
||||
cctxt.cast(context, 'delete_server', server=server)
|
||||
|
||||
def set_power_state(self, context, instance, state):
|
||||
"""Signal to engine service to perform power action on instance."""
|
||||
def set_power_state(self, context, server, state):
|
||||
"""Signal to engine service to perform power action on server."""
|
||||
cctxt = self.client.prepare(topic=self.topic, server=CONF.host)
|
||||
return cctxt.cast(context, 'set_power_state',
|
||||
instance=instance, state=state)
|
||||
server=server, state=state)
|
||||
|
||||
def rebuild_instance(self, context, instance):
|
||||
"""Signal to engine service to rebuild an instance."""
|
||||
def rebuild_server(self, context, server):
|
||||
"""Signal to engine service to rebuild a server."""
|
||||
cctxt = self.client.prepare(topic=self.topic, server=CONF.host)
|
||||
return cctxt.cast(context, 'rebuild_instance', instance=instance)
|
||||
return cctxt.cast(context, 'rebuild_server', server=server)
|
||||
|
||||
def get_serial_console(self, context, instance):
|
||||
def get_serial_console(self, context, server):
|
||||
cctxt = self.client.prepare(topic=self.topic, server=CONF.host)
|
||||
return cctxt.call(context, 'get_serial_console',
|
||||
instance=instance)
|
||||
server=server)
|
||||
|
@ -62,7 +62,7 @@ def get_client(token=None):
|
||||
class API(object):
|
||||
"""API for interacting with the neutron 2.x API."""
|
||||
|
||||
def create_port(self, context, network_uuid, mac, instance_uuid):
|
||||
def create_port(self, context, network_uuid, mac, server_uuid):
|
||||
"""Create neutron port."""
|
||||
|
||||
client = get_client(context.auth_token)
|
||||
@ -70,7 +70,7 @@ class API(object):
|
||||
'port': {
|
||||
'network_id': network_uuid,
|
||||
'mac_address': mac,
|
||||
'device_id': instance_uuid,
|
||||
'device_id': server_uuid,
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,8 +78,8 @@ class API(object):
|
||||
port = client.create_port(body)
|
||||
except neutron_exceptions.NeutronClientException as e:
|
||||
msg = (_("Could not create neutron port on network %(net)s for "
|
||||
"instance %(instance)s. %(exc)s"),
|
||||
{'net': network_uuid, 'instance': instance_uuid, 'exc': e})
|
||||
"server %(server)s. %(exc)s"),
|
||||
{'net': network_uuid, 'server': server_uuid, 'exc': e})
|
||||
LOG.exception(msg)
|
||||
raise exception.NetworkError(msg)
|
||||
return port
|
||||
@ -99,7 +99,7 @@ class API(object):
|
||||
{'port_id': port_id, 'reason': e})
|
||||
raise exception.NetworkError(msg)
|
||||
|
||||
def delete_port(self, context, port_id, instance_uuid):
|
||||
def delete_port(self, context, port_id, server_uuid):
|
||||
"""Delete neutron port."""
|
||||
|
||||
client = get_client(context.auth_token)
|
||||
@ -110,7 +110,7 @@ class API(object):
|
||||
LOG.warning("Port %s does not exist", port_id)
|
||||
else:
|
||||
LOG.warning(
|
||||
"Failed to delete port %s for instance.",
|
||||
"Failed to delete port %s for server.",
|
||||
port_id, exc_info=True)
|
||||
raise e
|
||||
|
||||
@ -149,8 +149,8 @@ class API(object):
|
||||
fip = self._get_floating_ip_by_address(client, address)
|
||||
return fip
|
||||
|
||||
def get_instance_id_by_floating_address(self, context, address):
|
||||
"""Return the instance id a floating IP's fixed IP is allocated to."""
|
||||
def get_server_id_by_floating_address(self, context, address):
|
||||
"""Return the server id a floating IP's fixed IP is allocated to."""
|
||||
client = get_client(context.auth_token)
|
||||
fip = self._get_floating_ip_by_address(client, address)
|
||||
if not fip['port_id']:
|
||||
@ -161,9 +161,9 @@ class API(object):
|
||||
except exception.PortNotFound:
|
||||
# NOTE: Here is a potential race condition between _show_port() and
|
||||
# _get_floating_ip_by_address(). fip['port_id'] shows a port which
|
||||
# is the server instance's. At _get_floating_ip_by_address(),
|
||||
# Neutron returns the list which includes the instance. Just after
|
||||
# that, the deletion of the instance happens and Neutron returns
|
||||
# is the server server's. At _get_floating_ip_by_address(),
|
||||
# Neutron returns the list which includes the server. Just after
|
||||
# that, the deletion of the server happens and Neutron returns
|
||||
# 404 on _show_port().
|
||||
LOG.debug('The port(%s) is not found', fip['port_id'])
|
||||
return None
|
||||
@ -181,7 +181,7 @@ class API(object):
|
||||
client.update_floatingip(fip['id'], {'floatingip': param})
|
||||
|
||||
def disassociate_floating_ip(self, context, address):
|
||||
"""Disassociate a floating IP from the instance."""
|
||||
"""Disassociate a floating IP from the server."""
|
||||
|
||||
client = get_client(context.auth_token)
|
||||
fip = self._get_floating_ip_by_address(client, address)
|
||||
@ -202,12 +202,12 @@ class API(object):
|
||||
|
||||
return nets
|
||||
|
||||
def _ports_needed_per_instance(self, context, client, requested_networks):
|
||||
def _ports_needed_per_server(self, context, client, requested_networks):
|
||||
|
||||
ports_needed_per_instance = 0
|
||||
ports_needed_per_server = 0
|
||||
net_ids_requested = []
|
||||
for request in requested_networks:
|
||||
ports_needed_per_instance += 1
|
||||
ports_needed_per_server += 1
|
||||
net_ids_requested.append(request['net_id'])
|
||||
|
||||
# Now check to see if all requested networks exist
|
||||
@ -231,27 +231,27 @@ class API(object):
|
||||
id_str = id_str and id_str + ', ' + _id or _id
|
||||
raise exception.NetworkNotFound(network_id=id_str)
|
||||
|
||||
return ports_needed_per_instance
|
||||
return ports_needed_per_server
|
||||
|
||||
def validate_networks(self, context, requested_networks, num_instances):
|
||||
def validate_networks(self, context, requested_networks, num_servers):
|
||||
"""Validate that the tenant can use the requested networks.
|
||||
|
||||
Return the number of instances than can be successfully allocated
|
||||
Return the number of servers than can be successfully allocated
|
||||
with the requested network configuration.
|
||||
"""
|
||||
LOG.debug('validate_networks() for %s', requested_networks)
|
||||
|
||||
client = get_client(context.auth_token)
|
||||
ports_needed_per_instance = self._ports_needed_per_instance(
|
||||
ports_needed_per_server = self._ports_needed_per_server(
|
||||
context, client, requested_networks)
|
||||
|
||||
# Check the quota and return how many of the requested number of
|
||||
# instances can be created
|
||||
if ports_needed_per_instance:
|
||||
# servers can be created
|
||||
if ports_needed_per_server:
|
||||
quotas = client.show_quota(context.project_id)['quota']
|
||||
if quotas.get('port', -1) == -1:
|
||||
# Unlimited Port Quota
|
||||
return num_instances
|
||||
return num_servers
|
||||
|
||||
# We only need the port count so only ask for ids back.
|
||||
params = dict(tenant_id=context.project_id, fields=['id'])
|
||||
@ -263,13 +263,13 @@ class API(object):
|
||||
{'ports': len(ports),
|
||||
'quota': quotas.get('port')})
|
||||
raise exception.PortLimitExceeded(msg)
|
||||
ports_needed = ports_needed_per_instance * num_instances
|
||||
ports_needed = ports_needed_per_server * num_servers
|
||||
if free_ports >= ports_needed:
|
||||
return num_instances
|
||||
return num_servers
|
||||
else:
|
||||
return free_ports // ports_needed_per_instance
|
||||
return free_ports // ports_needed_per_server
|
||||
|
||||
return num_instances
|
||||
return num_servers
|
||||
|
||||
|
||||
def _ensure_requested_network_ordering(accessor, unordered, preferred):
|
||||
|
@ -18,7 +18,7 @@ the system.
|
||||
|
||||
from mogan.notifications.objects import base as notification_base
|
||||
from mogan.notifications.objects import exception as notification_exception
|
||||
from mogan.notifications.objects import instance as instance_notification
|
||||
from mogan.notifications.objects import server as server_notification
|
||||
from mogan.objects import fields
|
||||
|
||||
|
||||
@ -34,10 +34,10 @@ def _get_fault_and_priority_from_exc(exception):
|
||||
return fault, priority
|
||||
|
||||
|
||||
def notify_about_instance_action(context, instance, host, action, phase=None,
|
||||
binary='mogan-engine', exception=None):
|
||||
"""Send versioned notification about the action made on the instance
|
||||
:param instance: the instance which the action performed on
|
||||
def notify_about_server_action(context, server, host, action, phase=None,
|
||||
binary='mogan-engine', exception=None):
|
||||
"""Send versioned notification about the action made on the server
|
||||
:param server: the server which the action performed on
|
||||
:param host: the host emitting the notification
|
||||
:param action: the name of the action
|
||||
:param phase: the phase of the action
|
||||
@ -47,16 +47,16 @@ def notify_about_instance_action(context, instance, host, action, phase=None,
|
||||
|
||||
fault, priority = _get_fault_and_priority_from_exc(exception)
|
||||
|
||||
payload = instance_notification.InstanceActionPayload(
|
||||
instance=instance,
|
||||
payload = server_notification.ServerActionPayload(
|
||||
server=server,
|
||||
fault=fault)
|
||||
notification = instance_notification.InstanceActionNotification(
|
||||
notification = server_notification.ServerActionNotification(
|
||||
context=context,
|
||||
priority=priority,
|
||||
publisher=notification_base.NotificationPublisher(
|
||||
context=context, host=host, binary=binary),
|
||||
event_type=notification_base.EventType(
|
||||
object='instance',
|
||||
object='server',
|
||||
action=action,
|
||||
phase=phase),
|
||||
payload=payload)
|
||||
|
@ -16,21 +16,21 @@ from mogan.objects import fields
|
||||
|
||||
|
||||
@mogan_base.MoganObjectRegistry.register_notification
|
||||
class InstancePayload(base.NotificationPayloadBase):
|
||||
class ServerPayload(base.NotificationPayloadBase):
|
||||
SCHEMA = {
|
||||
'name': ('instance', 'name'),
|
||||
'uuid': ('instance', 'uuid'),
|
||||
'user_id': ('instance', 'user_id'),
|
||||
'project_id': ('instance', 'project_id'),
|
||||
'availability_zone': ('instance', 'availability_zone'),
|
||||
'image_uuid': ('instance', 'image_uuid'),
|
||||
'created_at': ('instance', 'created_at'),
|
||||
'launched_at': ('instance', 'launched_at'),
|
||||
'updated_at': ('instance', 'updated_at'),
|
||||
'status': ('instance', 'status'),
|
||||
'power_state': ('instance', 'power_state'),
|
||||
'instance_type_uuid': ('instance', 'instance_type_uuid'),
|
||||
'description': ('instance', 'description')
|
||||
'name': ('server', 'name'),
|
||||
'uuid': ('server', 'uuid'),
|
||||
'user_id': ('server', 'user_id'),
|
||||
'project_id': ('server', 'project_id'),
|
||||
'availability_zone': ('server', 'availability_zone'),
|
||||
'image_uuid': ('server', 'image_uuid'),
|
||||
'created_at': ('server', 'created_at'),
|
||||
'launched_at': ('server', 'launched_at'),
|
||||
'updated_at': ('server', 'updated_at'),
|
||||
'status': ('server', 'status'),
|
||||
'power_state': ('server', 'power_state'),
|
||||
'flavor_uuid': ('server', 'flavor_uuid'),
|
||||
'description': ('server', 'description')
|
||||
}
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
@ -40,7 +40,7 @@ class InstancePayload(base.NotificationPayloadBase):
|
||||
'user_id': fields.StringField(nullable=True),
|
||||
'project_id': fields.StringField(nullable=True),
|
||||
'description': fields.StringField(nullable=True),
|
||||
'instance_type_uuid': fields.UUIDField(nullable=False),
|
||||
'flavor_uuid': fields.UUIDField(nullable=False),
|
||||
'image_uuid': fields.UUIDField(nullable=True),
|
||||
'availability_zone': fields.StringField(nullable=True),
|
||||
'power_state': fields.StringField(nullable=True),
|
||||
@ -52,13 +52,13 @@ class InstancePayload(base.NotificationPayloadBase):
|
||||
# 'extra'
|
||||
}
|
||||
|
||||
def __init__(self, instance, **kwargs):
|
||||
super(InstancePayload, self).__init__(**kwargs)
|
||||
self.populate_schema(instance=instance)
|
||||
def __init__(self, server, **kwargs):
|
||||
super(ServerPayload, self).__init__(**kwargs)
|
||||
self.populate_schema(server=server)
|
||||
|
||||
|
||||
@mogan_base.MoganObjectRegistry.register_notification
|
||||
class InstanceActionPayload(InstancePayload):
|
||||
class ServerActionPayload(ServerPayload):
|
||||
# No SCHEMA as all the additional fields are calculated
|
||||
|
||||
VERSION = '1.0'
|
||||
@ -66,18 +66,18 @@ class InstanceActionPayload(InstancePayload):
|
||||
'fault': fields.ObjectField('ExceptionPayload', nullable=True),
|
||||
}
|
||||
|
||||
def __init__(self, instance, fault, **kwargs):
|
||||
super(InstanceActionPayload, self).__init__(
|
||||
instance=instance,
|
||||
def __init__(self, server, fault, **kwargs):
|
||||
super(ServerActionPayload, self).__init__(
|
||||
server=server,
|
||||
fault=fault,
|
||||
**kwargs)
|
||||
|
||||
|
||||
@mogan_base.MoganObjectRegistry.register_notification
|
||||
class InstanceActionNotification(base.NotificationBase):
|
||||
class ServerActionNotification(base.NotificationBase):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
fields = {
|
||||
'payload': fields.ObjectField('InstanceActionPayload')
|
||||
'payload': fields.ObjectField('ServerActionPayload')
|
||||
}
|
@ -25,10 +25,10 @@ def register_all():
|
||||
# NOTE(danms): You must make sure your object gets imported in this
|
||||
# function in order for it to be registered by services that may
|
||||
# need to receive it via RPC.
|
||||
__import__('mogan.objects.instance_type')
|
||||
__import__('mogan.objects.instance')
|
||||
__import__('mogan.objects.instance_nics')
|
||||
__import__('mogan.objects.instance_fault')
|
||||
__import__('mogan.objects.flavor')
|
||||
__import__('mogan.objects.server')
|
||||
__import__('mogan.objects.server_nics')
|
||||
__import__('mogan.objects.server_fault')
|
||||
__import__('mogan.objects.compute_node')
|
||||
__import__('mogan.objects.compute_port')
|
||||
__import__('mogan.objects.compute_disk')
|
||||
|
@ -26,7 +26,7 @@ class ComputeDisk(base.MoganObject, object_base.VersionedObjectDictCompat):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
dbapi = dbapi.get_instance()
|
||||
dbapi = dbapi.get_server()
|
||||
|
||||
fields = {
|
||||
'id': object_fields.IntegerField(read_only=True),
|
||||
@ -81,7 +81,7 @@ class ComputeDiskList(object_base.ObjectListBase, base.MoganObject,
|
||||
|
||||
VERSION = '1.0'
|
||||
|
||||
dbapi = dbapi.get_instance()
|
||||
dbapi = dbapi.get_server()
|
||||
|
||||
fields = {
|
||||
'objects': object_fields.ListOfObjectsField('ComputeDisk')
|
||||
|
@ -27,7 +27,7 @@ class ComputeNode(base.MoganObject, object_base.VersionedObjectDictCompat):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
dbapi = dbapi.get_instance()
|
||||
dbapi = dbapi.get_server()
|
||||
|
||||
fields = {
|
||||
'id': object_fields.IntegerField(read_only=True),
|
||||
@ -100,7 +100,7 @@ class ComputeNodeList(object_base.ObjectListBase, base.MoganObject,
|
||||
|
||||
VERSION = '1.0'
|
||||
|
||||
dbapi = dbapi.get_instance()
|
||||
dbapi = dbapi.get_server()
|
||||
|
||||
fields = {
|
||||
'objects': object_fields.ListOfObjectsField('ComputeNode')
|
||||
|
@ -26,7 +26,7 @@ class ComputePort(base.MoganObject, object_base.VersionedObjectDictCompat):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
dbapi = dbapi.get_instance()
|
||||
dbapi = dbapi.get_server()
|
||||
|
||||
fields = {
|
||||
'id': object_fields.IntegerField(read_only=True),
|
||||
@ -88,7 +88,7 @@ class ComputePortList(object_base.ObjectListBase, base.MoganObject,
|
||||
|
||||
VERSION = '1.0'
|
||||
|
||||
dbapi = dbapi.get_instance()
|
||||
dbapi = dbapi.get_server()
|
||||
|
||||
fields = {
|
||||
'objects': object_fields.ListOfObjectsField('ComputePort')
|
||||
|
@ -25,11 +25,11 @@ OPTIONAL_FIELDS = ['extra_specs', 'projects']
|
||||
|
||||
|
||||
@base.MoganObjectRegistry.register
|
||||
class InstanceType(base.MoganObject, object_base.VersionedObjectDictCompat):
|
||||
class Flavor(base.MoganObject, object_base.VersionedObjectDictCompat):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
dbapi = dbapi.get_instance()
|
||||
dbapi = dbapi.get_server()
|
||||
|
||||
fields = {
|
||||
'uuid': object_fields.UUIDField(nullable=True),
|
||||
@ -41,7 +41,7 @@ class InstanceType(base.MoganObject, object_base.VersionedObjectDictCompat):
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(InstanceType, self).__init__(*args, **kwargs)
|
||||
super(Flavor, self).__init__(*args, **kwargs)
|
||||
self._orig_extra_specs = {}
|
||||
self._orig_projects = {}
|
||||
|
||||
@ -73,8 +73,8 @@ class InstanceType(base.MoganObject, object_base.VersionedObjectDictCompat):
|
||||
self.obj_reset_changes(['projects'])
|
||||
|
||||
def obj_reset_changes(self, fields=None, recursive=False):
|
||||
super(InstanceType, self).obj_reset_changes(fields=fields,
|
||||
recursive=recursive)
|
||||
super(Flavor, self).obj_reset_changes(fields=fields,
|
||||
recursive=recursive)
|
||||
if fields is None or 'extra_specs' in fields:
|
||||
self._orig_extra_specs = (dict(self.extra_specs)
|
||||
if self.obj_attr_is_set('extra_specs')
|
||||
@ -85,7 +85,7 @@ class InstanceType(base.MoganObject, object_base.VersionedObjectDictCompat):
|
||||
else [])
|
||||
|
||||
def obj_what_changed(self):
|
||||
changes = super(InstanceType, self).obj_what_changed()
|
||||
changes = super(Flavor, self).obj_what_changed()
|
||||
if ('extra_specs' in self and
|
||||
self.extra_specs != self._orig_extra_specs):
|
||||
changes.add('extra_specs')
|
||||
@ -96,37 +96,35 @@ class InstanceType(base.MoganObject, object_base.VersionedObjectDictCompat):
|
||||
@staticmethod
|
||||
def _from_db_object_list(db_objects, cls, context):
|
||||
"""Converts a list of database entities to a list of formal objects."""
|
||||
return [InstanceType._from_db_object(context, cls(context), obj,
|
||||
expected_attrs=['extra_specs'])
|
||||
return [Flavor._from_db_object(context, cls(context), obj,
|
||||
expected_attrs=['extra_specs'])
|
||||
for obj in db_objects]
|
||||
|
||||
@classmethod
|
||||
def list(cls, context):
|
||||
"""Return a list of Instance Type objects."""
|
||||
db_instance_types = cls.dbapi.instance_type_get_all(context)
|
||||
return InstanceType._from_db_object_list(db_instance_types, cls,
|
||||
context)
|
||||
"""Return a list of Flavor objects."""
|
||||
db_flavors = cls.dbapi.flavor_get_all(context)
|
||||
return Flavor._from_db_object_list(db_flavors, cls, context)
|
||||
|
||||
@classmethod
|
||||
def get(cls, context, instance_type_uuid):
|
||||
"""Find a Instance Type and return a Instance Type object."""
|
||||
db_instance_type = cls.dbapi.instance_type_get(context,
|
||||
instance_type_uuid)
|
||||
instance_type = InstanceType._from_db_object(
|
||||
context, cls(context), db_instance_type,
|
||||
def get(cls, context, flavor_uuid):
|
||||
"""Find a Flavor and return a Flavor object."""
|
||||
db_flavor = cls.dbapi.flavor_get(context, flavor_uuid)
|
||||
flavor = Flavor._from_db_object(
|
||||
context, cls(context), db_flavor,
|
||||
expected_attrs=['extra_specs', 'projects'])
|
||||
return instance_type
|
||||
return flavor
|
||||
|
||||
def create(self, context=None):
|
||||
"""Create a Instance Type record in the DB."""
|
||||
"""Create a Flavor record in the DB."""
|
||||
values = self.obj_get_changes()
|
||||
db_instance_type = self.dbapi.instance_type_create(context, values)
|
||||
self._from_db_object(context, self, db_instance_type,
|
||||
db_flavor = self.dbapi.flavor_create(context, values)
|
||||
self._from_db_object(context, self, db_flavor,
|
||||
expected_attrs=['extra_specs'])
|
||||
|
||||
def destroy(self, context=None):
|
||||
"""Delete the Instance Type from the DB."""
|
||||
self.dbapi.instance_type_destroy(context, self.uuid)
|
||||
"""Delete the Flavor from the DB."""
|
||||
self.dbapi.flavor_destroy(context, self.uuid)
|
||||
self.obj_reset_changes()
|
||||
|
||||
def save(self, context=None):
|
||||
@ -152,7 +150,7 @@ class InstanceType(base.MoganObject, object_base.VersionedObjectDictCompat):
|
||||
if added_projects or deleted_projects:
|
||||
self.save_projects(context, added_projects, deleted_projects)
|
||||
|
||||
self.dbapi.instance_type_update(context, self.uuid, updates)
|
||||
self.dbapi.flavor_update(context, self.uuid, updates)
|
||||
|
||||
def save_extra_specs(self, context, to_add=None, to_delete=None):
|
||||
"""Add or delete extra_specs.
|
@ -30,7 +30,7 @@ class KeyPair(base.MoganObject):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
dbapi = dbapi.get_instance()
|
||||
dbapi = dbapi.get_server()
|
||||
|
||||
fields = {
|
||||
'id': fields.IntegerField(),
|
||||
@ -85,7 +85,7 @@ class KeyPairList(object_base.ObjectListBase, base.MoganObject):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
dbapi = dbapi.get_instance()
|
||||
dbapi = dbapi.get_server()
|
||||
|
||||
fields = {
|
||||
'objects': fields.ListOfObjectsField('KeyPair'),
|
||||
|
@ -14,7 +14,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Quotas for instances."""
|
||||
"""Quotas for servers."""
|
||||
|
||||
import datetime
|
||||
|
||||
@ -38,7 +38,7 @@ class Quota(base.MoganObject, object_base.VersionedObjectDictCompat):
|
||||
# Version 1.0: Initial version
|
||||
VERSION = '1.0'
|
||||
|
||||
dbapi = dbapi.get_instance()
|
||||
dbapi = dbapi.get_server()
|
||||
|
||||
fields = {
|
||||
'id': object_fields.IntegerField(),
|
||||
@ -164,7 +164,7 @@ class DbQuotaDriver(object):
|
||||
The default driver utilizes the local database.
|
||||
"""
|
||||
|
||||
dbapi = dbapi.get_instance()
|
||||
dbapi = dbapi.get_server()
|
||||
|
||||
def get_project_quotas(self, context, resources, project_id, usages=True):
|
||||
"""Retrieve quotas for a project.
|
||||
@ -185,11 +185,11 @@ class DbQuotaDriver(object):
|
||||
for p_quota in res:
|
||||
project_quotas[p_quota.resource_name] = p_quota.hard_limit
|
||||
if project_quotas == {}:
|
||||
self.dbapi.quota_create(context, {'resource_name': 'instances',
|
||||
self.dbapi.quota_create(context, {'resource_name': 'servers',
|
||||
'project_id': project_id,
|
||||
'hard_limit': 10,
|
||||
'allocated': 0})
|
||||
project_quotas['instances'] = 10
|
||||
project_quotas['servers'] = 10
|
||||
allocated_quotas = None
|
||||
if usages:
|
||||
project_usages = self.dbapi.quota_usage_get_all_by_project(
|
||||
@ -374,7 +374,7 @@ class BaseResource(object):
|
||||
def __init__(self, name, sync, count=None):
|
||||
"""Initializes a Resource.
|
||||
|
||||
:param name: The name of the resource, i.e., "instances".
|
||||
:param name: The name of the resource, i.e., "servers".
|
||||
:param sync: A dbapi methods name which returns a dictionary
|
||||
to resynchronize the in_use count for one or more
|
||||
resources, as described above.
|
||||
@ -407,12 +407,12 @@ class BaseResource(object):
|
||||
return -1
|
||||
|
||||
|
||||
class InstanceResource(BaseResource):
|
||||
"""ReservableResource for a specific instance."""
|
||||
class ServerResource(BaseResource):
|
||||
"""ReservableResource for a specific server."""
|
||||
|
||||
def __init__(self, name='instances'):
|
||||
"""Initializes a InstanceResource.
|
||||
def __init__(self, name='servers'):
|
||||
"""Initializes a ServerResource.
|
||||
|
||||
:param name: The kind of resource, i.e., "instances".
|
||||
:param name: The kind of resource, i.e., "servers".
|
||||
"""
|
||||
super(InstanceResource, self).__init__(name, "_sync_%s" % name)
|
||||
super(ServerResource, self).__init__(name, "_sync_%s" % name)
|
||||
|
@ -29,11 +29,11 @@ LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@base.MoganObjectRegistry.register
|
||||
class Instance(base.MoganObject, object_base.VersionedObjectDictCompat):
|
||||
class Server(base.MoganObject, object_base.VersionedObjectDictCompat):
|
||||
# Version 1.0: Initial version
|
||||