Change to use /flavors in URI

Change-Id: I6a6a571e5485b9e64c34b1a551256c0bd3675ea5
Depends-On: I50358a289c58b827283c9c4c6e068eee17063bfd
This commit is contained in:
Zhenguo Niu 2017-04-17 19:54:25 +08:00
parent c1d2fa7172
commit 24ef8d2793
26 changed files with 705 additions and 708 deletions

View File

@ -0,0 +1,303 @@
.. -*- rst -*-
=========
Flavors
=========
Show and manage server flavors.
Flavors are a way to describe the basic dimensions of a instance to be
created including how much ``cpu``, ``ram``, and ``disk space`` are
allocated to an instance built with this flavor.
List Flavors
============
.. rest_method:: GET /flavors
Lists all flavors accessible to your project.
Normal response codes: 200
Error response codes: unauthorized(401), forbidden(403)
Request
-------
Response
--------
.. rest_parameters:: parameters.yaml
- flavors: flavors
- name: flavor_name
- links: links
- description: flavor_description
- uuid: flavor_uuid
- created_at: created_at
- updated_at: updated_at
- is_public: flavor_is_public
- extra_specs: flavor_extra_specs
**Example List flavors**
.. literalinclude:: samples/flavors/flavors-list-resp.json
:language: javascript
Create Flavor
=============
.. rest_method:: POST /flavors
Creates a flavor.
Creating a flavor is typically only available to administrators of a
cloud because this has implications for scheduling efficiently in the cloud.
Normal response codes: 201
Error response codes: badRequest(400), unauthorized(401), forbidden(403),
conflict(409)
Request
-------
.. rest_parameters:: parameters.yaml
- name: flavor_name
- description: flavor_description
- is_public: flavor_is_public_not_required
- uuid: flavor_uuid_not_required
**Example Create Flavor**
.. literalinclude:: samples/flavors/flavor-create-post-req.json
:language: javascript
Response
--------
.. rest_parameters:: parameters.yaml
- name: flavor_name
- links: links
- description: flavor_description
- uuid: flavor_uuid
- created_at: created_at
- updated_at: updated_at
- is_public: flavor_is_public
- extra_specs: flavor_extra_specs
**Example Create flavor**
.. literalinclude:: samples/flavors/flavor-create-post-resp.json
:language: javascript
Update Flavor
=============
.. rest_method:: PUT /flavors/{flavor_uuid}
Updates a flavor.
Updating a flavor is typically only available to administrators of a
cloud because this has implications for scheduling efficiently in the cloud.
Normal response codes: 200
Error response codes: badRequest(400), unauthorized(401), forbidden(403),
conflict(409)
Request
-------
.. rest_parameters:: parameters.yaml
- flavor_uuid: flavor_uuid_path
- name: flavor_name
- description: flavor_description
- is_public: flavor_is_public_not_required
**Example Update Flavor**
.. literalinclude:: samples/flavors/flavor-update-put-req.json
:language: javascript
Response
--------
.. rest_parameters:: parameters.yaml
- name: flavor_name
- links: links
- description: flavor_description
- uuid: flavor_uuid
- created_at: created_at
- updated_at: updated_at
- is_public: flavor_is_public
- extra_specs: flavor_extra_specs
**Example Update flavor**
.. literalinclude:: samples/flavors/flavor-update-put-resp.json
:language: javascript
Show Server Flavor Details
==========================
.. rest_method:: GET /flavors/{flavor_uuid}
Shows details for a flavor.
Normal response codes: 200
Error response codes: unauthorized(401), forbidden(403), itemNotFound(404)
Request
-------
.. rest_parameters:: parameters.yaml
- flavor_uuid: flavor_uuid_path
Response
--------
.. rest_parameters:: parameters.yaml
- name: flavor_name
- links: links
- description: flavor_description
- uuid: flavor_uuid
- created_at: created_at
- updated_at: updated_at
- is_public: flavor_is_public
- extra_specs: flavor_extra_specs
**Example Show Flavor Details**
.. literalinclude:: samples/flavors/flavor-get-resp.json
:language: javascript
Delete Flavor
=============
.. rest_method:: DELETE /flavors/{flavor_uuid}
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
be returned to the user under some operations.
Normal response codes: 204
Error response codes: unauthorized(401), forbidden(403), itemNotFound(404)
Request
-------
.. rest_parameters:: parameters.yaml
- flavor_uuid: flavor_uuid_path
Response
--------
No body content is returned on a successful DELETE.
List Extra Specs
================
.. rest_method:: GET /flavors/{flavor_uuid}/extraspecs
Lists all extra specs related to the given flavor.
Normal response codes: 200
Error response codes: unauthorized(401), forbidden(403)
Request
-------
.. rest_parameters:: parameters.yaml
- flavor_uuid: flavor_uuid_path
Response
--------
.. rest_parameters:: parameters.yaml
- extra_specs: flavor_extra_specs
**Example List Extra Specs**
.. literalinclude:: samples/flavors/flavor-extra-specs-list-resp.json
:language: javascript
Create/Update Extra Spec
========================
.. rest_method:: PATCH /flavors/{flavor_uuid}/extraspecs
Create/update extra specs to the given flavor.
Normal response codes: 201
Error response codes: unauthorized(401), forbidden(403)
Request
-------
.. rest_parameters:: parameters.yaml
- flavor_uuid: flavor_uuid_path
- extra_specs: flavor_extra_specs
**Example Create Extra Specs**
.. literalinclude:: samples/flavors/flavor-extra-specs-patch-req.json
:language: javascript
Response
--------
.. rest_parameters:: parameters.yaml
- extra_specs: flavor_extra_specs
**Example Create Extra Specs**
.. literalinclude:: samples/flavors/flavor-extra-specs-patch-resp.json
:language: javascript
Delete Extra Spec
=================
.. rest_method:: DELETE /flavors/{flavor_uuid}/extraspecs/key
Deletes an extra spec related to the specific flavor.
Normal response codes: 204
Error response codes: unauthorized(401), forbidden(403), itemNotFound(404)
Request
-------
.. rest_parameters:: parameters.yaml
- flavor_uuid: flavor_uuid_path
- key: spec_key_path
Response
--------
No body content is returned on a successful DELETE.

View File

@ -10,5 +10,5 @@ Baremetal Compute API V1 (CURRENT)
.. include:: instances.inc
.. include:: instance_states.inc
.. include:: instance_networks.inc
.. include:: instance_types.inc
.. include:: flavors.inc
.. include:: availability_zones.inc

View File

@ -1,303 +0,0 @@
.. -*- rst -*-
===============
Instance Type
===============
Show and manage Instance Types.
Types are a way to describe the basic dimensions of a instance to be
created including how much ``cpu``, ``ram``, and ``disk space`` are
allocated to an instance built with this type.
List Types
==========
.. rest_method:: GET /types
Lists all types accessible to your project.
Normal response codes: 200
Error response codes: unauthorized(401), forbidden(403)
Request
-------
Response
--------
.. rest_parameters:: parameters.yaml
- types: types
- name: type_name
- links: links
- description: type_description
- uuid: type_uuid
- created_at: created_at
- updated_at: updated_at
- is_public: type_is_public
- extra_specs: type_extra_specs
**Example List types**
.. literalinclude:: samples/instance_types/types-list-resp.json
:language: javascript
Create Instance Type
====================
.. rest_method:: POST /types
Creates a type.
Creating a type is typically only available to administrators of a
cloud because this has implications for scheduling efficiently in the cloud.
Normal response codes: 201
Error response codes: badRequest(400), unauthorized(401), forbidden(403),
conflict(409)
Request
-------
.. rest_parameters:: parameters.yaml
- name: type_name
- description: type_description
- is_public: type_is_public_not_required
- uuid: type_uuid_not_required
**Example Create Type**
.. literalinclude:: samples/instance_types/type-create-post-req.json
:language: javascript
Response
--------
.. rest_parameters:: parameters.yaml
- name: type_name
- links: links
- description: type_description
- uuid: type_uuid
- created_at: created_at
- updated_at: updated_at
- is_public: type_is_public
- extra_specs: type_extra_specs
**Example Create type**
.. literalinclude:: samples/instance_types/type-create-post-resp.json
:language: javascript
Update Instance Type
====================
.. rest_method:: PUT /types/{type_uuid}
Updates a type.
Updating a type is typically only available to administrators of a
cloud because this has implications for scheduling efficiently in the cloud.
Normal response codes: 200
Error response codes: badRequest(400), unauthorized(401), forbidden(403),
conflict(409)
Request
-------
.. rest_parameters:: parameters.yaml
- type_uuid: type_uuid_path
- name: type_name
- description: type_description
- is_public: type_is_public_not_required
**Example Update Type**
.. literalinclude:: samples/instance_types/type-update-put-req.json
:language: javascript
Response
--------
.. rest_parameters:: parameters.yaml
- name: type_name
- links: links
- description: type_description
- uuid: type_uuid
- created_at: created_at
- updated_at: updated_at
- is_public: type_is_public
- extra_specs: type_extra_specs
**Example Update type**
.. literalinclude:: samples/instance_types/type-update-put-resp.json
:language: javascript
Show Instance Type Details
==========================
.. rest_method:: GET /types/{type_uuid}
Shows details for a type.
Normal response codes: 200
Error response codes: unauthorized(401), forbidden(403), itemNotFound(404)
Request
-------
.. rest_parameters:: parameters.yaml
- type_uuid: type_uuid_path
Response
--------
.. rest_parameters:: parameters.yaml
- name: type_name
- links: links
- description: type_description
- uuid: type_uuid
- created_at: created_at
- updated_at: updated_at
- is_public: type_is_public
- extra_specs: type_extra_specs
**Example Show type Details**
.. literalinclude:: samples/instance_types/type-get-resp.json
:language: javascript
Delete Instance Type
====================
.. rest_method:: DELETE /types/{type_uuid}
Deletes a type.
This is typically an admin only action. Deleting a type that is in use by
existing instances is not recommended as it can cause incorrect data to
be returned to the user under some operations.
Normal response codes: 204
Error response codes: unauthorized(401), forbidden(403), itemNotFound(404)
Request
-------
.. rest_parameters:: parameters.yaml
- type_uuid: type_uuid_path
Response
--------
No body content is returned on a successful DELETE.
List Extra Specs
================
.. rest_method:: GET /types/{type_uuid}/extraspecs
Lists all extra specs related to the given type.
Normal response codes: 200
Error response codes: unauthorized(401), forbidden(403)
Request
-------
.. rest_parameters:: parameters.yaml
- type_uuid: type_uuid_path
Response
--------
.. rest_parameters:: parameters.yaml
- extra_specs: type_extra_specs
**Example List Extra Specs**
.. literalinclude:: samples/instance_types/type-extra-specs-list-resp.json
:language: javascript
Create/Update Extra Spec
========================
.. rest_method:: PATCH /types/{type_uuid}/extraspecs
Create/update extra specs to the given type.
Normal response codes: 201
Error response codes: unauthorized(401), forbidden(403)
Request
-------
.. rest_parameters:: parameters.yaml
- type_uuid: type_uuid_path
- extra_specs: type_extra_specs
**Example Create Extra Specs**
.. literalinclude:: samples/instance_types/type-extra-specs-patch-req.json
:language: javascript
Response
--------
.. rest_parameters:: parameters.yaml
- extra_specs: type_extra_specs
**Example Create Extra Specs**
.. literalinclude:: samples/instance_types/type-extra-specs-patch-resp.json
:language: javascript
Delete Extra Spec
=================
.. rest_method:: DELETE /types/{type_uuid}/extraspecs/key
Deletes an extra spec related to the specific type.
Normal response codes: 204
Error response codes: unauthorized(401), forbidden(403), itemNotFound(404)
Request
-------
.. rest_parameters:: parameters.yaml
- type_uuid: type_uuid_path
- key: spec_key_path
Response
--------
No body content is returned on a successful DELETE.

View File

@ -32,7 +32,7 @@ Request
- name: instance_name
- description: instance_description
- instance_type_uuid: typeRef
- instance_type_uuid: flavorRef
- image_uuid: imageRef
- availability_zone: availability_zone
- networks: networks
@ -53,7 +53,7 @@ Response
- name: instance_name
- description: instance_description
- instance_type_uuid: typeRef
- instance_type_uuid: flavorRef
- image_uuid: imageRef
- availability_zone: availability_zone
- network_info: network_info
@ -186,7 +186,7 @@ Response
- name: instance_name
- description: instance_description
- instance_type_uuid: typeRef
- instance_type_uuid: flavorRef
- image_uuid: imageRef
- availability_zone: availability_zone
- network_info: network_info
@ -236,7 +236,7 @@ Response
- name: instance_name
- description: instance_description
- instance_type_uuid: typeRef
- instance_type_uuid: flavorRef
- image_uuid: imageRef
- availability_zone: availability_zone
- network_info: network_info
@ -291,7 +291,7 @@ Response
- name: instance_name
- description: instance_description
- instance_type_uuid: typeRef
- instance_type_uuid: flavorRef
- image_uuid: imageRef
- availability_zone: availability_zone
- network_info: network_info

View File

@ -21,6 +21,12 @@ api_version:
type: string
description: >
The API version as returned in the links from the ``GET /`` call.
flavor_uuid_path:
description: |
The UUID of the flavor.
in: path
required: true
type: string
instance_ident:
description: |
The UUID of the instance.
@ -33,12 +39,6 @@ spec_key_path:
in: path
required: true
type: string
type_uuid_path:
description: |
The UUID of the type.
in: path
required: true
type: string
# variables in query
all_tenants:
@ -125,6 +125,62 @@ fixed_address:
in: body
required: false
type: string
flavor_description:
description: |
The description of the flavor.
in: body
required: true
type: string
flavor_extra_specs:
description: |
Extra spec key and value pairs associate with the flavor.
in: body
required: true
type: object
flavor_is_public:
description: |
Whether the flavor is public (available to all projects) or scoped
to a set of projects. Default is True if not specified.
in: body
required: true
type: boolean
flavor_is_public_not_required:
description: |
Whether the flavor is public (available to all projects) or scoped
to a set of projects. Default is True if not specified.
in: body
required: true
type: boolean
flavor_name:
description: |
The name of the flavor.
in: body
required: true
type: string
flavor_uuid:
description: |
The UUID of the flavor.
in: body
required: true
type: string
flavor_uuid_not_required:
description: |
The UUID of the flavor.
in: body
required: false
type: string
flavorRef:
description: |
The flavor reference, as a UUID for the flavor for your server instance.
in: body
required: true
type: string
flavors:
description: |
An array of flavor objects.
in: body
required: true
type: array
imageRef:
description: |
The UUID of the image to use for your instance.
@ -275,62 +331,6 @@ provision_state:
in: body
required: true
type: string
type_description:
description: |
The description of the type.
in: body
required: true
type: string
type_extra_specs:
description: |
Extra spec key and value pairs associate with the type.
in: body
required: true
type: object
type_is_public:
description: |
Whether the type is public (available to all projects) or scoped
to a set of projects. Default is True if not specified.
in: body
required: true
type: boolean
type_is_public_not_required:
description: |
Whether the type is public (available to all projects) or scoped
to a set of projects. Default is True if not specified.
in: body
required: true
type: boolean
type_name:
description: |
The name of the type.
in: body
required: true
type: string
type_uuid:
description: |
The UUID of the type.
in: body
required: true
type: string
type_uuid_not_required:
description: |
The UUID of the type.
in: body
required: false
type: string
typeRef:
description: |
The type reference, as a UUID or full URL, for the type for your server instance.
in: body
required: true
type: string
types:
description: |
An array of type objects.
in: body
required: true
type: array
updated_at:
description: |
The date and time when the resource was updated. The date and time

View File

@ -0,0 +1,5 @@
{
"name": "test_flavor",
"description": "this is a test flavor",
"is_public": true
}

View File

@ -1,12 +1,12 @@
{
"description": "this is a test type",
"description": "this is a test flavor",
"links": [
{
"href": "http://10.3.150.17:6688/v1/types/7de2859d-ec6d-42c7-bb86-9d630ba5ac94",
"href": "http://10.3.150.17:6688/v1/flavors/7de2859d-ec6d-42c7-bb86-9d630ba5ac94",
"rel": "self"
},
{
"href": "http://10.3.150.17:6688/types/7de2859d-ec6d-42c7-bb86-9d630ba5ac94",
"href": "http://10.3.150.17:6688/flavors/7de2859d-ec6d-42c7-bb86-9d630ba5ac94",
"rel": "bookmark"
}
],
@ -15,5 +15,5 @@
"updated_at": null,
"extra_specs": {},
"is_public": true,
"name": "test_type"
"name": "test_flavor"
}

View File

@ -1,12 +1,12 @@
{
"description": "this is a test type",
"description": "this is a test flavor",
"links": [
{
"href": "http://10.3.150.17:6688/v1/types/7de2859d-ec6d-42c7-bb86-9d630ba5ac94",
"href": "http://10.3.150.17:6688/v1/flavors/7de2859d-ec6d-42c7-bb86-9d630ba5ac94",
"rel": "self"
},
{
"href": "http://10.3.150.17:6688/types/7de2859d-ec6d-42c7-bb86-9d630ba5ac94",
"href": "http://10.3.150.17:6688/flavors/7de2859d-ec6d-42c7-bb86-9d630ba5ac94",
"rel": "bookmark"
}
],
@ -15,5 +15,5 @@
"updated_at": null,
"extra_specs": {},
"is_public": true,
"name": "test_type"
"name": "test_flavor"
}

View File

@ -0,0 +1,5 @@
{
"name": "updated_flavor",
"description": "this is a flavor to be updated",
"is_public": false
}

View File

@ -1,12 +1,12 @@
{
"description": "this is a type to be updated",
"description": "this is a flavor to be updated",
"links": [
{
"href": "http://10.3.150.17:6688/v1/types/7de2859d-ec6d-42c7-bb86-9d630ba5ac94",
"href": "http://10.3.150.17:6688/v1/flavors/7de2859d-ec6d-42c7-bb86-9d630ba5ac94",
"rel": "self"
},
{
"href": "http://10.3.150.17:6688/types/7de2859d-ec6d-42c7-bb86-9d630ba5ac94",
"href": "http://10.3.150.17:6688/flavors/7de2859d-ec6d-42c7-bb86-9d630ba5ac94",
"rel": "bookmark"
}
],
@ -15,5 +15,5 @@
"updated_at": null,
"extra_specs": {},
"is_public": false,
"name": "updated_type"
"name": "updated_flavor"
}

View File

@ -1,14 +1,14 @@
{
"types": [
"flavors": [
{
"description": "this is a test type1",
"description": "this is a test flavor1",
"links": [
{
"href": "http://10.3.150.17:6688/v1/types/2ce3df6b-f571-42e8-b6a8-8f7fa1c019ce",
"href": "http://10.3.150.17:6688/v1/flavors/2ce3df6b-f571-42e8-b6a8-8f7fa1c019ce",
"rel": "self"
},
{
"href": "http://10.3.150.17:6688/types/2ce3df6b-f571-42e8-b6a8-8f7fa1c019ce",
"href": "http://10.3.150.17:6688/flavors/2ce3df6b-f571-42e8-b6a8-8f7fa1c019ce",
"rel": "bookmark"
}
],
@ -22,14 +22,14 @@
"name": "new_test1"
},
{
"description": "this is a test type2",
"description": "this is a test flavor2",
"links": [
{
"href": "http://10.3.150.17:6688/v1/types/7de2859d-ec6d-42c7-bb86-9d630ba5ac94",
"href": "http://10.3.150.17:6688/v1/flavors/7de2859d-ec6d-42c7-bb86-9d630ba5ac94",
"rel": "self"
},
{
"href": "http://10.3.150.17:6688/types/7de2859d-ec6d-42c7-bb86-9d630ba5ac94",
"href": "http://10.3.150.17:6688/flavors/7de2859d-ec6d-42c7-bb86-9d630ba5ac94",
"rel": "bookmark"
}
],

View File

@ -1,5 +0,0 @@
{
"name": "test_type",
"description": "this is a test type",
"is_public": true
}

View File

@ -1,5 +0,0 @@
{
"name": "updated_type",
"description": "this is a type to be updated",
"is_public": false
}

View File

@ -181,15 +181,15 @@ function _mogan_cleanup_mogan_dashboard {
}
function create_instance_type {
openstack baremetal flavor create ${MOGAN_DEFAULT_INSTANCE_TYPE} --description 'Mogan default instance type'
function create_flavor {
openstack baremetal flavor create ${MOGAN_DEFAULT_FLAVOR} --description 'Mogan default flavor'
}
function update_ironic_node_type {
ironic_nodes=$(openstack baremetal node list -c UUID -f value)
for node in ${ironic_nodes};do
openstack baremetal node set --property node_type=${MOGAN_DEFAULT_INSTANCE_TYPE} ${node}
openstack baremetal node set --property node_type=${MOGAN_DEFAULT_FLAVOR} ${node}
done
}
@ -212,7 +212,7 @@ if is_service_enabled mogan; then
init_mogan
start_mogan
echo_summary "Creating instance type"
create_instance_type
create_flavor
echo_summary "Updating ironic node properties"
update_ironic_node_type
fi

View File

@ -27,4 +27,4 @@ MOGAN_SERVICE_PORT=${MOGAN_SERVICE_PORT:-6688}
MOGAN_SERVICE_PROTOCOL=${MOGAN_SERVICE_PROTOCOL:-$SERVICE_PROTOCOL}
MOGAN_ADMIN_USER=${MOGAN_ADMIN_USER:-mogan}
MOGAN_DEFAULT_INSTANCE_TYPE=${MOGAN_DEFAULT_INSTANCE_TYPE:-small}
MOGAN_DEFAULT_FLAVOR=${MOGAN_DEFAULT_FLAVOR:-small}

View File

@ -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 import availability_zone
from mogan.api.controllers.v1 import instance_types
from mogan.api.controllers.v1 import flavors
from mogan.api.controllers.v1 import instances
from mogan.api import expose
@ -40,7 +40,7 @@ class V1(base.APIBase):
instances = [link.Link]
"""Links to the instances resource"""
types = [link.Link]
flavors = [link.Link]
"""Links to the instance types resource"""
availability_zones = [link.Link]
@ -57,13 +57,13 @@ class V1(base.APIBase):
'instances', '',
bookmark=True)
]
v1.types = [link.Link.make_link('self', pecan.request.public_url,
'types', ''),
link.Link.make_link('bookmark',
pecan.request.public_url,
'types', '',
bookmark=True)
]
v1.flavors = [link.Link.make_link('self', pecan.request.public_url,
'flavors', ''),
link.Link.make_link('bookmark',
pecan.request.public_url,
'flavors', '',
bookmark=True)
]
v1.availability_zones = [link.Link.make_link('self',
pecan.request.public_url,
'availability_zones', ''),
@ -78,7 +78,7 @@ class V1(base.APIBase):
class Controller(rest.RestController):
"""Version 1 API controller root."""
types = instance_types.InstanceTypeController()
flavors = flavors.FlavorsController()
instances = instances.InstanceController()
availability_zones = availability_zone.AvailabilityZoneController()

View File

@ -0,0 +1,201 @@
# Copyright 2016 Huawei Technologies Co.,LTD.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import pecan
from pecan import rest
from six.moves import http_client
import wsme
from wsme import types as wtypes
from mogan.api.controllers import base
from mogan.api.controllers import link
from mogan.api.controllers.v1 import types
from mogan.api import expose
from mogan.common import exception
from mogan.common.i18n import _
from mogan import objects
class Flavor(base.APIBase):
"""API representation of a flavor.
This class enforces type checking and value constraints, and converts
between the internal object model and the API representation of
a flavor.
"""
uuid = types.uuid
"""The UUID of the flavor"""
name = wtypes.text
"""The name of the flavor"""
description = wtypes.text
"""The description of the flavor"""
is_public = types.boolean
"""Indicates whether the flavor is public."""
extra_specs = {wtypes.text: types.jsontype}
"""The extra specs of the flavor"""
links = wsme.wsattr([link.Link], readonly=True)
"""A list containing a self link"""
def __init__(self, **kwargs):
self.fields = []
for field in objects.InstanceType.fields:
# Skip fields we do not expose.
if not hasattr(self, field):
continue
self.fields.append(field)
setattr(self, field, kwargs.get(field, wtypes.Unset))
@classmethod
def convert_with_links(cls, rpc_flavor):
flavor = Flavor(**rpc_flavor.as_dict())
url = pecan.request.public_url
flavor.links = [link.Link.make_link('self', url,
'flavors',
flavor.uuid),
link.Link.make_link('bookmark', url,
'flavors',
flavor.uuid,
bookmark=True)
]
return flavor
class FlavorCollection(base.APIBase):
"""API representation of a collection of flavor."""
flavors = [Flavor]
"""A list containing Flavor objects"""
@staticmethod
def convert_with_links(flavors, url=None, **kwargs):
collection = FlavorCollection()
collection.flavors = [Flavor.convert_with_links(flavor)
for flavor in flavors]
return collection
class FlavorExtraSpecsController(rest.RestController):
"""REST controller for flavor extra specs."""
@expose.expose(wtypes.text, types.uuid)
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)
return dict(extra_specs=flavor.extra_specs)
@expose.expose(types.jsontype, types.uuid, body=types.jsontype,
status_code=http_client.ACCEPTED)
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.extra_specs = dict(flavor.extra_specs, **extra_spec)
flavor.save()
return dict(extra_specs=flavor.extra_specs)
@expose.expose(None, types.uuid, wtypes.text,
status_code=http_client.NO_CONTENT)
def delete(self, flavor_uuid, spec_name):
"""Delete an extra specs for the given flavor."""
flavor = objects.InstanceType.get(pecan.request.context,
flavor_uuid)
del flavor.extra_specs[spec_name]
flavor.save()
class FlavorsController(rest.RestController):
"""REST controller for Flavors."""
extraspecs = FlavorExtraSpecsController()
@expose.expose(FlavorCollection)
def get_all(self):
"""Retrieve a list of flavor."""
flavors = objects.InstanceType.list(pecan.request.context)
return FlavorCollection.convert_with_links(flavors)
@expose.expose(Flavor, types.uuid)
def get_one(self, flavor_uuid):
"""Retrieve information about the given flavor.
:param flavor_uuid: UUID of a flavor.
"""
rpc_flavor = objects.InstanceType.get(pecan.request.context,
flavor_uuid)
return Flavor.convert_with_links(rpc_flavor)
@expose.expose(Flavor, body=Flavor,
status_code=http_client.CREATED)
def post(self, flavor):
"""Create an new flavor.
:param flavor: a flavor within the request body.
"""
new_flavor = objects.InstanceType(pecan.request.context,
**flavor.as_dict())
new_flavor.create()
# Set the HTTP Location Header
pecan.response.location = link.build_url('flavors',
new_flavor.uuid)
return Flavor.convert_with_links(new_flavor)
@expose.expose(Flavor, types.uuid, body=Flavor)
def put(self, flavor_uuid, flavor):
"""Update a flavor.
:param flavor_uuid: the uuid of the flavor to be updated.
:param flavor: a flavor within the request body.
"""
try:
flavor_in_db = objects.InstanceType.get(
pecan.request.context, flavor_uuid)
except exception.InstanceTypeNotFound:
msg = (_("InstanceType %s could not be found") %
flavor_uuid)
raise wsme.exc.ClientSideError(
msg, status_code=http_client.BAD_REQUEST)
need_to_update = False
for attr in ('name', 'description', 'is_public'):
if getattr(flavor, attr) != wtypes.Unset:
need_to_update = True
setattr(flavor_in_db, attr, getattr(flavor, attr))
# don't need to call db_api if no update
if need_to_update:
flavor_in_db.save()
# Set the HTTP Location Header
pecan.response.location = link.build_url('flavor',
flavor_in_db.uuid)
return Flavor.convert_with_links(flavor_in_db)
@expose.expose(None, types.uuid, status_code=http_client.NO_CONTENT)
def delete(self, flavor_uuid):
"""Delete a flavor.
:param flavor_uuid: UUID of a flavor.
"""
rpc_flavor = objects.InstanceType.get(pecan.request.context,
flavor_uuid)
rpc_flavor.destroy()

View File

@ -1,202 +0,0 @@
# Copyright 2016 Huawei Technologies Co.,LTD.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import pecan
from pecan import rest
from six.moves import http_client
import wsme
from wsme import types as wtypes
from mogan.api.controllers import base
from mogan.api.controllers import link
from mogan.api.controllers.v1 import types
from mogan.api import expose
from mogan.common import exception
from mogan.common.i18n import _
from mogan import objects
class InstanceType(base.APIBase):
"""API representation of an instance type.
This class enforces type checking and value constraints, and converts
between the internal object model and the API representation of
an instance type.
"""
uuid = types.uuid
"""The UUID of the instance type"""
name = wtypes.text
"""The name of the instance type"""
description = wtypes.text
"""The description of the instance type"""
is_public = types.boolean
"""Indicates whether the instance type is public."""
extra_specs = {wtypes.text: types.jsontype}
"""The extra specs of the instance type"""
links = wsme.wsattr([link.Link], readonly=True)
"""A list containing a self link"""
def __init__(self, **kwargs):
self.fields = []
for field in objects.InstanceType.fields:
# Skip fields we do not expose.
if not hasattr(self, field):
continue
self.fields.append(field)
setattr(self, field, kwargs.get(field, wtypes.Unset))
@classmethod
def convert_with_links(cls, rpc_instance_type):
instance_type = InstanceType(**rpc_instance_type.as_dict())
url = pecan.request.public_url
instance_type.links = [link.Link.make_link('self', url,
'types',
instance_type.uuid),
link.Link.make_link('bookmark', url,
'types',
instance_type.uuid,
bookmark=True)
]
return instance_type
class InstanceTypeCollection(base.APIBase):
"""API representation of a collection of instance type."""
types = [InstanceType]
"""A list containing Instance Type objects"""
@staticmethod
def convert_with_links(instance_types, url=None, **kwargs):
collection = InstanceTypeCollection()
collection.types = [InstanceType.convert_with_links(type1)
for type1 in instance_types]
return collection
class TypeExtraSpecController(rest.RestController):
"""REST controller for Instance Type extra spec."""
@expose.expose(wtypes.text, types.uuid)
def get_all(self, instance_type_uuid):
"""Retrieve a list of extra specs of the queried instance type."""
instance_type = objects.InstanceType.get(pecan.request.context,
instance_type_uuid)
return dict(extra_specs=instance_type.extra_specs)
@expose.expose(types.jsontype, types.uuid, body=types.jsontype,
status_code=http_client.ACCEPTED)
def patch(self, instance_type_uuid, extra_spec):
"""Create/update extra specs for the given instance type."""
instance_type = objects.InstanceType.get(pecan.request.context,
instance_type_uuid)
instance_type.extra_specs = dict(instance_type.extra_specs,
**extra_spec)
instance_type.save()
return dict(extra_specs=instance_type.extra_specs)
@expose.expose(None, types.uuid, wtypes.text,
status_code=http_client.NO_CONTENT)
def delete(self, instance_type_uuid, spec_name):
"""Delete an extra specs for the given instance type."""
instance_type = objects.InstanceType.get(pecan.request.context,
instance_type_uuid)
del instance_type.extra_specs[spec_name]
instance_type.save()
class InstanceTypeController(rest.RestController):
"""REST controller for Instance Type."""
extraspecs = TypeExtraSpecController()
@expose.expose(InstanceTypeCollection)
def get_all(self):
"""Retrieve a list of instance type."""
instance_types = objects.InstanceType.list(pecan.request.context)
return InstanceTypeCollection.convert_with_links(instance_types)
@expose.expose(InstanceType, types.uuid)
def get_one(self, instance_type_uuid):
"""Retrieve information about the given instance type.
:param instance_type_uuid: UUID of a instance type.
"""
rpc_instance_type = objects.InstanceType.get(pecan.request.context,
instance_type_uuid)
return InstanceType.convert_with_links(rpc_instance_type)
@expose.expose(InstanceType, body=InstanceType,
status_code=http_client.CREATED)
def post(self, instance_type):
"""Create an new instance type.
:param instance_type: a instance type within the request body.
"""
new_instance_type = objects.InstanceType(pecan.request.context,
**instance_type.as_dict())
new_instance_type.create()
# Set the HTTP Location Header
pecan.response.location = link.build_url('types',
new_instance_type.uuid)
return InstanceType.convert_with_links(new_instance_type)
@expose.expose(InstanceType, types.uuid, body=InstanceType)
def put(self, instance_type_uuid, instance_type):
"""Update an instance type.
:param instance_type_uuid: the uuid of instance_type to be updated.
:param instance_type: a instance type within the request body.
"""
try:
inst_type_in_db = objects.InstanceType.get(
pecan.request.context, instance_type_uuid)
except exception.InstanceTypeNotFound:
msg = (_("InstanceType %s could not be found") %
instance_type_uuid)
raise wsme.exc.ClientSideError(
msg, status_code=http_client.BAD_REQUEST)
need_to_update = False
for attr in ('name', 'description', 'is_public'):
if getattr(instance_type, attr) != wtypes.Unset:
need_to_update = True
setattr(inst_type_in_db, attr, getattr(instance_type, attr))
# don't need to call db_api if no update
if need_to_update:
inst_type_in_db.save()
# Set the HTTP Location Header
pecan.response.location = link.build_url('instance_type',
inst_type_in_db.uuid)
return InstanceType.convert_with_links(inst_type_in_db)
@expose.expose(None, types.uuid, status_code=http_client.NO_CONTENT)
def delete(self, instance_type_uuid):
"""Delete an instance type.
:param instance_type_uuid: UUID of an instance type.
"""
rpc_instance_type = objects.InstanceType.get(pecan.request.context,
instance_type_uuid)
rpc_instance_type.destroy()

View File

@ -1,4 +1,3 @@
#
# Copyright 2016 Huawei Technologies Co., Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -21,27 +20,27 @@ from oslo_serialization import jsonutils
from mogan.tests.functional.api import v1 as v1_test
class TestInstanceType(v1_test.APITestV1):
class TestFlavor(v1_test.APITestV1):
TYPE_UUIDS = ['ff28b5a2-73e5-431c-b4b7-1b96b74bca7b',
'94baf80e-2bae-4c3e-8dab-38b5441e7097',
'4bcfff85-c55a-493b-b544-b6c90b8fb397',
'e50fb289-4ee1-47dd-b371-6ca39af12888']
FLAVOR_UUIDS = ['ff28b5a2-73e5-431c-b4b7-1b96b74bca7b',
'94baf80e-2bae-4c3e-8dab-38b5441e7097',
'4bcfff85-c55a-493b-b544-b6c90b8fb397',
'e50fb289-4ee1-47dd-b371-6ca39af12888']
def setUp(self):
super(TestInstanceType, self).setUp()
super(TestFlavor, self).setUp()
@mock.patch('oslo_utils.uuidutils.generate_uuid')
def _prepare_instance_types(self, mocked):
mocked.side_effect = self.TYPE_UUIDS
def _prepare_flavors(self, mocked):
mocked.side_effect = self.FLAVOR_UUIDS
for i in six.moves.xrange(4):
body = {"name": "test" + str(i),
"description": "just test" + str(i)}
self.post_json('/types', body, status=201)
self.post_json('/flavors', body, status=201)
def test_instance_type_post(self):
def test_flavor_post(self):
body = {"name": "test", "description": "just test"}
resp = self.post_json('/types', body, status=201)
resp = self.post_json('/flavors', body, status=201)
resp = resp.json
self.assertEqual('test', resp['name'])
self.assertEqual('just test', resp['description'])
@ -50,76 +49,76 @@ class TestInstanceType(v1_test.APITestV1):
self.assertIn('extra_specs', resp)
self.assertIn('links', resp)
def test_instance_type_get_all(self):
self._prepare_instance_types()
resp = self.get_json('/types')
self.assertEqual(4, len(resp['types']))
def test_flavor_get_all(self):
self._prepare_flavors()
resp = self.get_json('/flavors')
self.assertEqual(4, len(resp['flavors']))
def test_instance_type_get_one(self):
self._prepare_instance_types()
resp = self.get_json('/types/' + self.TYPE_UUIDS[0])
def test_flavor_get_one(self):
self._prepare_flavors()
resp = self.get_json('/flavors/' + self.FLAVOR_UUIDS[0])
self.assertEqual('test0', resp['name'])
self.assertEqual('just test0', resp['description'])
def test_instance_type_delete(self):
self._prepare_instance_types()
resp = self.get_json('/types')
self.assertEqual(4, len(resp['types']))
self.delete('/types/' + self.TYPE_UUIDS[0], status=204)
resp = self.get_json('/types')
self.assertEqual(3, len(resp['types']))
def test_flavor_delete(self):
self._prepare_flavors()
resp = self.get_json('/flavors')
self.assertEqual(4, len(resp['flavors']))
self.delete('/flavors/' + self.FLAVOR_UUIDS[0], status=204)
resp = self.get_json('/flavors')
self.assertEqual(3, len(resp['flavors']))
def test_instance_type_update(self):
self._prepare_instance_types()
resp = self.get_json('/types/' + self.TYPE_UUIDS[0])
def test_flavor_update(self):
self._prepare_flavors()
resp = self.get_json('/flavors/' + self.FLAVOR_UUIDS[0])
self.assertEqual('test0', resp['name'])
self.assertEqual('just test0', resp['description'])
values = {"name": "update_name", "description": "updated_description",
"is_public": False}
self.put_json('/types/' + self.TYPE_UUIDS[0], values, status=200)
resp = self.get_json('/types/' + self.TYPE_UUIDS[0])
self.put_json('/flavors/' + self.FLAVOR_UUIDS[0], values, status=200)
resp = self.get_json('/flavors/' + self.FLAVOR_UUIDS[0])
self.assertEqual('update_name', resp['name'])
self.assertEqual('updated_description', resp['description'])
self.assertEqual(False, resp['is_public'])
class TestInstanceTypeExtra(v1_test.APITestV1):
TYPE_UUID = 'ff28b5a2-73e5-431c-b4b7-1b96b74bca7b'
class TestFlavorExtra(v1_test.APITestV1):
FLAVOR_UUID = 'ff28b5a2-73e5-431c-b4b7-1b96b74bca7b'
def setUp(self):
super(TestInstanceTypeExtra, self).setUp()
self._prepare_instance_type()
super(TestFlavorExtra, self).setUp()
self._prepare_flavor()
@mock.patch('oslo_utils.uuidutils.generate_uuid')
def _prepare_instance_type(self, mocked):
mocked.return_value = self.TYPE_UUID
body = {"name": "test_type_extra",
"description": "just test type extra"}
self.post_json('/types', body, status=201)
def _prepare_flavor(self, mocked):
mocked.return_value = self.FLAVOR_UUID
body = {"name": "test_flavor_extra",
"description": "just test flavor extra"}
self.post_json('/flavors', body, status=201)
def test_list_extra_empty(self):
resp = self.get_json('/types/%s/extraspecs' % self.TYPE_UUID)
resp = self.get_json('/flavors/%s/extraspecs' % self.FLAVOR_UUID)
self.assertEqual({}, resp['extra_specs'])
def test_add_extra(self):
resp = self.patch_json('/types/%s/extraspecs' % self.TYPE_UUID,
resp = self.patch_json('/flavors/%s/extraspecs' % self.FLAVOR_UUID,
{'test_key': 'test_value'})
resp = resp.json
self.assertEqual({'extra_specs': {'test_key': 'test_value'}}, resp)
def test_update_extra(self):
resp = self.patch_json('/types/%s/extraspecs' % self.TYPE_UUID,
resp = self.patch_json('/flavors/%s/extraspecs' % self.FLAVOR_UUID,
{'test_key': 'test_value1'})
resp = resp.json
self.assertEqual({'extra_specs': {'test_key': 'test_value1'}}, resp)
resp = self.patch_json('/types/%s/extraspecs' % self.TYPE_UUID,
resp = self.patch_json('/flavors/%s/extraspecs' % self.FLAVOR_UUID,
{'test_key': 'test_value2'})
resp = resp.json
self.assertEqual({'extra_specs': {'test_key': 'test_value2'}}, resp)
def test_list_extra(self):
resp = self.patch_json('/types/%s/extraspecs' % self.TYPE_UUID,
resp = self.patch_json('/flavors/%s/extraspecs' % self.FLAVOR_UUID,
{'test_key1': 'test_value1',
'test_key2': 'test_value2'})
resp = resp.json
@ -127,16 +126,16 @@ class TestInstanceTypeExtra(v1_test.APITestV1):
'{"test_key1": "test_value1", "test_key2": "test_value2"}',
jsonutils.dumps(resp['extra_specs'], sort_keys=True))
self.patch_json('/types/%s/extraspecs' % self.TYPE_UUID,
self.patch_json('/flavors/%s/extraspecs' % self.FLAVOR_UUID,
{'test_key3': 'test_value3'})
resp = self.get_json('/types/%s/extraspecs' % self.TYPE_UUID)
resp = self.get_json('/flavors/%s/extraspecs' % self.FLAVOR_UUID)
self.assertEqual(
'{"test_key1": "test_value1", "test_key2": "test_value2", '
'"test_key3": "test_value3"}',
jsonutils.dumps(resp['extra_specs'], sort_keys=True))
def test_delete_extra(self):
resp = self.patch_json('/types/%s/extraspecs' % self.TYPE_UUID,
resp = self.patch_json('/flavors/%s/extraspecs' % self.FLAVOR_UUID,
{'test_key1': 'test_value1',
'test_key2': 'test_value2'})
resp = resp.json
@ -144,6 +143,6 @@ class TestInstanceTypeExtra(v1_test.APITestV1):
'{"test_key1": "test_value1", "test_key2": "test_value2"}',
jsonutils.dumps(resp['extra_specs'], sort_keys=True))
self.delete('/types/%s/extraspecs/test_key1' % self.TYPE_UUID)
resp = self.get_json('/types/%s/extraspecs' % self.TYPE_UUID)
self.delete('/flavors/%s/extraspecs/test_key1' % self.FLAVOR_UUID)
resp = self.get_json('/flavors/%s/extraspecs' % self.FLAVOR_UUID)
self.assertEqual({'test_key2': 'test_value2'}, resp['extra_specs'])

View File

@ -101,7 +101,7 @@ class TestInstances(v1_test.APITestV1):
expect_errors=True)
def _clean_type(self):
self.delete('/types/' + self.INSTANCE_TYPE_UUID, status=204)
self.delete('/flavors/' + self.INSTANCE_TYPE_UUID, status=204)
def _make_app(self):
return super(TestInstances, self)._make_app()
@ -111,7 +111,7 @@ class TestInstances(v1_test.APITestV1):
mocked.side_effect = [self.INSTANCE_TYPE_UUID]
body = {"name": "type_for_instance_testing",
"description": "type for instance testing"}
self.post_json('/types', body, status=201)
self.post_json('/flavors', body, status=201)
@mock.patch('oslo_utils.uuidutils.generate_uuid')
def _prepare_instance(self, amount, mocked):

View File

@ -50,10 +50,10 @@ class BaseBaremetalComputeTest(tempest.test.BaseTestCase):
@classmethod
def _get_small_flavor(cls):
types = cls.baremetal_compute_client.list_instance_types()
for t in types:
if t['name'] == 'small':
return t['uuid']
flavors = cls.baremetal_compute_client.list_flavors()
for f in flavors:
if f['name'] == 'small':
return f['uuid']
else:
# TODO(liusheng) we shouldn't depend on the default
# type created by devstack
@ -70,7 +70,7 @@ class BaseBaremetalComputeTest(tempest.test.BaseTestCase):
@classmethod
def resource_setup(cls):
super(BaseBaremetalComputeTest, cls).resource_setup()
cls.type_ids = []
cls.flavor_ids = []
cls.instance_ids = []
cls.small_flavor = cls._get_small_flavor()
cls.image_id = CONF.compute.image_ref
@ -129,7 +129,7 @@ class BaseBaremetalComputeTest(tempest.test.BaseTestCase):
@classmethod
def resource_cleanup(cls):
cls.cleanup_resources(
cls.baremetal_compute_client.delete_instance_type, cls.type_ids)
cls.baremetal_compute_client.delete_flavor, cls.flavor_ids)
cls.cleanup_resources(cls.baremetal_compute_client.delete_instance,
cls.instance_ids)
super(BaseBaremetalComputeTest, cls).resource_cleanup()

View File

@ -1,4 +1,3 @@
#
# Copyright 2016 Huawei Technologies Co., Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -28,48 +27,48 @@ class BaremetalComputeAPITest(base.BaseBaremetalComputeTest):
def resource_setup(cls):
super(BaremetalComputeAPITest, cls).resource_setup()
for i in six.moves.xrange(3):
body = {"name": data_utils.rand_name('mogan_instance_type'),
"description": "mogan instance type description",
body = {"name": data_utils.rand_name('mogan_flavor'),
"description": "mogan flavor description",
'is_public': bool(data_utils.rand_int_id(0, 1))}
resp = cls.baremetal_compute_client.create_instance_type(**body)
cls.type_ids.append(resp['uuid'])
resp = cls.baremetal_compute_client.create_flavor(**body)
cls.flavor_ids.append(resp['uuid'])
@decorators.idempotent_id('4b256d35-47a9-4195-8f7e-56ceb4ce4737')
def test_type_list(self):
def test_flavor_list(self):
# List instance types
type_list = self.baremetal_compute_client.list_instance_types()
flavor_list = self.baremetal_compute_client.list_flavors()
# Verify created instance type in the list
fetched_ids = [t['uuid'] for t in type_list]
missing_types = [a for a in self.type_ids if a not in fetched_ids]
self.assertEqual(0, len(missing_types),
fetched_ids = [f['uuid'] for f in flavor_list]
missing_flavors = [a for a in self.flavor_ids if a not in fetched_ids]
self.assertEqual(0, len(missing_flavors),
"Failed to find the following created"
" instance_type(s) in a fetched list: %s" %
', '.join(str(t) for t in missing_types))
" flavor(s) in a fetched list: %s" %
', '.join(str(t) for t in missing_flavors))
@decorators.idempotent_id('f6ad64af-abc9-456c-9109-bc27cd9af635')
def test_type_create_show_delete(self):
# Create an instance type
body = {"name": 'mogan_type_create',
"description": "mogan instance type description",
def test_flavor_create_show_delete(self):
# Create a flavor
body = {"name": 'mogan_flavor_create',
"description": "mogan flavor description",
'is_public': True}
resp = self.baremetal_compute_client.create_instance_type(**body)
self.assertEqual('mogan_type_create', resp['name'])
self.assertEqual('mogan instance type description',
resp = self.baremetal_compute_client.create_flavor(**body)
self.assertEqual('mogan_flavor_create', resp['name'])
self.assertEqual('mogan flavor description',
resp['description'])
self.assertEqual(True, resp['is_public'])
self.assertIn('uuid', resp)
self.assertIn('extra_specs', resp)
self.assertIn('links', resp)
resp = self.baremetal_compute_client.show_instance_type(resp['uuid'])
self.assertEqual('mogan_type_create', resp['name'])
self.assertEqual('mogan instance type description',
resp = self.baremetal_compute_client.show_flavor(resp['uuid'])
self.assertEqual('mogan_flavor_create', resp['name'])
self.assertEqual('mogan flavor description',
resp['description'])
self.assertEqual(True, resp['is_public'])
self.assertIn('uuid', resp)
self.assertIn('extra_specs', resp)
self.assertIn('links', resp)
self.baremetal_compute_client.delete_instance_type(resp['uuid'])
self.baremetal_compute_client.delete_flavor(resp['uuid'])
self.assertRaises(lib_exc.NotFound,
self.baremetal_compute_client.show_instance_type,
self.baremetal_compute_client.show_flavor,
resp['uuid'])

View File

@ -36,30 +36,30 @@ class BaremetalComputeClient(rest_client.RestClient):
def serialize(self, body):
return json.dumps(body)
def list_instance_types(self):
uri = '%s/types' % self.uri_prefix
def list_flavors(self):
uri = '%s/flavors' % self.uri_prefix
resp, body = self.get(uri)
self.expected_success(200, resp.status)
body = self.deserialize(body)['types']
body = self.deserialize(body)['flavors']
return rest_client.ResponseBodyList(resp, body)
def show_instance_type(self, type_id):
uri = '%s/types/%s' % (self.uri_prefix, type_id)
def show_flavor(self, flavor_uuid):
uri = '%s/flavors/%s' % (self.uri_prefix, flavor_uuid)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
body = self.deserialize(body)
return rest_client.ResponseBody(resp, body)
def delete_instance_type(self, type_id):
uri = "%s/types/%s" % (self.uri_prefix, type_id)
def delete_flavor(self, flavor_uuid):
uri = "%s/flavors/%s" % (self.uri_prefix, flavor_uuid)
resp, body = self.delete(uri)
self.expected_success(204, resp.status)
if body:
body = self.deserialize(body)
return rest_client.ResponseBody(resp, body)
def create_instance_type(self, **kwargs):
uri = "%s/types" % self.uri_prefix
def create_flavor(self, **kwargs):
uri = "%s/flavors" % self.uri_prefix
body = self.serialize(kwargs)
resp, body = self.post(uri, body)
self.expected_success(201, resp.status)