api: Add response body schemas for remaining server action APIs
This demonstrates far more complex response schemas, including the response to the rebuild action which is effectively the response to the server show API. Change-Id: I6dc355f3c3f164d0bc7887a58e8b13979f0b476e Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
parent
908d9263ee
commit
b967f2a693
@ -2,7 +2,7 @@
|
||||
"flavor_access": [
|
||||
{
|
||||
"flavor_id": "10",
|
||||
"tenant_id": "fake_tenant"
|
||||
"tenant_id": "6f70656e737461636b20342065766572"
|
||||
}
|
||||
]
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
"flavor_access": [
|
||||
{
|
||||
"flavor_id": "10",
|
||||
"tenant_id": "fake_tenant"
|
||||
"tenant_id": "6f70656e737461636b20342065766572"
|
||||
}
|
||||
]
|
||||
}
|
@ -13,7 +13,7 @@
|
||||
"extra_specs": {
|
||||
"hw:numa_nodes": "2"
|
||||
},
|
||||
"projects": ["fake_tenant"],
|
||||
"projects": ["6f70656e737461636b20342065766572"],
|
||||
"swap": 0,
|
||||
"rxtx_factor": 2.0,
|
||||
"is_public": false,
|
||||
|
@ -19,7 +19,7 @@ import re
|
||||
import webob
|
||||
|
||||
from nova.api.openstack import common
|
||||
from nova.api.openstack.compute.schemas import console_output
|
||||
from nova.api.openstack.compute.schemas import console_output as schema
|
||||
from nova.api.openstack import wsgi
|
||||
from nova.api import validation
|
||||
from nova.compute import api as compute
|
||||
@ -34,7 +34,8 @@ class ConsoleOutputController(wsgi.Controller):
|
||||
|
||||
@wsgi.expected_errors((404, 409, 501))
|
||||
@wsgi.action('os-getConsoleOutput')
|
||||
@validation.schema(console_output.get_console_output)
|
||||
@validation.schema(schema.get_console_output)
|
||||
@validation.response_body_schema(schema.get_console_output_response)
|
||||
def get_console_output(self, req, id, body):
|
||||
"""Get text console output."""
|
||||
context = req.environ['nova.context']
|
||||
|
@ -17,7 +17,7 @@ import webob
|
||||
|
||||
from nova.api.openstack import api_version_request
|
||||
from nova.api.openstack import common
|
||||
from nova.api.openstack.compute.schemas import create_backup
|
||||
from nova.api.openstack.compute.schemas import create_backup as schema
|
||||
from nova.api.openstack import wsgi
|
||||
from nova.api import validation
|
||||
from nova.compute import api as compute
|
||||
@ -33,8 +33,14 @@ class CreateBackupController(wsgi.Controller):
|
||||
@wsgi.response(202)
|
||||
@wsgi.expected_errors((400, 403, 404, 409))
|
||||
@wsgi.action('createBackup')
|
||||
@validation.schema(create_backup.create_backup_v20, '2.0', '2.0')
|
||||
@validation.schema(create_backup.create_backup, '2.1')
|
||||
@validation.schema(schema.create_backup_v20, '2.0', '2.0')
|
||||
@validation.schema(schema.create_backup, '2.1')
|
||||
@validation.response_body_schema(
|
||||
schema.create_backup_response, '2.1', '2.44',
|
||||
)
|
||||
@validation.response_body_schema(
|
||||
schema.create_backup_response_v245, '2.45'
|
||||
)
|
||||
def _create_backup(self, req, id, body):
|
||||
"""Backup a server instance.
|
||||
|
||||
|
@ -80,9 +80,13 @@ class EvacuateController(wsgi.Controller):
|
||||
@wsgi.action('evacuate')
|
||||
@validation.schema(evacuate.evacuate, "2.0", "2.13")
|
||||
@validation.schema(evacuate.evacuate_v214, "2.14", "2.28")
|
||||
@validation.schema(evacuate.evacuate_v2_29, "2.29", "2.67")
|
||||
@validation.schema(evacuate.evacuate_v2_68, "2.68", "2.94")
|
||||
@validation.schema(evacuate.evacuate_v2_95, "2.95")
|
||||
@validation.schema(evacuate.evacuate_v229, "2.29", "2.67")
|
||||
@validation.schema(evacuate.evacuate_v268, "2.68", "2.94")
|
||||
@validation.schema(evacuate.evacuate_v295, "2.95")
|
||||
@validation.response_body_schema(
|
||||
evacuate.evacuate_response, "2.0", "2.13"
|
||||
)
|
||||
@validation.response_body_schema(evacuate.evacuate_response_v214, "2.14")
|
||||
def _evacuate(self, req, id, body):
|
||||
"""Permit admins to evacuate a server from a failed host
|
||||
to a new one.
|
||||
|
@ -63,6 +63,7 @@ class FlavorActionController(wsgi.Controller):
|
||||
@wsgi.expected_errors((400, 403, 404, 409))
|
||||
@wsgi.action("addTenantAccess")
|
||||
@validation.schema(schema.add_tenant_access)
|
||||
@validation.response_body_schema(schema.add_tenant_access_response)
|
||||
def _add_tenant_access(self, req, id, body):
|
||||
context = req.environ['nova.context']
|
||||
context.can(fa_policies.POLICY_ROOT % "add_tenant_access", target={})
|
||||
@ -88,6 +89,7 @@ class FlavorActionController(wsgi.Controller):
|
||||
@wsgi.expected_errors((400, 403, 404))
|
||||
@wsgi.action("removeTenantAccess")
|
||||
@validation.schema(schema.remove_tenant_access)
|
||||
@validation.response_body_schema(schema.remove_tenant_access_response)
|
||||
def _remove_tenant_access(self, req, id, body):
|
||||
context = req.environ['nova.context']
|
||||
context.can(
|
||||
|
@ -15,7 +15,7 @@
|
||||
import webob
|
||||
|
||||
from nova.api.openstack import common
|
||||
from nova.api.openstack.compute.schemas import remote_consoles
|
||||
from nova.api.openstack.compute.schemas import remote_consoles as schema
|
||||
from nova.api.openstack import wsgi
|
||||
from nova.api import validation
|
||||
from nova.compute import api as compute
|
||||
@ -40,7 +40,8 @@ class RemoteConsolesController(wsgi.Controller):
|
||||
@wsgi.Controller.api_version("2.1", "2.5")
|
||||
@wsgi.expected_errors((400, 404, 409, 501))
|
||||
@wsgi.action('os-getVNCConsole')
|
||||
@validation.schema(remote_consoles.get_vnc_console)
|
||||
@validation.schema(schema.get_vnc_console)
|
||||
@validation.response_body_schema(schema.get_vnc_console_response)
|
||||
def get_vnc_console(self, req, id, body):
|
||||
"""Get text console output."""
|
||||
context = req.environ['nova.context']
|
||||
@ -71,7 +72,8 @@ class RemoteConsolesController(wsgi.Controller):
|
||||
@wsgi.Controller.api_version("2.1", "2.5")
|
||||
@wsgi.expected_errors((400, 404, 409, 501))
|
||||
@wsgi.action('os-getSPICEConsole')
|
||||
@validation.schema(remote_consoles.get_spice_console)
|
||||
@validation.schema(schema.get_spice_console)
|
||||
@validation.response_body_schema(schema.get_spice_console_response)
|
||||
def get_spice_console(self, req, id, body):
|
||||
"""Get text console output."""
|
||||
context = req.environ['nova.context']
|
||||
@ -100,7 +102,7 @@ class RemoteConsolesController(wsgi.Controller):
|
||||
@wsgi.expected_errors((400, 404, 409, 501))
|
||||
@wsgi.action('os-getRDPConsole')
|
||||
@wsgi.removed('29.0.0', _rdp_console_removal_reason)
|
||||
@validation.schema(remote_consoles.get_rdp_console)
|
||||
@validation.schema(schema.get_rdp_console)
|
||||
def get_rdp_console(self, req, id, body):
|
||||
"""RDP console was available only for HyperV driver which has been
|
||||
removed from Nova in 29.0.0 (Caracal) release.
|
||||
@ -110,7 +112,8 @@ class RemoteConsolesController(wsgi.Controller):
|
||||
@wsgi.Controller.api_version("2.1", "2.5")
|
||||
@wsgi.expected_errors((400, 404, 409, 501))
|
||||
@wsgi.action('os-getSerialConsole')
|
||||
@validation.schema(remote_consoles.get_serial_console)
|
||||
@validation.schema(schema.get_serial_console)
|
||||
@validation.response_body_schema(schema.get_serial_console_response)
|
||||
def get_serial_console(self, req, id, body):
|
||||
"""Get connection to a serial console."""
|
||||
context = req.environ['nova.context']
|
||||
@ -139,8 +142,8 @@ class RemoteConsolesController(wsgi.Controller):
|
||||
|
||||
@wsgi.Controller.api_version("2.6")
|
||||
@wsgi.expected_errors((400, 404, 409, 501))
|
||||
@validation.schema(remote_consoles.create_v26, "2.6", "2.7")
|
||||
@validation.schema(remote_consoles.create_v28, "2.8")
|
||||
@validation.schema(schema.create_v26, "2.6", "2.7")
|
||||
@validation.schema(schema.create_v28, "2.8")
|
||||
def create(self, req, server_id, body):
|
||||
context = req.environ['nova.context']
|
||||
instance = common.get_instance(self.compute_api, context, server_id)
|
||||
|
@ -34,3 +34,12 @@ get_console_output = {
|
||||
'required': ['os-getConsoleOutput'],
|
||||
'additionalProperties': False,
|
||||
}
|
||||
|
||||
get_console_output_response = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'output': {'type': 'string'},
|
||||
},
|
||||
'required': ['output'],
|
||||
'additionalProperties': False,
|
||||
}
|
||||
|
@ -41,5 +41,19 @@ create_backup = {
|
||||
|
||||
create_backup_v20 = copy.deepcopy(create_backup)
|
||||
create_backup_v20['properties'][
|
||||
'createBackup']['properties']['name'] = (parameter_types.
|
||||
name_with_leading_trailing_spaces)
|
||||
'createBackup']['properties']['name'] = (
|
||||
parameter_types.name_with_leading_trailing_spaces)
|
||||
|
||||
|
||||
create_backup_response = {
|
||||
'type': 'null',
|
||||
}
|
||||
|
||||
create_backup_response_v245 = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'image_id': {'type': 'string', 'format': 'uuid'},
|
||||
},
|
||||
'required': ['image_id'],
|
||||
'additionalProperties': False,
|
||||
}
|
||||
|
@ -39,14 +39,31 @@ evacuate_v214 = copy.deepcopy(evacuate)
|
||||
del evacuate_v214['properties']['evacuate']['properties']['onSharedStorage']
|
||||
del evacuate_v214['properties']['evacuate']['required']
|
||||
|
||||
evacuate_v2_29 = copy.deepcopy(evacuate_v214)
|
||||
evacuate_v2_29['properties']['evacuate']['properties'][
|
||||
evacuate_v229 = copy.deepcopy(evacuate_v214)
|
||||
evacuate_v229['properties']['evacuate']['properties'][
|
||||
'force'] = parameter_types.boolean
|
||||
|
||||
# v2.68 removes the 'force' parameter added in v2.29, meaning it is identical
|
||||
# to v2.14
|
||||
evacuate_v2_68 = copy.deepcopy(evacuate_v214)
|
||||
evacuate_v268 = copy.deepcopy(evacuate_v214)
|
||||
|
||||
# v2.95 keeps the same schema, evacuating an instance will now result its state
|
||||
# to be stopped at destination.
|
||||
evacuate_v2_95 = copy.deepcopy(evacuate_v2_68)
|
||||
evacuate_v295 = copy.deepcopy(evacuate_v268)
|
||||
|
||||
evacuate_response = {
|
||||
'type': ['object', 'null'],
|
||||
'properties': {
|
||||
'adminPass': {
|
||||
'type': ['null', 'string'],
|
||||
}
|
||||
},
|
||||
# adminPass is a rare-example of configuration-driven API behavior: the
|
||||
# value depends on '[api] enable_instance_password'
|
||||
'required': [],
|
||||
'additionalProperties': False,
|
||||
}
|
||||
|
||||
evacuate_response_v214 = {
|
||||
'type': 'null',
|
||||
}
|
||||
|
@ -12,6 +12,8 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import copy
|
||||
|
||||
add_tenant_access = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
@ -31,7 +33,6 @@ add_tenant_access = {
|
||||
'additionalProperties': False,
|
||||
}
|
||||
|
||||
|
||||
remove_tenant_access = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
@ -57,3 +58,27 @@ index_query = {
|
||||
'properties': {},
|
||||
'additionalProperties': True,
|
||||
}
|
||||
|
||||
_common_response = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'flavor_access': {
|
||||
'type': 'array',
|
||||
'items': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'flavor_id': {'type': 'string'},
|
||||
'tenant_id': {'type': 'string', 'format': 'uuid'},
|
||||
},
|
||||
'required': ['flavor_id', 'tenant_id'],
|
||||
'additionalProperties': True,
|
||||
},
|
||||
},
|
||||
},
|
||||
'required': ['flavor_access'],
|
||||
'additionalProperties': True,
|
||||
}
|
||||
|
||||
add_tenant_access_response = copy.deepcopy(_common_response)
|
||||
|
||||
remove_tenant_access_response = copy.deepcopy(_common_response)
|
||||
|
@ -119,3 +119,78 @@ create_v28 = {
|
||||
'required': ['remote_console'],
|
||||
'additionalProperties': False,
|
||||
}
|
||||
|
||||
get_vnc_console_response = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'console': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'type': {
|
||||
'type': 'string',
|
||||
'enum': ['novnc', 'xvpvnc'],
|
||||
'description': '',
|
||||
},
|
||||
'url': {
|
||||
'type': 'string',
|
||||
'format': 'uri',
|
||||
'description': '',
|
||||
},
|
||||
},
|
||||
'required': ['type', 'url'],
|
||||
'additionalProperties': False,
|
||||
},
|
||||
},
|
||||
'required': ['console'],
|
||||
'additionalProperties': False,
|
||||
}
|
||||
|
||||
get_spice_console_response = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'console': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'type': {
|
||||
'type': 'string',
|
||||
'enum': ['spice-html5'],
|
||||
'description': '',
|
||||
},
|
||||
'url': {
|
||||
'type': 'string',
|
||||
'format': 'uri',
|
||||
'description': '',
|
||||
},
|
||||
},
|
||||
'required': ['type', 'url'],
|
||||
'additionalProperties': False,
|
||||
},
|
||||
},
|
||||
'required': ['console'],
|
||||
'additionalProperties': False,
|
||||
}
|
||||
|
||||
get_serial_console_response = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'console': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'type': {
|
||||
'type': 'string',
|
||||
'enum': ['serial'],
|
||||
'description': '',
|
||||
},
|
||||
'url': {
|
||||
'type': 'string',
|
||||
'format': 'uri',
|
||||
'description': '',
|
||||
},
|
||||
},
|
||||
'required': ['type', 'url'],
|
||||
'additionalProperties': False,
|
||||
},
|
||||
},
|
||||
'required': ['console'],
|
||||
'additionalProperties': False,
|
||||
}
|
||||
|
@ -238,8 +238,9 @@ create_v20['properties']['server']['properties'][
|
||||
'security_groups']['items']['properties']['name'] = (
|
||||
parameter_types.name_with_leading_trailing_spaces)
|
||||
create_v20['properties']['server']['properties']['user_data'] = {
|
||||
'oneOf': [{'type': 'string', 'format': 'base64', 'maxLength': 65535},
|
||||
{'type': 'null'},
|
||||
'oneOf': [
|
||||
{'type': 'string', 'format': 'base64', 'maxLength': 65535},
|
||||
{'type': 'null'},
|
||||
],
|
||||
}
|
||||
|
||||
@ -282,45 +283,49 @@ create_v237 = copy.deepcopy(create_v233)
|
||||
create_v237['properties']['server']['required'].append('networks')
|
||||
create_v237['properties']['server']['properties']['networks'] = {
|
||||
'oneOf': [
|
||||
{'type': 'array',
|
||||
'items': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'fixed_ip': parameter_types.ip_address,
|
||||
'port': {
|
||||
'oneOf': [{'type': 'string', 'format': 'uuid'},
|
||||
{'type': 'null'}]
|
||||
},
|
||||
'uuid': {'type': 'string', 'format': 'uuid'},
|
||||
},
|
||||
'additionalProperties': False,
|
||||
},
|
||||
{
|
||||
'type': 'array',
|
||||
'items': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'fixed_ip': parameter_types.ip_address,
|
||||
'port': {
|
||||
'oneOf': [{'type': 'string', 'format': 'uuid'},
|
||||
{'type': 'null'}]
|
||||
},
|
||||
'uuid': {'type': 'string', 'format': 'uuid'},
|
||||
},
|
||||
'additionalProperties': False,
|
||||
},
|
||||
},
|
||||
{'type': 'string', 'enum': ['none', 'auto']},
|
||||
]}
|
||||
],
|
||||
}
|
||||
|
||||
# 2.42 builds on 2.37 and re-introduces the tag field to the list of network
|
||||
# objects.
|
||||
create_v242 = copy.deepcopy(create_v237)
|
||||
create_v242['properties']['server']['properties']['networks'] = {
|
||||
'oneOf': [
|
||||
{'type': 'array',
|
||||
'items': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'fixed_ip': parameter_types.ip_address,
|
||||
'port': {
|
||||
'oneOf': [{'type': 'string', 'format': 'uuid'},
|
||||
{'type': 'null'}]
|
||||
},
|
||||
'uuid': {'type': 'string', 'format': 'uuid'},
|
||||
'tag': parameter_types.tag,
|
||||
},
|
||||
'additionalProperties': False,
|
||||
},
|
||||
{
|
||||
'type': 'array',
|
||||
'items': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'fixed_ip': parameter_types.ip_address,
|
||||
'port': {
|
||||
'oneOf': [{'type': 'string', 'format': 'uuid'},
|
||||
{'type': 'null'}]
|
||||
},
|
||||
'uuid': {'type': 'string', 'format': 'uuid'},
|
||||
'tag': parameter_types.tag,
|
||||
},
|
||||
'additionalProperties': False,
|
||||
},
|
||||
},
|
||||
{'type': 'string', 'enum': ['none', 'auto']},
|
||||
]}
|
||||
],
|
||||
}
|
||||
create_v242['properties']['server'][
|
||||
'properties']['block_device_mapping_v2']['items'][
|
||||
'properties']['tag'] = parameter_types.tag
|
||||
@ -465,7 +470,6 @@ rebuild_v294 = copy.deepcopy(rebuild_v290)
|
||||
rebuild_v294['properties']['rebuild']['properties'][
|
||||
'hostname'] = parameter_types.fqdn
|
||||
|
||||
|
||||
resize = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
@ -771,3 +775,458 @@ stop_server_response = {
|
||||
trigger_crash_dump_response = {
|
||||
'type': 'null',
|
||||
}
|
||||
|
||||
create_image_response = {
|
||||
'type': 'null',
|
||||
}
|
||||
|
||||
create_image_response_v245 = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'image_id': {'type': 'string', 'format': 'uuid'},
|
||||
},
|
||||
'required': ['image_id'],
|
||||
'additionalProperties': False,
|
||||
}
|
||||
|
||||
rebuild_response = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'server': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'accessIPv4': {
|
||||
'type': 'string',
|
||||
'oneOf': [
|
||||
{'format': 'ipv4'},
|
||||
{'const': ''},
|
||||
],
|
||||
},
|
||||
'accessIPv6': {
|
||||
'type': 'string',
|
||||
'oneOf': [
|
||||
{'format': 'ipv6'},
|
||||
{'const': ''},
|
||||
],
|
||||
},
|
||||
'addresses': {
|
||||
'type': 'object',
|
||||
'patternProperties': {
|
||||
'^.+$': {
|
||||
'type': 'array',
|
||||
'items': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'addr': {
|
||||
'type': 'string',
|
||||
'oneOf': [
|
||||
{'format': 'ipv4'},
|
||||
{'format': 'ipv6'},
|
||||
],
|
||||
},
|
||||
'version': {
|
||||
'type': 'number',
|
||||
'enum': [4, 6],
|
||||
},
|
||||
},
|
||||
'required': [
|
||||
'addr',
|
||||
'version'
|
||||
],
|
||||
'additionalProperties': False,
|
||||
},
|
||||
},
|
||||
},
|
||||
'additionalProperties': False,
|
||||
},
|
||||
'adminPass': {'type': ['null', 'string']},
|
||||
'created': {'type': 'string', 'format': 'date-time'},
|
||||
'fault': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'code': {'type': 'integer'},
|
||||
'created': {'type': 'string', 'format': 'date-time'},
|
||||
'details': {'type': 'string'},
|
||||
'message': {'type': 'string'},
|
||||
},
|
||||
'required': ['code', 'created', 'message'],
|
||||
'additionalProperties': False,
|
||||
},
|
||||
'flavor': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'id': {
|
||||
'type': 'string',
|
||||
},
|
||||
'links': {
|
||||
'type': 'array',
|
||||
'items': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'href': {
|
||||
'type': 'string',
|
||||
'format': 'uri',
|
||||
},
|
||||
'rel': {
|
||||
'type': 'string',
|
||||
},
|
||||
},
|
||||
'required': [
|
||||
'href',
|
||||
'rel'
|
||||
],
|
||||
"additionalProperties": False,
|
||||
},
|
||||
},
|
||||
},
|
||||
'additionalProperties': False,
|
||||
},
|
||||
'hostId': {'type': 'string'},
|
||||
'id': {'type': 'string'},
|
||||
'image': {
|
||||
'oneOf': [
|
||||
{
|
||||
'type': 'string',
|
||||
'const': '',
|
||||
},
|
||||
{
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'id': {
|
||||
'type': 'string'
|
||||
},
|
||||
'links': {
|
||||
'type': 'array',
|
||||
'items': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'href': {
|
||||
'type': 'string',
|
||||
'format': 'uri',
|
||||
},
|
||||
'rel': {
|
||||
'type': 'string',
|
||||
},
|
||||
},
|
||||
'required': [
|
||||
'href',
|
||||
'rel'
|
||||
],
|
||||
"additionalProperties": False,
|
||||
},
|
||||
},
|
||||
},
|
||||
'additionalProperties': False,
|
||||
},
|
||||
],
|
||||
},
|
||||
'links': {
|
||||
'type': 'array',
|
||||
'items': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'href': {
|
||||
'type': 'string',
|
||||
'format': 'uri',
|
||||
},
|
||||
'rel': {
|
||||
'type': 'string',
|
||||
},
|
||||
},
|
||||
'required': [
|
||||
'href',
|
||||
'rel'
|
||||
],
|
||||
'additionalProperties': False,
|
||||
},
|
||||
},
|
||||
'metadata': {
|
||||
'type': 'object',
|
||||
'patternProperties': {
|
||||
'^.+$': {
|
||||
'type': 'string'
|
||||
},
|
||||
},
|
||||
'additionalProperties': False,
|
||||
},
|
||||
'name': {'type': ['string', 'null']},
|
||||
'progress': {'type': ['null', 'number']},
|
||||
'status': {'type': 'string'},
|
||||
'tenant_id': {'type': 'string', 'format': 'uuid'},
|
||||
'updated': {'type': 'string', 'format': 'date-time'},
|
||||
'user_id': {'type': 'string'},
|
||||
'OS-DCF:diskConfig': {'type': 'string'},
|
||||
},
|
||||
'required': [
|
||||
'accessIPv4',
|
||||
'accessIPv6',
|
||||
'addresses',
|
||||
'created',
|
||||
'flavor',
|
||||
'hostId',
|
||||
'id',
|
||||
'image',
|
||||
'links',
|
||||
'metadata',
|
||||
'name',
|
||||
'progress',
|
||||
'status',
|
||||
'tenant_id',
|
||||
'updated',
|
||||
'user_id',
|
||||
'OS-DCF:diskConfig',
|
||||
],
|
||||
'additionalProperties': False,
|
||||
},
|
||||
},
|
||||
'required': [
|
||||
'server'
|
||||
],
|
||||
'additionalProperties': False,
|
||||
}
|
||||
|
||||
rebuild_response_v29 = copy.deepcopy(rebuild_response)
|
||||
rebuild_response_v29['properties']['server']['properties']['locked'] = {
|
||||
'type': 'boolean',
|
||||
}
|
||||
rebuild_response_v29['properties']['server']['required'].append('locked')
|
||||
|
||||
rebuild_response_v219 = copy.deepcopy(rebuild_response_v29)
|
||||
rebuild_response_v219['properties']['server']['properties']['description'] = {
|
||||
'type': ['null', 'string'],
|
||||
}
|
||||
rebuild_response_v219['properties']['server']['required'].append('description')
|
||||
|
||||
rebuild_response_v226 = copy.deepcopy(rebuild_response_v219)
|
||||
rebuild_response_v226['properties']['server']['properties']['tags'] = {
|
||||
'type': 'array',
|
||||
'items': {
|
||||
'type': 'string',
|
||||
},
|
||||
'maxItems': 50,
|
||||
}
|
||||
rebuild_response_v226['properties']['server']['required'].append('tags')
|
||||
|
||||
# NOTE(stephenfin): We overwrite rather than extend 'flavor', since we now
|
||||
# embed the flavor in this version
|
||||
rebuild_response_v246 = copy.deepcopy(rebuild_response_v226)
|
||||
rebuild_response_v246['properties']['server']['properties']['flavor'] = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'vcpus': {
|
||||
'type': 'integer',
|
||||
},
|
||||
'ram': {
|
||||
'type': 'integer',
|
||||
},
|
||||
'disk': {
|
||||
'type': 'integer',
|
||||
},
|
||||
'ephemeral': {
|
||||
'type': 'integer',
|
||||
},
|
||||
'swap': {
|
||||
'type': 'integer',
|
||||
},
|
||||
'original_name': {
|
||||
'type': 'string',
|
||||
},
|
||||
'extra_specs': {
|
||||
'type': 'object',
|
||||
'patternProperties': {
|
||||
'^.+$': {
|
||||
'type': 'string'
|
||||
},
|
||||
},
|
||||
'additionalProperties': False,
|
||||
},
|
||||
},
|
||||
'required': ['vcpus', 'ram', 'disk', 'ephemeral', 'swap', 'original_name'],
|
||||
'additionalProperties': False,
|
||||
}
|
||||
|
||||
rebuild_response_v254 = copy.deepcopy(rebuild_response_v246)
|
||||
rebuild_response_v254['properties']['server']['properties']['key_name'] = {
|
||||
'type': ['null', 'string'],
|
||||
}
|
||||
rebuild_response_v254['properties']['server']['required'].append('key_name')
|
||||
|
||||
rebuild_response_v257 = copy.deepcopy(rebuild_response_v254)
|
||||
rebuild_response_v257['properties']['server']['properties']['user_data'] = {
|
||||
'oneOf': [
|
||||
{'type': 'string', 'format': 'base64', 'maxLength': 65535},
|
||||
{'type': 'null'},
|
||||
],
|
||||
}
|
||||
rebuild_response_v257['properties']['server']['required'].append('user_data')
|
||||
|
||||
rebuild_response_v263 = copy.deepcopy(rebuild_response_v257)
|
||||
rebuild_response_v263['properties']['server']['properties'].update(
|
||||
{
|
||||
'trusted_image_certificates': {
|
||||
'type': ['array', 'null'],
|
||||
'items': {
|
||||
'type': 'string',
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
rebuild_response_v263['properties']['server']['required'].append(
|
||||
'trusted_image_certificates'
|
||||
)
|
||||
|
||||
rebuild_response_v271 = copy.deepcopy(rebuild_response_v263)
|
||||
rebuild_response_v271['properties']['server']['properties'].update(
|
||||
{
|
||||
'server_groups': {
|
||||
'type': 'array',
|
||||
'items': {
|
||||
'type': 'string',
|
||||
'format': 'uuid',
|
||||
},
|
||||
'maxLength': 1,
|
||||
},
|
||||
},
|
||||
)
|
||||
rebuild_response_v271['properties']['server']['required'].append(
|
||||
'server_groups'
|
||||
)
|
||||
|
||||
rebuild_response_v273 = copy.deepcopy(rebuild_response_v271)
|
||||
rebuild_response_v273['properties']['server']['properties'].update(
|
||||
{
|
||||
'locked_reason': {
|
||||
'type': ['null', 'string'],
|
||||
},
|
||||
},
|
||||
)
|
||||
rebuild_response_v273['properties']['server']['required'].append(
|
||||
'locked_reason'
|
||||
)
|
||||
|
||||
rebuild_response_v275 = copy.deepcopy(rebuild_response_v273)
|
||||
rebuild_response_v275['properties']['server']['properties'].update(
|
||||
{
|
||||
'config_drive': {
|
||||
# TODO(stephenfin): Our tests return null but this shouldn't happen
|
||||
# in practice, apparently?
|
||||
'type': ['string', 'boolean', 'null'],
|
||||
},
|
||||
'OS-EXT-AZ:availability_zone': {
|
||||
'type': 'string',
|
||||
},
|
||||
'OS-EXT-SRV-ATTR:host': {
|
||||
'type': ['string', 'null'],
|
||||
},
|
||||
'OS-EXT-SRV-ATTR:hypervisor_hostname': {
|
||||
'type': ['string', 'null'],
|
||||
},
|
||||
'OS-EXT-SRV-ATTR:instance_name': {
|
||||
'type': 'string',
|
||||
},
|
||||
'OS-EXT-STS:power_state': {
|
||||
'type': 'integer',
|
||||
'enum': [0, 1, 3, 4, 6, 7],
|
||||
},
|
||||
'OS-EXT-STS:task_state': {
|
||||
'type': ['null', 'string'],
|
||||
},
|
||||
'OS-EXT-STS:vm_state': {
|
||||
'type': 'string',
|
||||
},
|
||||
'OS-EXT-SRV-ATTR:hostname': {
|
||||
'type': 'string',
|
||||
},
|
||||
'OS-EXT-SRV-ATTR:reservation_id': {
|
||||
'type': ['string', 'null'],
|
||||
},
|
||||
'OS-EXT-SRV-ATTR:launch_index': {
|
||||
'type': 'integer',
|
||||
},
|
||||
'OS-EXT-SRV-ATTR:kernel_id': {
|
||||
'type': ['string', 'null'],
|
||||
},
|
||||
'OS-EXT-SRV-ATTR:ramdisk_id': {
|
||||
'type': ['string', 'null'],
|
||||
},
|
||||
'OS-EXT-SRV-ATTR:root_device_name': {
|
||||
'type': ['string', 'null'],
|
||||
},
|
||||
'os-extended-volumes:volumes_attached': {
|
||||
'type': 'array',
|
||||
'items': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'id': {
|
||||
'type': 'string',
|
||||
},
|
||||
'delete_on_termination': {
|
||||
'type': 'boolean',
|
||||
'default': False,
|
||||
},
|
||||
},
|
||||
'required': ['id', 'delete_on_termination'],
|
||||
'additionalProperties': False,
|
||||
},
|
||||
},
|
||||
'OS-SRV-USG:launched_at': {
|
||||
'oneOf': [
|
||||
{'type': 'null'},
|
||||
{'type': 'string', 'format': 'date-time'},
|
||||
],
|
||||
},
|
||||
'OS-SRV-USG:terminated_at': {
|
||||
'oneOf': [
|
||||
{'type': 'null'},
|
||||
{'type': 'string', 'format': 'date-time'},
|
||||
],
|
||||
},
|
||||
'security_groups': {
|
||||
'type': 'array',
|
||||
'items': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'name': {
|
||||
'type': 'string',
|
||||
},
|
||||
},
|
||||
'required': ['name'],
|
||||
'additionalProperties': False,
|
||||
},
|
||||
},
|
||||
'host_status': {
|
||||
'type': 'string',
|
||||
},
|
||||
},
|
||||
)
|
||||
rebuild_response_v275['properties']['server']['required'].extend([
|
||||
'config_drive',
|
||||
'OS-EXT-AZ:availability_zone',
|
||||
'OS-EXT-STS:power_state',
|
||||
'OS-EXT-STS:task_state',
|
||||
'OS-EXT-STS:vm_state',
|
||||
'os-extended-volumes:volumes_attached',
|
||||
'OS-SRV-USG:launched_at',
|
||||
'OS-SRV-USG:terminated_at',
|
||||
])
|
||||
rebuild_response_v275['properties']['server']['properties']['addresses'][
|
||||
'patternProperties'
|
||||
]['^.+$']['items']['properties'].update({
|
||||
'OS-EXT-IPS-MAC:mac_addr': {'type': 'string', 'format': 'mac-address'},
|
||||
'OS-EXT-IPS:type': {'type': 'string', 'enum': ['fixed', 'floating']},
|
||||
})
|
||||
rebuild_response_v275['properties']['server']['properties']['addresses'][
|
||||
'patternProperties'
|
||||
]['^.+$']['items']['required'].extend([
|
||||
'OS-EXT-IPS-MAC:mac_addr', 'OS-EXT-IPS:type'
|
||||
])
|
||||
|
||||
rebuild_response_v296 = copy.deepcopy(rebuild_response_v275)
|
||||
rebuild_response_v296['properties']['server']['properties'].update({
|
||||
'pinned_availability_zone': {
|
||||
'type': ['null', 'string'],
|
||||
},
|
||||
})
|
||||
rebuild_response_v296['properties']['server']['required'].append(
|
||||
'pinned_availability_zone'
|
||||
)
|
||||
|
@ -1163,6 +1163,29 @@ class ServersController(wsgi.Controller):
|
||||
@validation.schema(schema.rebuild_v263, '2.63', '2.89')
|
||||
@validation.schema(schema.rebuild_v290, '2.90', '2.93')
|
||||
@validation.schema(schema.rebuild_v294, '2.94')
|
||||
@validation.response_body_schema(schema.rebuild_response, '2.0', '2.8')
|
||||
@validation.response_body_schema(
|
||||
schema.rebuild_response_v29, '2.9', '2.18')
|
||||
@validation.response_body_schema(
|
||||
schema.rebuild_response_v219, '2.19', '2.25')
|
||||
@validation.response_body_schema(
|
||||
schema.rebuild_response_v226, '2.26', '2.45')
|
||||
@validation.response_body_schema(
|
||||
schema.rebuild_response_v246, '2.46', '2.53')
|
||||
@validation.response_body_schema(
|
||||
schema.rebuild_response_v254, '2.54', '2.56')
|
||||
@validation.response_body_schema(
|
||||
schema.rebuild_response_v257, '2.57', '2.62')
|
||||
@validation.response_body_schema(
|
||||
schema.rebuild_response_v263, '2.63', '2.70')
|
||||
@validation.response_body_schema(
|
||||
schema.rebuild_response_v271, '2.71', '2.72')
|
||||
@validation.response_body_schema(
|
||||
schema.rebuild_response_v273, '2.73', '2.74')
|
||||
@validation.response_body_schema(
|
||||
schema.rebuild_response_v275, '2.75', '2.95')
|
||||
@validation.response_body_schema(
|
||||
schema.rebuild_response_v296, '2.96')
|
||||
def _action_rebuild(self, req, id, body):
|
||||
"""Rebuild an instance with the given attributes."""
|
||||
rebuild_dict = body['rebuild']
|
||||
@ -1333,6 +1356,9 @@ class ServersController(wsgi.Controller):
|
||||
@wsgi.action('createImage')
|
||||
@validation.schema(schema.create_image, '2.0', '2.0')
|
||||
@validation.schema(schema.create_image, '2.1')
|
||||
@validation.response_body_schema(
|
||||
schema.create_image_response, '2.0', '2.44')
|
||||
@validation.response_body_schema(schema.create_image_response_v245, '2.45')
|
||||
def _action_create_image(self, req, id, body):
|
||||
"""Snapshot a server instance."""
|
||||
context = req.environ['nova.context']
|
||||
|
@ -2,7 +2,7 @@
|
||||
"flavor_access": [
|
||||
{
|
||||
"flavor_id": "%(flavor_id)s",
|
||||
"tenant_id": "fake_tenant"
|
||||
"tenant_id": "%(tenant_id)s"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -11,7 +11,6 @@
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from nova.tests.functional.api_sample_tests import api_sample_base
|
||||
|
||||
|
||||
@ -21,7 +20,7 @@ class FlavorAccessTestsBase(api_sample_base.ApiSampleTestBaseV21):
|
||||
|
||||
def _add_tenant(self):
|
||||
subs = {
|
||||
'tenant_id': 'fake_tenant',
|
||||
'tenant_id': self.api.project_id,
|
||||
'flavor_id': '10',
|
||||
}
|
||||
response = self._do_post('flavors/10/action',
|
||||
@ -49,7 +48,7 @@ class FlavorAccessSampleJsonTests(FlavorAccessTestsBase):
|
||||
response = self._do_get('flavors/%s/os-flavor-access' % flavor_id)
|
||||
subs = {
|
||||
'flavor_id': flavor_id,
|
||||
'tenant_id': 'fake_tenant',
|
||||
'tenant_id': self.api.project_id,
|
||||
}
|
||||
self._verify_response('flavor-access-list-resp', subs, response, 200)
|
||||
|
||||
@ -61,7 +60,7 @@ class FlavorAccessSampleJsonTests(FlavorAccessTestsBase):
|
||||
self._create_flavor()
|
||||
self._add_tenant()
|
||||
subs = {
|
||||
'tenant_id': 'fake_tenant',
|
||||
'tenant_id': self.api.project_id,
|
||||
}
|
||||
response = self._do_post('flavors/10/action',
|
||||
"flavor-access-remove-tenant-req",
|
||||
@ -88,7 +87,7 @@ class FlavorAccessV27SampleJsonTests(FlavorAccessTestsBase):
|
||||
|
||||
subs = {
|
||||
'flavor_id': '10',
|
||||
'tenant_id': 'fake_tenant'
|
||||
'tenant_id': self.api.project_id
|
||||
}
|
||||
# Version 2.7+ will return HTTPConflict (409)
|
||||
# if the flavor is public
|
||||
|
@ -75,7 +75,7 @@ class TestFlavorNotificationSample(
|
||||
|
||||
body = {
|
||||
"addTenantAccess": {
|
||||
"tenant": "fake_tenant"
|
||||
"tenant": "6f70656e737461636b20342065766572"
|
||||
}
|
||||
}
|
||||
self.admin_api.api_post(
|
||||
|
@ -15,12 +15,12 @@
|
||||
|
||||
from unittest import mock
|
||||
|
||||
from oslo_utils.fixture import uuidsentinel as uuids
|
||||
from oslo_utils import timeutils
|
||||
import webob
|
||||
|
||||
from nova.api.openstack import common
|
||||
from nova.api.openstack.compute import create_backup \
|
||||
as create_backup_v21
|
||||
from nova.api.openstack.compute import create_backup
|
||||
from nova.compute import api
|
||||
from nova.compute import utils as compute_utils
|
||||
from nova import exception
|
||||
@ -32,7 +32,7 @@ from nova.tests.unit import fake_instance
|
||||
|
||||
class CreateBackupTestsV21(admin_only_action_common.CommonMixin,
|
||||
test.NoDBTestCase):
|
||||
create_backup = create_backup_v21
|
||||
create_backup = create_backup
|
||||
controller_name = 'CreateBackupController'
|
||||
validation_error = exception.ValidationError
|
||||
|
||||
@ -54,7 +54,7 @@ class CreateBackupTestsV21(admin_only_action_common.CommonMixin,
|
||||
},
|
||||
}
|
||||
|
||||
image = dict(id='fake-image-id', status='ACTIVE', name='Backup 1',
|
||||
image = dict(id=uuids.image_id, status='ACTIVE', name='Backup 1',
|
||||
properties=metadata)
|
||||
|
||||
instance = fake_instance.fake_instance_obj(self.context)
|
||||
@ -70,7 +70,7 @@ class CreateBackupTestsV21(admin_only_action_common.CommonMixin,
|
||||
extra_properties=metadata)
|
||||
|
||||
self.assertEqual(202, res.status_int)
|
||||
self.assertIn('fake-image-id', res.headers['Location'])
|
||||
self.assertIn(uuids.image_id, res.headers['Location'])
|
||||
|
||||
def test_create_backup_no_name(self):
|
||||
# Name is required for backups.
|
||||
@ -107,7 +107,7 @@ class CreateBackupTestsV21(admin_only_action_common.CommonMixin,
|
||||
'rotation': 1,
|
||||
},
|
||||
}
|
||||
image = dict(id='fake-image-id', status='ACTIVE', name='Backup 1',
|
||||
image = dict(id=uuids.image_id, status='ACTIVE', name='Backup 1',
|
||||
properties={})
|
||||
instance = fake_instance.fake_instance_obj(self.context)
|
||||
self.mock_get.return_value = instance
|
||||
@ -217,7 +217,7 @@ class CreateBackupTestsV21(admin_only_action_common.CommonMixin,
|
||||
},
|
||||
}
|
||||
|
||||
image = dict(id='fake-image-id', status='ACTIVE', name='Backup 1',
|
||||
image = dict(id=uuids.image_id, status='ACTIVE', name='Backup 1',
|
||||
properties={})
|
||||
instance = fake_instance.fake_instance_obj(self.context)
|
||||
self.mock_get.return_value = instance
|
||||
@ -246,7 +246,7 @@ class CreateBackupTestsV21(admin_only_action_common.CommonMixin,
|
||||
},
|
||||
}
|
||||
|
||||
image = dict(id='fake-image-id', status='ACTIVE', name='Backup 1',
|
||||
image = dict(id=uuids.image_id, status='ACTIVE', name='Backup 1',
|
||||
properties={})
|
||||
instance = fake_instance.fake_instance_obj(self.context)
|
||||
self.mock_get.return_value = instance
|
||||
@ -261,7 +261,7 @@ class CreateBackupTestsV21(admin_only_action_common.CommonMixin,
|
||||
extra_properties={})
|
||||
|
||||
self.assertEqual(202, res.status_int)
|
||||
self.assertIn('fake-image-id', res.headers['Location'])
|
||||
self.assertIn(uuids.image_id, res.headers['Location'])
|
||||
|
||||
@mock.patch.object(common, 'check_img_metadata_properties_quota')
|
||||
@mock.patch.object(api.API, 'backup')
|
||||
@ -275,7 +275,7 @@ class CreateBackupTestsV21(admin_only_action_common.CommonMixin,
|
||||
},
|
||||
}
|
||||
|
||||
image = dict(id='fake-image-id', status='ACTIVE', name='Backup 1',
|
||||
image = dict(id=uuids.image_id, status='ACTIVE', name='Backup 1',
|
||||
properties={})
|
||||
instance = fake_instance.fake_instance_obj(self.context)
|
||||
self.mock_get.return_value = instance
|
||||
@ -289,11 +289,11 @@ class CreateBackupTestsV21(admin_only_action_common.CommonMixin,
|
||||
'daily', 1,
|
||||
extra_properties={})
|
||||
self.assertEqual(202, res.status_int)
|
||||
self.assertIn('fake-image-id', res.headers['Location'])
|
||||
self.assertIn(uuids.image_id, res.headers['Location'])
|
||||
|
||||
@mock.patch.object(common, 'check_img_metadata_properties_quota')
|
||||
@mock.patch.object(api.API, 'backup', return_value=dict(
|
||||
id='fake-image-id', status='ACTIVE', name='Backup 1', properties={}))
|
||||
id=uuids.image_id, status='ACTIVE', name='Backup 1', properties={}))
|
||||
def test_create_backup_v2_45(self, mock_backup, mock_check_image):
|
||||
"""Tests the 2.45 microversion to ensure the Location header is not
|
||||
in the response.
|
||||
@ -310,7 +310,7 @@ class CreateBackupTestsV21(admin_only_action_common.CommonMixin,
|
||||
req = fakes.HTTPRequest.blank('', version='2.45')
|
||||
res = self.controller._create_backup(req, instance['uuid'], body=body)
|
||||
self.assertIsInstance(res, dict)
|
||||
self.assertEqual('fake-image-id', res['image_id'])
|
||||
self.assertEqual(uuids.image_id, res['image_id'])
|
||||
|
||||
@mock.patch.object(common, 'check_img_metadata_properties_quota')
|
||||
@mock.patch.object(api.API, 'backup')
|
||||
@ -396,7 +396,7 @@ class CreateBackupTestsV239(test.NoDBTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(CreateBackupTestsV239, self).setUp()
|
||||
self.controller = create_backup_v21.CreateBackupController()
|
||||
self.controller = create_backup.CreateBackupController()
|
||||
self.req = fakes.HTTPRequest.blank('', version='2.39')
|
||||
|
||||
@mock.patch.object(common, 'check_img_metadata_properties_quota')
|
||||
|
@ -16,11 +16,11 @@
|
||||
import datetime
|
||||
from unittest import mock
|
||||
|
||||
from oslo_utils.fixture import uuidsentinel as uuids
|
||||
from webob import exc
|
||||
|
||||
from nova.api.openstack import api_version_request as api_version
|
||||
from nova.api.openstack.compute import flavor_access \
|
||||
as flavor_access_v21
|
||||
from nova.api.openstack.compute import flavor_access
|
||||
from nova.api.openstack.compute import flavors as flavors_api
|
||||
from nova import context
|
||||
from nova import exception
|
||||
@ -57,9 +57,9 @@ FLAVORS = {
|
||||
|
||||
|
||||
ACCESS_LIST = [
|
||||
{'flavor_id': '2', 'project_id': 'proj2'},
|
||||
{'flavor_id': '2', 'project_id': 'proj3'},
|
||||
{'flavor_id': '3', 'project_id': 'proj3'},
|
||||
{'flavor_id': '2', 'project_id': uuids.proj2},
|
||||
{'flavor_id': '2', 'project_id': uuids.proj3},
|
||||
{'flavor_id': '3', 'project_id': uuids.proj3},
|
||||
]
|
||||
|
||||
|
||||
@ -126,8 +126,8 @@ def fake_get_flavor_projects_from_db(context, flavorid):
|
||||
|
||||
class FlavorAccessTestV21(test.NoDBTestCase):
|
||||
api_version = "2.1"
|
||||
FlavorAccessController = flavor_access_v21.FlavorAccessController
|
||||
FlavorActionController = flavor_access_v21.FlavorActionController
|
||||
FlavorAccessController = flavor_access.FlavorAccessController
|
||||
FlavorActionController = flavor_access.FlavorActionController
|
||||
_prefix = "/v2/%s" % fakes.FAKE_PROJECT_ID
|
||||
validation_ex = exception.ValidationError
|
||||
|
||||
@ -175,8 +175,8 @@ class FlavorAccessTestV21(test.NoDBTestCase):
|
||||
req.environ = {"nova.context": context.RequestContext(
|
||||
'fake_user', fakes.FAKE_PROJECT_ID)}
|
||||
expected = {'flavor_access': [
|
||||
{'flavor_id': '2', 'tenant_id': 'proj2'},
|
||||
{'flavor_id': '2', 'tenant_id': 'proj3'}]}
|
||||
{'flavor_id': '2', 'tenant_id': uuids.proj2},
|
||||
{'flavor_id': '2', 'tenant_id': uuids.proj3}]}
|
||||
result = self.flavor_access_controller.index(req, '2')
|
||||
self.assertEqual(result, expected)
|
||||
|
||||
@ -192,7 +192,7 @@ class FlavorAccessTestV21(test.NoDBTestCase):
|
||||
expected = {'flavors': [{'id': '0'}, {'id': '1'}, {'id': '2'}]}
|
||||
req = fakes.HTTPRequest.blank(self._prefix + '/flavors',
|
||||
use_admin_context=True)
|
||||
req.environ['nova.context'].project_id = 'proj2'
|
||||
req.environ['nova.context'].project_id = uuids.proj2
|
||||
result = self.flavor_controller.index(req)
|
||||
self._verify_flavor_list(result['flavors'], expected['flavors'])
|
||||
|
||||
@ -217,7 +217,7 @@ class FlavorAccessTestV21(test.NoDBTestCase):
|
||||
url = self._prefix + '/flavors?is_public=false'
|
||||
req = fakes.HTTPRequest.blank(url,
|
||||
use_admin_context=True)
|
||||
req.environ['nova.context'].project_id = 'proj2'
|
||||
req.environ['nova.context'].project_id = uuids.proj2
|
||||
result = self.flavor_controller.index(req)
|
||||
self._verify_flavor_list(result['flavors'], expected['flavors'])
|
||||
|
||||
@ -264,12 +264,13 @@ class FlavorAccessTestV21(test.NoDBTestCase):
|
||||
def test_add_tenant_access(self):
|
||||
def stub_add_flavor_access(context, flavor_id, projectid):
|
||||
self.assertEqual(3, flavor_id, "flavor_id")
|
||||
self.assertEqual("proj2", projectid, "projectid")
|
||||
self.assertEqual(uuids.proj2, projectid, "projectid")
|
||||
self.stub_out('nova.objects.Flavor._flavor_add_project',
|
||||
stub_add_flavor_access)
|
||||
expected = {'flavor_access':
|
||||
[{'flavor_id': '3', 'tenant_id': 'proj3'}]}
|
||||
body = {'addTenantAccess': {'tenant': 'proj2'}}
|
||||
expected = {
|
||||
'flavor_access': [{'flavor_id': '3', 'tenant_id': uuids.proj3}]
|
||||
}
|
||||
body = {'addTenantAccess': {'tenant': uuids.proj2}}
|
||||
req = fakes.HTTPRequest.blank(self._prefix + '/flavors/2/action',
|
||||
use_admin_context=True)
|
||||
|
||||
@ -280,7 +281,7 @@ class FlavorAccessTestV21(test.NoDBTestCase):
|
||||
@mock.patch('nova.objects.Flavor.get_by_flavor_id',
|
||||
side_effect=exception.FlavorNotFound(flavor_id='1'))
|
||||
def test_add_tenant_access_with_flavor_not_found(self, mock_get):
|
||||
body = {'addTenantAccess': {'tenant': 'proj2'}}
|
||||
body = {'addTenantAccess': {'tenant': uuids.proj2}}
|
||||
req = fakes.HTTPRequest.blank(self._prefix + '/flavors/2/action',
|
||||
use_admin_context=True)
|
||||
self.assertRaises(exc.HTTPNotFound,
|
||||
@ -290,7 +291,7 @@ class FlavorAccessTestV21(test.NoDBTestCase):
|
||||
def test_add_tenant_access_with_no_tenant(self):
|
||||
req = fakes.HTTPRequest.blank(self._prefix + '/flavors/2/action',
|
||||
use_admin_context=True)
|
||||
body = {'addTenantAccess': {'foo': 'proj2'}}
|
||||
body = {'addTenantAccess': {'foo': uuids.proj2}}
|
||||
self.assertRaises(self.validation_ex,
|
||||
self.flavor_action_controller._add_tenant_access,
|
||||
req, '2', body=body)
|
||||
@ -309,7 +310,7 @@ class FlavorAccessTestV21(test.NoDBTestCase):
|
||||
self._prefix + '/flavors/3/os-flavor-access')
|
||||
req.environ = {"nova.context": context.RequestContext(
|
||||
'fake_user', fakes.FAKE_PROJECT_ID)}
|
||||
body = {'addTenantAccess': {'tenant': 'proj2'}}
|
||||
body = {'addTenantAccess': {'tenant': uuids.proj2}}
|
||||
self.assertRaises(exc.HTTPConflict,
|
||||
self.flavor_action_controller._add_tenant_access,
|
||||
req, '3', body=body)
|
||||
@ -320,7 +321,7 @@ class FlavorAccessTestV21(test.NoDBTestCase):
|
||||
project_id=projectid)
|
||||
self.stub_out('nova.objects.Flavor._flavor_del_project',
|
||||
stub_remove_flavor_access)
|
||||
body = {'removeTenantAccess': {'tenant': 'proj2'}}
|
||||
body = {'removeTenantAccess': {'tenant': uuids.proj2}}
|
||||
req = fakes.HTTPRequest.blank(
|
||||
self._prefix + '/flavors/3/os-flavor-access')
|
||||
req.environ = {"nova.context": context.RequestContext(
|
||||
@ -330,7 +331,7 @@ class FlavorAccessTestV21(test.NoDBTestCase):
|
||||
req, '3', body=body)
|
||||
|
||||
def test_add_tenant_access_is_public(self):
|
||||
body = {'addTenantAccess': {'tenant': 'proj2'}}
|
||||
body = {'addTenantAccess': {'tenant': uuids.proj2}}
|
||||
req = fakes.HTTPRequest.blank(self._prefix + '/flavors/2/action',
|
||||
use_admin_context=True)
|
||||
req.api_version_request = api_version.APIVersionRequest('2.7')
|
||||
@ -343,7 +344,7 @@ class FlavorAccessTestV21(test.NoDBTestCase):
|
||||
def test_delete_tenant_access_with_no_tenant(self, mock_api_get):
|
||||
req = fakes.HTTPRequest.blank(self._prefix + '/flavors/2/action',
|
||||
use_admin_context=True)
|
||||
body = {'removeTenantAccess': {'foo': 'proj2'}}
|
||||
body = {'removeTenantAccess': {'foo': uuids.proj2}}
|
||||
self.assertRaises(self.validation_ex,
|
||||
self.flavor_action_controller._remove_tenant_access,
|
||||
req, '2', body=body)
|
||||
@ -359,30 +360,32 @@ class FlavorAccessTestV21(test.NoDBTestCase):
|
||||
"""Tests the case that the tenant does not exist in Keystone."""
|
||||
req = fakes.HTTPRequest.blank(self._prefix + '/flavors/2/action',
|
||||
use_admin_context=True)
|
||||
body = {'addTenantAccess': {'tenant': 'proj2'}}
|
||||
body = {'addTenantAccess': {'tenant': uuids.proj2}}
|
||||
self.assertRaises(exc.HTTPBadRequest,
|
||||
self.flavor_action_controller._add_tenant_access,
|
||||
req, '2', body=body)
|
||||
mock_verify.assert_called_once_with(
|
||||
req.environ['nova.context'], 'proj2')
|
||||
req.environ['nova.context'], uuids.proj2)
|
||||
|
||||
@mock.patch('nova.objects.Flavor.remove_access')
|
||||
@mock.patch('nova.api.openstack.identity.verify_project_id',
|
||||
side_effect=exc.HTTPBadRequest(
|
||||
explanation="Project ID proj2 is not a valid project."))
|
||||
@mock.patch('nova.api.openstack.identity.verify_project_id')
|
||||
def test_remove_tenant_access_with_invalid_tenant(self,
|
||||
mock_verify,
|
||||
mock_remove_access):
|
||||
"""Tests the case that the tenant does not exist in Keystone."""
|
||||
mock_verify.side_effect = exc.HTTPBadRequest(explanation=(
|
||||
f"Project ID {uuids.proj2} is not a valid project."
|
||||
))
|
||||
|
||||
req = fakes.HTTPRequest.blank(self._prefix + '/flavors/2/action',
|
||||
use_admin_context=True)
|
||||
body = {'removeTenantAccess': {'tenant': 'proj2'}}
|
||||
body = {'removeTenantAccess': {'tenant': uuids.proj2}}
|
||||
|
||||
self.flavor_action_controller._remove_tenant_access(
|
||||
req, '2', body=body)
|
||||
mock_verify.assert_called_once_with(
|
||||
req.environ['nova.context'], 'proj2')
|
||||
mock_remove_access.assert_called_once_with('proj2')
|
||||
req.environ['nova.context'], uuids.proj2)
|
||||
mock_remove_access.assert_called_once_with(uuids.proj2)
|
||||
|
||||
@mock.patch('nova.api.openstack.identity.verify_project_id',
|
||||
side_effect=exc.HTTPBadRequest(
|
||||
@ -395,10 +398,10 @@ class FlavorAccessTestV21(test.NoDBTestCase):
|
||||
"""
|
||||
req = fakes.HTTPRequest.blank(self._prefix + '/flavors/2/action',
|
||||
use_admin_context=True)
|
||||
body = {'removeTenantAccess': {'tenant': 'proj2'}}
|
||||
body = {'removeTenantAccess': {'tenant': uuids.proj2}}
|
||||
|
||||
self.assertRaises(exc.HTTPBadRequest,
|
||||
self.flavor_action_controller._remove_tenant_access,
|
||||
req, '2', body=body)
|
||||
mock_verify.assert_called_once_with(
|
||||
req.environ['nova.context'], 'proj2')
|
||||
req.environ['nova.context'], uuids.proj2)
|
||||
|
@ -395,7 +395,7 @@ class KeypairsTestV210(KeypairsTestV22):
|
||||
with mock.patch.object(self.controller.api, 'get_key_pairs') as mock_g:
|
||||
self.controller.index(req)
|
||||
userid = mock_g.call_args_list[0][0][1]
|
||||
self.assertEqual('fake_user', userid)
|
||||
self.assertEqual(fakes.FAKE_USER_ID, userid)
|
||||
|
||||
|
||||
class KeypairsTestV235(test.TestCase):
|
||||
@ -421,7 +421,7 @@ class KeypairsTestV235(test.TestCase):
|
||||
res_dict = self.controller.index(req)
|
||||
|
||||
mock_kp_get.assert_called_once_with(
|
||||
req.environ['nova.context'], 'fake_user',
|
||||
req.environ['nova.context'], fakes.FAKE_USER_ID,
|
||||
limit=3, marker='fake_marker')
|
||||
response = {'keypairs': [{'keypair': dict(keypair_data, name='FAKE',
|
||||
type='ssh')}]}
|
||||
@ -458,7 +458,7 @@ class KeypairsTestV235(test.TestCase):
|
||||
self.controller.index(req)
|
||||
|
||||
mock_kp_get.assert_called_once_with(
|
||||
req.environ['nova.context'], 'fake_user',
|
||||
req.environ['nova.context'], fakes.FAKE_USER_ID,
|
||||
limit=None, marker=None)
|
||||
|
||||
|
||||
|
@ -1002,12 +1002,15 @@ class ServerActionsControllerTestV21(test.TestCase):
|
||||
response = self.controller._action_create_image(self.req, FAKE_UUID,
|
||||
body=body)
|
||||
|
||||
location = response.headers['Location']
|
||||
self.assertEqual(self.image_url + '123' if self.image_url else
|
||||
self.image_api.generate_image_url('123', self.context),
|
||||
location)
|
||||
if self.image_url:
|
||||
expected_location = self.image_url + uuids.snapshot_id
|
||||
else:
|
||||
expected_location = self.image_api.generate_image_url(
|
||||
uuids.snapshot_id, self.context
|
||||
)
|
||||
self.assertEqual(response.headers['Location'], expected_location)
|
||||
|
||||
def test_create_image_v2_45(self):
|
||||
def test_create_image_v245(self):
|
||||
"""Tests the createImage server action API with the 2.45 microversion
|
||||
where there is a response body but no Location header.
|
||||
"""
|
||||
@ -1020,7 +1023,7 @@ class ServerActionsControllerTestV21(test.TestCase):
|
||||
response = self.controller._action_create_image(req, FAKE_UUID,
|
||||
body=body)
|
||||
self.assertIsInstance(response, dict)
|
||||
self.assertEqual('123', response['image_id'])
|
||||
self.assertEqual(uuids.snapshot_id, response['image_id'])
|
||||
|
||||
def test_create_image_name_too_long(self):
|
||||
long_name = 'a' * 260
|
||||
@ -1254,9 +1257,13 @@ class ServerActionsControllerTestV21(test.TestCase):
|
||||
response = self.controller._action_create_image(self.req, FAKE_UUID,
|
||||
body=body)
|
||||
|
||||
location = response.headers['Location']
|
||||
self.assertEqual(self.image_url + '123' if self.image_url else
|
||||
self.image_api.generate_image_url('123', self.context), location)
|
||||
if self.image_url:
|
||||
expected_location = self.image_url + uuids.snapshot_id
|
||||
else:
|
||||
expected_location = self.image_api.generate_image_url(
|
||||
uuids.snapshot_id, self.context
|
||||
)
|
||||
self.assertEqual(response.headers['Location'], expected_location)
|
||||
|
||||
def test_create_image_with_too_much_metadata(self):
|
||||
body = {
|
||||
|
@ -171,7 +171,7 @@ def fake_get_inst_mappings_by_instance_uuids_from_db(*args, **kwargs):
|
||||
'transport_url': 'fake://nowhere/', 'updated_at': None,
|
||||
'database_connection': uuids.cell1, 'created_at': None,
|
||||
'disabled': False},
|
||||
'project_id': 'fake-project'
|
||||
'project_id': fakes.FAKE_PROJECT_ID,
|
||||
}]
|
||||
|
||||
|
||||
@ -265,7 +265,7 @@ class _ServersControllerTest(ControllerTest):
|
||||
return {
|
||||
"server": {
|
||||
"id": uuid,
|
||||
"user_id": "fake_user",
|
||||
"user_id": fakes.FAKE_USER_ID,
|
||||
"created": "2010-10-10T12:00:00Z",
|
||||
"updated": "2010-11-11T11:00:00Z",
|
||||
"progress": progress,
|
||||
@ -3767,6 +3767,21 @@ class ServersControllerRebuildTestV275(ControllerTest):
|
||||
microversion = '2.75'
|
||||
image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
mock_rebuild = mock.patch(
|
||||
'nova.compute.api.API.rebuild', return_value=None)
|
||||
self.mock_rebuild = mock_rebuild.start()
|
||||
self.addCleanup(mock_rebuild.stop)
|
||||
|
||||
self.mock_get_instance_host_status = self.useFixture(
|
||||
fixtures.MockPatchObject(
|
||||
compute_api.API, 'get_instance_host_status',
|
||||
return_value='UP'
|
||||
)
|
||||
).mock
|
||||
|
||||
def test_rebuild_response_no_show_server_only_attributes_old_version(self):
|
||||
# There are some old server attributes which were added only for
|
||||
# GET server APIs not for Rebuild. GET server and Rebuild server share
|
||||
@ -3799,11 +3814,29 @@ class ServersControllerRebuildTestV275(ControllerTest):
|
||||
req = fakes.HTTPRequest.blank(self.path_with_query % 'unknown=1',
|
||||
use_admin_context=True,
|
||||
version=self.microversion)
|
||||
fake_get = fakes.fake_compute_get(
|
||||
self.mock_get.side_effect = fakes.fake_compute_get(
|
||||
id=2,
|
||||
display_description="",
|
||||
uuid=FAKE_UUID,
|
||||
node="node-fake",
|
||||
reservation_id="r-1",
|
||||
launch_index=0,
|
||||
kernel_id=UUID1,
|
||||
ramdisk_id=UUID2,
|
||||
display_name="server2",
|
||||
host='host',
|
||||
root_device_name="/dev/vda",
|
||||
user_data="userdata",
|
||||
metadata={"seq": "2"},
|
||||
availability_zone='nova',
|
||||
launched_at=None,
|
||||
terminated_at=None,
|
||||
task_state="ACTIVE",
|
||||
vm_state=vm_states.ACTIVE,
|
||||
power_state=1,
|
||||
project_id=req.environ['nova.context'].project_id,
|
||||
user_id=req.environ['nova.context'].user_id)
|
||||
self.mock_get.side_effect = fake_get
|
||||
|
||||
res_dict = self.controller._action_rebuild(req, FAKE_UUID,
|
||||
body=body).obj
|
||||
for field in GET_ONLY_FIELDS:
|
||||
@ -3829,6 +3862,13 @@ class ServersControllerRebuildTestV290(ControllerTest):
|
||||
self.mock_rebuild = mock_rebuild.start()
|
||||
self.addCleanup(mock_rebuild.stop)
|
||||
|
||||
self.mock_get_instance_host_status = self.useFixture(
|
||||
fixtures.MockPatchObject(
|
||||
compute_api.API, 'get_instance_host_status',
|
||||
return_value='UP'
|
||||
)
|
||||
).mock
|
||||
|
||||
def _get_request(self, body=None):
|
||||
req = fakes.HTTPRequest.blank(
|
||||
self.path_action % FAKE_UUID,
|
||||
@ -3851,6 +3891,29 @@ class ServersControllerRebuildTestV290(ControllerTest):
|
||||
}
|
||||
req = self._get_request(body)
|
||||
|
||||
self.mock_get.side_effect = fakes.fake_compute_get(
|
||||
id=2,
|
||||
display_description="",
|
||||
uuid=FAKE_UUID,
|
||||
node="node-fake",
|
||||
reservation_id="r-1",
|
||||
launch_index=0,
|
||||
kernel_id=UUID1,
|
||||
ramdisk_id=UUID2,
|
||||
display_name="server2",
|
||||
host='host',
|
||||
root_device_name="/dev/vda",
|
||||
user_data="userdata",
|
||||
metadata={"seq": "2"},
|
||||
availability_zone='nova',
|
||||
launched_at=None,
|
||||
terminated_at=None,
|
||||
task_state="ACTIVE",
|
||||
vm_state=vm_states.ACTIVE,
|
||||
power_state=1,
|
||||
project_id=req.environ['nova.context'].project_id,
|
||||
user_id=req.environ['nova.context'].user_id)
|
||||
|
||||
# There's nothing to check here from the return value since the
|
||||
# 'rebuild' API is a cast and we immediately fetch the instance from
|
||||
# the database after this cast...which returns a mocked Instance
|
||||
@ -5826,7 +5889,7 @@ class ServersControllerCreateTest(_ServersControllerCreateTest):
|
||||
mock_count.return_value = count
|
||||
mock_get_all_p.return_value = {'project_id': fakes.FAKE_PROJECT_ID}
|
||||
mock_get_all_pu.return_value = {'project_id': fakes.FAKE_PROJECT_ID,
|
||||
'user_id': 'fake_user'}
|
||||
'user_id': fakes.FAKE_USER_ID}
|
||||
if resource in db.PER_PROJECT_QUOTAS:
|
||||
mock_get_all_p.return_value[resource] = quota
|
||||
else:
|
||||
@ -7235,7 +7298,7 @@ class ServersControllerCreateTestV274(_ServersControllerCreateTest):
|
||||
def setUp(self):
|
||||
super(ServersControllerCreateTestV274, self).setUp()
|
||||
self.req.environ['nova.context'] = fakes.FakeRequestContext(
|
||||
user_id='fake_user',
|
||||
user_id=fakes.FAKE_USER_ID,
|
||||
project_id=self.project_id,
|
||||
is_admin=True)
|
||||
self.mock_get = self.useFixture(
|
||||
@ -7533,8 +7596,8 @@ class ServersViewBuilderTest(_ServersViewBuilderTest):
|
||||
expected_server = {
|
||||
"server": {
|
||||
"id": self.uuid,
|
||||
"user_id": "fake_user",
|
||||
"tenant_id": "fake_project",
|
||||
"user_id": fakes.FAKE_USER_ID,
|
||||
"tenant_id": fakes.FAKE_PROJECT_ID,
|
||||
"updated": "2010-11-11T11:00:00Z",
|
||||
"created": "2010-10-10T12:00:00Z",
|
||||
"progress": 0,
|
||||
@ -7552,12 +7615,12 @@ class ServersViewBuilderTest(_ServersViewBuilderTest):
|
||||
},
|
||||
"flavor": {
|
||||
"id": "1",
|
||||
"links": [
|
||||
{
|
||||
"rel": "bookmark",
|
||||
"href": flavor_bookmark,
|
||||
},
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"rel": "bookmark",
|
||||
"href": flavor_bookmark,
|
||||
},
|
||||
],
|
||||
},
|
||||
"addresses": {
|
||||
'test1': [
|
||||
@ -7623,8 +7686,8 @@ class ServersViewBuilderTest(_ServersViewBuilderTest):
|
||||
expected_server = {
|
||||
"server": {
|
||||
"id": self.uuid,
|
||||
"user_id": "fake_user",
|
||||
"tenant_id": "fake_project",
|
||||
"user_id": fakes.FAKE_USER_ID,
|
||||
"tenant_id": fakes.FAKE_PROJECT_ID,
|
||||
"updated": "2010-11-11T11:00:00Z",
|
||||
"created": "2010-10-10T12:00:00Z",
|
||||
"name": "test_server",
|
||||
@ -7641,12 +7704,12 @@ class ServersViewBuilderTest(_ServersViewBuilderTest):
|
||||
},
|
||||
"flavor": {
|
||||
"id": "1",
|
||||
"links": [
|
||||
{
|
||||
"rel": "bookmark",
|
||||
"href": flavor_bookmark,
|
||||
},
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"rel": "bookmark",
|
||||
"href": flavor_bookmark,
|
||||
},
|
||||
],
|
||||
},
|
||||
"addresses": {
|
||||
'test1': [
|
||||
@ -7822,8 +7885,8 @@ class ServersViewBuilderTest(_ServersViewBuilderTest):
|
||||
expected_server = {
|
||||
"server": {
|
||||
"id": self.uuid,
|
||||
"user_id": "fake_user",
|
||||
"tenant_id": "fake_project",
|
||||
"user_id": fakes.FAKE_USER_ID,
|
||||
"tenant_id": fakes.FAKE_PROJECT_ID,
|
||||
"updated": "2010-11-11T11:00:00Z",
|
||||
"created": "2010-10-10T12:00:00Z",
|
||||
"progress": 100,
|
||||
@ -7841,12 +7904,12 @@ class ServersViewBuilderTest(_ServersViewBuilderTest):
|
||||
},
|
||||
"flavor": {
|
||||
"id": "1",
|
||||
"links": [
|
||||
{
|
||||
"rel": "bookmark",
|
||||
"href": flavor_bookmark,
|
||||
},
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"rel": "bookmark",
|
||||
"href": flavor_bookmark,
|
||||
},
|
||||
],
|
||||
},
|
||||
"addresses": {
|
||||
'test1': [
|
||||
@ -7914,8 +7977,8 @@ class ServersViewBuilderTest(_ServersViewBuilderTest):
|
||||
expected_server = {
|
||||
"server": {
|
||||
"id": self.uuid,
|
||||
"user_id": "fake_user",
|
||||
"tenant_id": "fake_project",
|
||||
"user_id": fakes.FAKE_USER_ID,
|
||||
"tenant_id": fakes.FAKE_PROJECT_ID,
|
||||
"updated": "2010-11-11T11:00:00Z",
|
||||
"created": "2010-10-10T12:00:00Z",
|
||||
"progress": 0,
|
||||
@ -7934,7 +7997,7 @@ class ServersViewBuilderTest(_ServersViewBuilderTest):
|
||||
"flavor": {
|
||||
"id": "1",
|
||||
"links": [
|
||||
{
|
||||
{
|
||||
"rel": "bookmark",
|
||||
"href": flavor_bookmark,
|
||||
},
|
||||
@ -8042,8 +8105,8 @@ class ServersViewBuilderTestV269(_ServersViewBuilderTest):
|
||||
expected = {
|
||||
"servers": [{
|
||||
"id": self.uuid,
|
||||
"user_id": "fake_user",
|
||||
"tenant_id": "fake_project",
|
||||
"user_id": fakes.FAKE_USER_ID,
|
||||
"tenant_id": fakes.FAKE_PROJECT_ID,
|
||||
"updated": "2010-11-11T11:00:00Z",
|
||||
"created": "2010-10-10T12:00:00Z",
|
||||
"progress": 0,
|
||||
@ -8225,8 +8288,8 @@ class ServersViewBuilderTestV269(_ServersViewBuilderTest):
|
||||
expected = {
|
||||
"server": {
|
||||
"id": self.uuid,
|
||||
"user_id": "fake_user",
|
||||
"tenant_id": "fake_project",
|
||||
"user_id": fakes.FAKE_USER_ID,
|
||||
"tenant_id": fakes.FAKE_PROJECT_ID,
|
||||
"created": '1955-11-05T00:00:00Z',
|
||||
"status": "UNKNOWN",
|
||||
"image": {
|
||||
@ -8288,7 +8351,7 @@ class ServersViewBuilderTestV269(_ServersViewBuilderTest):
|
||||
"server": {
|
||||
"id": self.uuid,
|
||||
"user_id": "UNKNOWN",
|
||||
"tenant_id": "fake_project",
|
||||
"tenant_id": fakes.FAKE_PROJECT_ID,
|
||||
"created": '1955-11-05T00:00:00Z',
|
||||
"status": "UNKNOWN",
|
||||
"image": "",
|
||||
|
@ -16,6 +16,7 @@
|
||||
import datetime
|
||||
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils.fixture import uuidsentinel as uuids
|
||||
from oslo_utils import timeutils
|
||||
from oslo_utils import uuidutils
|
||||
import routes
|
||||
@ -139,8 +140,10 @@ def stub_out_compute_api_snapshot(test):
|
||||
# emulate glance rejecting image names which are too long
|
||||
if len(name) > 256:
|
||||
raise exc.Invalid
|
||||
return dict(id='123', status='ACTIVE', name=name,
|
||||
properties=extra_properties)
|
||||
return {
|
||||
'id': uuids.snapshot_id, 'status': 'ACTIVE', 'name': name,
|
||||
'properties': extra_properties,
|
||||
}
|
||||
|
||||
test.stub_out('nova.compute.api.API.snapshot', snapshot)
|
||||
|
||||
@ -154,10 +157,12 @@ class stub_out_compute_api_backup(object):
|
||||
def backup(self, context, instance, name, backup_type, rotation,
|
||||
extra_properties=None):
|
||||
self.extra_props_last_call = extra_properties
|
||||
props = dict(backup_type=backup_type,
|
||||
rotation=rotation)
|
||||
props = {'backup_type': backup_type, 'rotation': rotation}
|
||||
props.update(extra_properties or {})
|
||||
return dict(id='123', status='ACTIVE', name=name, properties=props)
|
||||
return {
|
||||
'id': uuids.backup_id, 'status': 'ACTIVE', 'name': name,
|
||||
'properties': props,
|
||||
}
|
||||
|
||||
|
||||
def stub_out_nw_api(test, cls=None, private=None, publics=None):
|
||||
@ -244,11 +249,12 @@ class HTTPRequest(os_wsgi.Request):
|
||||
if use_admin_context:
|
||||
roles.append('admin')
|
||||
project_id = kwargs.pop('project_id', FAKE_PROJECT_ID)
|
||||
user_id = kwargs.pop('user_id', FAKE_USER_ID)
|
||||
version = kwargs.pop('version', os_wsgi.DEFAULT_API_VERSION)
|
||||
defaults.update(kwargs)
|
||||
out = super(HTTPRequest, cls).blank(*args, **defaults)
|
||||
out.environ['nova.context'] = FakeRequestContext(
|
||||
user_id='fake_user',
|
||||
user_id=user_id,
|
||||
project_id=project_id,
|
||||
is_admin=use_admin_context,
|
||||
roles=roles)
|
||||
@ -434,9 +440,9 @@ def stub_instance(id=1, user_id=None, project_id=None, host=None,
|
||||
services=None, trusted_certs=None, hidden=False,
|
||||
compute_id=None):
|
||||
if user_id is None:
|
||||
user_id = 'fake_user'
|
||||
user_id = FAKE_USER_ID
|
||||
if project_id is None:
|
||||
project_id = 'fake_project'
|
||||
project_id = FAKE_PROJECT_ID
|
||||
|
||||
if metadata:
|
||||
metadata = [{'key': k, 'value': v} for k, v in metadata.items()]
|
||||
|
@ -20,6 +20,7 @@ from oslo_utils import timeutils
|
||||
from nova.api.openstack.compute import migrate_server
|
||||
from nova.api.openstack.compute import servers
|
||||
from nova.compute import api as compute
|
||||
from nova.compute import power_state
|
||||
from nova.compute import vm_states
|
||||
import nova.conf
|
||||
from nova import exception
|
||||
@ -63,14 +64,18 @@ class ServersPolicyTest(base.BasePolicyTest):
|
||||
self.controller._view_builder._add_security_grps = mock.MagicMock()
|
||||
self.controller._view_builder._get_metadata = mock.MagicMock()
|
||||
self.controller._view_builder._get_addresses = mock.MagicMock()
|
||||
self.controller._view_builder._get_host_id = mock.MagicMock()
|
||||
self.controller._view_builder._get_host_id = mock.MagicMock(
|
||||
return_value=''
|
||||
)
|
||||
self.controller._view_builder._get_fault = mock.MagicMock()
|
||||
|
||||
self.instance = fake_instance.fake_instance_obj(
|
||||
self.project_member_context,
|
||||
id=1, uuid=uuids.fake_id, project_id=self.project_id,
|
||||
user_id=user_id, vm_state=vm_states.ACTIVE,
|
||||
system_metadata={}, expected_attrs=['system_metadata'])
|
||||
self.project_member_context,
|
||||
id=1, uuid=uuids.fake_id, project_id=self.project_id,
|
||||
user_id=user_id, vm_state=vm_states.ACTIVE,
|
||||
system_metadata={}, expected_attrs=['system_metadata'],
|
||||
task_state=None, power_state=power_state.SHUTDOWN,
|
||||
hostname='foo', launch_index=0)
|
||||
|
||||
self.mock_flavor = self.useFixture(
|
||||
fixtures.MockPatch('nova.compute.flavors.get_flavor_by_flavor_id'
|
||||
@ -912,7 +917,8 @@ class ServersPolicyTest(base.BasePolicyTest):
|
||||
self.assertNotIn(attr, resp['server'])
|
||||
|
||||
@mock.patch('nova.objects.BlockDeviceMappingList.bdms_by_instance_uuid')
|
||||
@mock.patch('nova.compute.api.API.get_instance_host_status')
|
||||
@mock.patch('nova.compute.api.API.get_instance_host_status',
|
||||
return_value=fields.HostStatus.UP)
|
||||
@mock.patch('nova.compute.api.API.rebuild')
|
||||
def test_server_rebuild_with_extended_attr_policy(self, mock_rebuild,
|
||||
mock_get, mock_bdm):
|
||||
@ -1011,7 +1017,8 @@ class ServersPolicyTest(base.BasePolicyTest):
|
||||
self.assertNotIn('host_status', resp['server'])
|
||||
|
||||
@mock.patch('nova.objects.BlockDeviceMappingList.bdms_by_instance_uuid')
|
||||
@mock.patch('nova.compute.api.API.get_instance_host_status')
|
||||
@mock.patch('nova.compute.api.API.get_instance_host_status',
|
||||
return_value=fields.HostStatus.UP)
|
||||
@mock.patch('nova.compute.api.API.rebuild')
|
||||
def test_server_rebuild_with_host_status_policy(self, mock_rebuild,
|
||||
mock_status, mock_bdm):
|
||||
|
Loading…
x
Reference in New Issue
Block a user