Add openstackcli support for novacli
* Added Client, Config, Behaviors, response models and extensions * Added unittests for client calls Change-Id: I149f8ec3f17c5af1766027d1e7375852dabe2a35
This commit is contained in:
parent
9955831638
commit
59fb3c1d96
15
cloudcafe/openstackcli/novacli/__init__.py
Normal file
15
cloudcafe/openstackcli/novacli/__init__.py
Normal file
@ -0,0 +1,15 @@
|
||||
"""
|
||||
Copyright 2013 Rackspace
|
||||
|
||||
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.
|
||||
"""
|
142
cloudcafe/openstackcli/novacli/behaviors.py
Normal file
142
cloudcafe/openstackcli/novacli/behaviors.py
Normal file
@ -0,0 +1,142 @@
|
||||
from time import time
|
||||
|
||||
from cafe.engine.behaviors import behavior
|
||||
|
||||
from cloudcafe.common.tools.datagen import random_string
|
||||
from cloudcafe.openstackcli.novacli.client import NovaCLI
|
||||
from cloudcafe.openstackcli.novacli.config import NovaCLI_Config
|
||||
from cloudcafe.openstackcli.common.behaviors import \
|
||||
OpenstackCLI_BaseBehavior, OpenstackCLI_BehaviorError
|
||||
|
||||
from cloudcafe.compute.servers_api.config import ServersConfig
|
||||
from cloudcafe.compute.images_api.config import ImagesConfig
|
||||
from cloudcafe.compute.flavors_api.config import FlavorsConfig
|
||||
from cloudcafe.compute.common.types import \
|
||||
NovaServerStatusTypes as ServerStates
|
||||
from cloudcafe.compute.common.exceptions import \
|
||||
TimeoutException, BuildErrorException, RequiredResourceException
|
||||
|
||||
|
||||
class NovaCLIBehaviorError(OpenstackCLI_BehaviorError):
|
||||
pass
|
||||
|
||||
|
||||
class NovaCLI_Behaviors(OpenstackCLI_BaseBehavior):
|
||||
|
||||
_default_error = NovaCLIBehaviorError
|
||||
|
||||
def __init__(
|
||||
self, nova_cli_client=None, nova_cli_config=None,
|
||||
servers_api_config=None, images_api_config=None,
|
||||
flavors_api_config=None):
|
||||
|
||||
super(NovaCLI_Behaviors, self).__init__()
|
||||
self.nova_cli_client = nova_cli_client
|
||||
self.nova_cli_config = nova_cli_config or NovaCLI_Config()
|
||||
|
||||
self.servers_api_config = servers_api_config or ServersConfig()
|
||||
self.images_api_config = images_api_config or ImagesConfig()
|
||||
self.flavors_api_config = flavors_api_config or FlavorsConfig()
|
||||
|
||||
@behavior(NovaCLI)
|
||||
def create_available_server(
|
||||
self, name, flavor=None, image=None, no_service_net=None,
|
||||
no_public=None, disk_config=None, image_with=None,
|
||||
boot_volume=None, snapshot=None, num_instances=None, meta=None,
|
||||
file_=None, key_name=None, user_data=None, availability_zone=None,
|
||||
security_groups=None, block_device_mapping=None, block_device=None,
|
||||
swap=None, ephemeral=None, hint=None, nic=None, config_drive=None):
|
||||
"""
|
||||
Expected input for non-string parameters
|
||||
|
||||
disk_config: 'auto' or 'manual'
|
||||
image-with: {key: value}
|
||||
meta: {key: value, [key2=value2, ...] }
|
||||
file_: {dst-path: src-path}
|
||||
block_device_mapping: {dev-name: mapping}
|
||||
block_device: {key=value, [key2=value2, ...] }
|
||||
ephemeral: {'size': size, ['format': format]}
|
||||
hint: {key: value}
|
||||
nic: {'net-id'=net-uuid,
|
||||
'port-id'=port-uuid,
|
||||
['v4-fixed-ip'=ip-addr]}
|
||||
|
||||
"""
|
||||
name = name or random_string('NovaCLI')
|
||||
image = image or self.images_api_config.primary_image
|
||||
flavor = flavor or self.flavors_api_config.primary_flavor
|
||||
|
||||
failures = []
|
||||
attempts = self.servers_api_config.resource_build_attempts
|
||||
for attempt in range(attempts):
|
||||
|
||||
self._log.debug(
|
||||
'Attempt {attempt} of {attempts} to create server with the '
|
||||
'NovaCLI.'.format(attempt=attempt + 1, attempts=attempts))
|
||||
|
||||
resp = self.nova_cli_client.create_server(
|
||||
name=name, flavor=flavor, image=image,
|
||||
no_service_net=no_service_net, no_public=no_public,
|
||||
disk_config=disk_config, image_with=image_with,
|
||||
boot_volume=boot_volume, snapshot=snapshot,
|
||||
num_instances=num_instances, meta=meta, file_=file_,
|
||||
key_name=key_name, user_data=user_data,
|
||||
availability_zone=availability_zone,
|
||||
security_groups=security_groups,
|
||||
block_device_mapping=block_device_mapping,
|
||||
block_device=block_device,
|
||||
swap=swap, ephemeral=ephemeral, hint=hint, nic=nic,
|
||||
config_drive=config_drive)
|
||||
server = resp.entity
|
||||
|
||||
if server is None:
|
||||
raise self._default_error("Unable to parse nova boot response")
|
||||
|
||||
try:
|
||||
resp = self.wait_for_server_status(
|
||||
server.id_, ServerStates.ACTIVE)
|
||||
# Add the password from the create request
|
||||
# into the final response
|
||||
resp.entity.admin_pass = server.admin_pass
|
||||
return resp
|
||||
except (TimeoutException, BuildErrorException) as ex:
|
||||
msg = 'Failed to build server {server_id}'.format(
|
||||
server_id=server.id_)
|
||||
self._log.exception(msg)
|
||||
failures.append(ex.message)
|
||||
self.nova_cli_client.delete_server(server.id_)
|
||||
|
||||
raise RequiredResourceException(
|
||||
'Failed to successfully build a server after '
|
||||
'{attempts} attempts: {failures}'.format(
|
||||
attempts=attempts, failures=failures))
|
||||
|
||||
def wait_for_server_status(
|
||||
self, server_id, desired_status, interval_time=None, timeout=None):
|
||||
|
||||
interval_time = int(
|
||||
interval_time or self.servers_api_config.server_status_interval)
|
||||
timeout = int(timeout or self.servers_api_config.server_build_timeout)
|
||||
end_time = time.time() + timeout
|
||||
|
||||
time.sleep(interval_time)
|
||||
while time.time() < end_time:
|
||||
resp = self.nova_cli_client.show_server(server_id)
|
||||
server = resp.entity
|
||||
|
||||
if server.status.lower() == ServerStates.ERROR.lower():
|
||||
raise BuildErrorException(
|
||||
'Build failed. Server with uuid "{0} entered ERROR status.'
|
||||
.format(server.id))
|
||||
|
||||
if server.status == desired_status:
|
||||
break
|
||||
time.sleep(interval_time)
|
||||
|
||||
else:
|
||||
raise TimeoutException(
|
||||
"wait_for_server_status ran for {0} seconds and did not "
|
||||
"observe server {1} reach the {2} status.".format(
|
||||
timeout, server_id, desired_status))
|
||||
|
||||
return resp
|
121
cloudcafe/openstackcli/novacli/client.py
Normal file
121
cloudcafe/openstackcli/novacli/client.py
Normal file
@ -0,0 +1,121 @@
|
||||
from cloudcafe.openstackcli.common.client import BaseOpenstackPythonCLI_Client
|
||||
from cloudcafe.openstackcli.novacli.models import responses
|
||||
|
||||
|
||||
class NovaCLI(BaseOpenstackPythonCLI_Client):
|
||||
|
||||
_KWMAP = {
|
||||
'os_cache': 'os-cache',
|
||||
'timings': 'timings',
|
||||
'timeout': 'timeout',
|
||||
'os_tenant_id': 'os-tenant-id',
|
||||
'os_auth_system': 'os-auth-system',
|
||||
'service_type': 'service-type',
|
||||
'service_name': 'service-name',
|
||||
'volume_service_name': 'volume-service-name',
|
||||
'os_compute_api_version': 'os-compute-api-version',
|
||||
'bypass_url': 'bypass-url',
|
||||
'os_auth_url': 'os-auth-url',
|
||||
'endpoint_type': 'endpoint-type',
|
||||
'insecure': 'insecure'}
|
||||
|
||||
# Make sure to include all openstack common cli paramaters in addition to
|
||||
# the nova specific ones
|
||||
_KWMAP.update(BaseOpenstackPythonCLI_Client._KWMAP)
|
||||
|
||||
#The client command the must precede any call to the cli
|
||||
_CMD = 'nova'
|
||||
|
||||
def __init__(
|
||||
self, os_cache=None, timings=None, timeout=None, os_tenant_id=None,
|
||||
os_auth_system=None, service_type=None, service_name=None,
|
||||
volume_service_name=None, os_compute_api_version=None,
|
||||
insecure=False, bypass_url=None, os_auth_url=None,
|
||||
endpoint_type=None, **kwargs):
|
||||
|
||||
super(NovaCLI, self).__init__(**kwargs)
|
||||
self.os_cache = os_cache
|
||||
self.timings = timings
|
||||
self.timeout = timeout
|
||||
self.os_auth_system = os_auth_system
|
||||
self.service_type = service_type
|
||||
self.service_name = service_name
|
||||
self.volume_service_name = volume_service_name
|
||||
self.os_compute_api_version = os_compute_api_version
|
||||
self.insecure = insecure
|
||||
self.bypass_url = bypass_url
|
||||
self.os_tenant_id = os_tenant_id
|
||||
self.os_auth_url = os_auth_url
|
||||
self.endpoint_type = endpoint_type
|
||||
|
||||
def create_server(
|
||||
self, name, no_service_net=None, no_public=None, disk_config=None,
|
||||
flavor=None, image=None, image_with=None, boot_volume=None,
|
||||
snapshot=None, num_instances=None, meta=None, file_=None,
|
||||
key_name=None, user_data=None, availability_zone=None,
|
||||
security_groups=None, block_device_mapping=None, block_device=None,
|
||||
swap=None, ephemeral=None, hint=None, nic=None, config_drive=None):
|
||||
"""
|
||||
Expected input for parameters
|
||||
|
||||
disk_config: 'auto' or 'manual'
|
||||
image-with: {key: value}
|
||||
meta: {key: value, [key2=value2, ...] }
|
||||
file_: {dst-path: src-path}
|
||||
block_device_mapping: {dev-name: mapping}
|
||||
block_device: {key=value, [key2=value2, ...] }
|
||||
ephemeral: {'size': size, ['format': format]}
|
||||
hint: {key: value}
|
||||
nic: {'net-id'=net-uuid,
|
||||
'port-id'=port-uuid,
|
||||
['v4-fixed-ip'=ip-addr]}
|
||||
|
||||
"""
|
||||
_cmd = 'boot'
|
||||
_kwmap = {
|
||||
'no_service_net': 'no-service-net',
|
||||
'no_public': 'no-public',
|
||||
'disk_config': 'disk-config',
|
||||
'flavor': 'flavor',
|
||||
'image': 'image',
|
||||
'image_with': 'image-with',
|
||||
'boot_volume': 'boot-volume',
|
||||
'snapshot': 'snapshot',
|
||||
'num_instances': 'num-instances',
|
||||
'meta': 'meta',
|
||||
'file_': 'file',
|
||||
'key_name': 'key-name',
|
||||
'user_data': 'user-data',
|
||||
'availability_zone': 'availability-zone',
|
||||
'security_groups': 'security-groups',
|
||||
'block_device_mapping': 'block-device-mapping',
|
||||
'block_device': 'block-device',
|
||||
'swap': 'swap',
|
||||
'ephemeral': 'ephemeral',
|
||||
'hint': 'hint',
|
||||
'nic': 'nic',
|
||||
'config_drive': 'config-drive'}
|
||||
|
||||
no_service_net = True if no_service_net else False
|
||||
no_public = True if no_public else False
|
||||
meta = self._multiplicable_flag_data_to_string('meta', meta)
|
||||
image_with = self._dict_to_string(image_with)
|
||||
file_ = self._dict_to_string(file_)
|
||||
block_device = self._dict_to_string(block_device)
|
||||
ephemeral = self._dict_to_string(ephemeral)
|
||||
hint = self._dict_to_string(hint)
|
||||
nic = self._dict_to_string(nic)
|
||||
block_device_mapping = self._dict_to_string(block_device_mapping)
|
||||
|
||||
_response_type = responses.ServerResponse
|
||||
return self._process_command()
|
||||
|
||||
def show_server(self, server_id):
|
||||
_cmd = 'show'
|
||||
_response_type = responses.ServerResponse
|
||||
return self._process_command()
|
||||
|
||||
def list_servers(self):
|
||||
_cmd = 'list'
|
||||
_response_type = responses.ServerListResponse
|
||||
return self._process_command()
|
29
cloudcafe/openstackcli/novacli/config.py
Normal file
29
cloudcafe/openstackcli/novacli/config.py
Normal file
@ -0,0 +1,29 @@
|
||||
"""
|
||||
Copyright 2013 Rackspace
|
||||
|
||||
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.
|
||||
"""
|
||||
from cloudcafe.common.models.configuration import ConfigSectionInterface
|
||||
|
||||
|
||||
class NovaCLI_Config(ConfigSectionInterface):
|
||||
|
||||
SECTION_NAME = 'nova_cli'
|
||||
|
||||
@property
|
||||
def insecure(self):
|
||||
return self.get_boolean('insecure', True)
|
||||
|
||||
@property
|
||||
def os_auth_system(self):
|
||||
return self.get('os_auth_system')
|
15
cloudcafe/openstackcli/novacli/models/__init__.py
Normal file
15
cloudcafe/openstackcli/novacli/models/__init__.py
Normal file
@ -0,0 +1,15 @@
|
||||
"""
|
||||
Copyright 2013 Rackspace
|
||||
|
||||
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.
|
||||
"""
|
51
cloudcafe/openstackcli/novacli/models/extensions.py
Normal file
51
cloudcafe/openstackcli/novacli/models/extensions.py
Normal file
@ -0,0 +1,51 @@
|
||||
from cloudcafe.openstackcli.common.models.extensions import \
|
||||
ResponseExtensionType, SingleAttributeResponseExtension
|
||||
|
||||
# Extensions defined here are registered in this list
|
||||
extensions = []
|
||||
|
||||
|
||||
class OS_DCF_show(SingleAttributeResponseExtension):
|
||||
__extends__ = 'ServerResponse'
|
||||
key_name = 'OS-DCF:diskConfig'
|
||||
attr_name = 'disk_config'
|
||||
|
||||
|
||||
class ConfigDrive(SingleAttributeResponseExtension):
|
||||
__extends__ = 'ServerResponse'
|
||||
key_name = 'config_drive'
|
||||
attr_name = 'config_drive'
|
||||
|
||||
|
||||
class OS_EXT_STS_show(object):
|
||||
__metaclass__ = ResponseExtensionType
|
||||
__extends__ = 'ServerResponse'
|
||||
_prefix = 'OS-EXT-STS'
|
||||
_sub_attr_map = {
|
||||
'OS-EXT-STS:power_state': 'power_state',
|
||||
'OS-EXT-STS:task_state': 'task_state',
|
||||
'OS-EXT-STS:vm_state': 'vm_state'}
|
||||
|
||||
def extend(cls, obj, **kwargs):
|
||||
if obj.__class__.__name__ not in cls.__extends__:
|
||||
return obj
|
||||
|
||||
for kw_name, attr_name in cls._sub_attr_map.items():
|
||||
setattr(obj, attr_name, kwargs.get(kw_name, None))
|
||||
return obj
|
||||
|
||||
|
||||
class OS_EXT_STS_list(object):
|
||||
__metaclass__ = ResponseExtensionType
|
||||
__extends__ = '_ServerListItem'
|
||||
_sub_attr_map = {
|
||||
'Power State': 'power_state',
|
||||
'Task State': 'task_state'}
|
||||
|
||||
def extend(cls, obj, **kwargs):
|
||||
if obj.__class__.__name__ not in cls.__extends__:
|
||||
return obj
|
||||
|
||||
for kw_name, attr_name in cls._sub_attr_map.items():
|
||||
setattr(obj, attr_name, kwargs.get(kw_name, None))
|
||||
return obj
|
80
cloudcafe/openstackcli/novacli/models/responses.py
Normal file
80
cloudcafe/openstackcli/novacli/models/responses.py
Normal file
@ -0,0 +1,80 @@
|
||||
# Used by models that inherit from an *Extensible* model
|
||||
from cloudcafe.openstackcli.novacli.models.extensions import extensions
|
||||
|
||||
from cloudcafe.openstackcli.common.models.responses import (
|
||||
BaseExtensibleModel, BasePrettyTableResponseModel,
|
||||
BasePrettyTableResponseListModel)
|
||||
|
||||
|
||||
class ServerResponse(BasePrettyTableResponseModel):
|
||||
|
||||
def __init__(
|
||||
self, status=None, updated=None, key_name=None, image=None,
|
||||
host_id=None, flavor=None, id_=None, user_id=None, name=None,
|
||||
admin_pass=None, tenant_id=None, created_at=None, access_ipv4=None,
|
||||
access_ipv6=None, progress=None, metadata=None,
|
||||
private_network=None, public_network=None, **kwargs):
|
||||
|
||||
super(ServerResponse, self).__init__(**kwargs)
|
||||
self.status = status
|
||||
self.updated = updated
|
||||
self.key_name = key_name
|
||||
self.image = image
|
||||
self.host_id = host_id
|
||||
self.flavor = flavor
|
||||
self.id_ = id_
|
||||
self.user_id = user_id
|
||||
self.name = name
|
||||
self.admin_pass = admin_pass
|
||||
self.tenant_id = tenant_id
|
||||
self.created_at = created_at
|
||||
self.access_ipv4 = access_ipv4
|
||||
self.access_ipv6 = access_ipv6
|
||||
self.progress = progress
|
||||
self.metadata = metadata
|
||||
self.private_network = private_network
|
||||
self.public_network = public_network
|
||||
|
||||
@classmethod
|
||||
def _prettytable_str_to_obj(cls, prettytable_string):
|
||||
kwdict = cls._property_value_table_to_dict(prettytable_string)
|
||||
kwmap = {
|
||||
'id_': 'id',
|
||||
'private_network': 'private network',
|
||||
'public_network': 'public network',
|
||||
'host_id': 'hostId',
|
||||
'access_ipv4': 'accessIPv4',
|
||||
'access_ipv6': 'accessIPv6',
|
||||
'admin_pass': 'adminPass'}
|
||||
|
||||
kwdict = cls._apply_kwmap(kwmap, kwdict)
|
||||
return ServerResponse(**kwdict)
|
||||
|
||||
|
||||
class _ServerListItem(BaseExtensibleModel):
|
||||
|
||||
def __init__(
|
||||
self, id_=None, name=None, status=None, networks=None, **kwargs):
|
||||
|
||||
super(_ServerListItem, self).__init__(**kwargs)
|
||||
self.id_ = id_
|
||||
self.name = name
|
||||
self.status = status
|
||||
self.networks = networks
|
||||
|
||||
|
||||
class ServerListResponse(BasePrettyTableResponseListModel):
|
||||
|
||||
@classmethod
|
||||
def _prettytable_str_to_obj(cls, prettytable_string):
|
||||
server_list_response = ServerListResponse()
|
||||
datatuple = cls._load_prettytable_string(prettytable_string)
|
||||
for datadict in datatuple:
|
||||
kwmap = {
|
||||
'id_': 'ID',
|
||||
'name': 'Name',
|
||||
'status': 'Status',
|
||||
'networks': 'Networks'}
|
||||
kwdict = cls._apply_kwmap(kwmap, datadict)
|
||||
server_list_response.append(_ServerListItem(**kwdict))
|
||||
return server_list_response
|
15
metatests/openstackcli/novacli/__init__.py
Normal file
15
metatests/openstackcli/novacli/__init__.py
Normal file
@ -0,0 +1,15 @@
|
||||
"""
|
||||
Copyright 2013 Rackspace
|
||||
|
||||
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.
|
||||
"""
|
199
metatests/openstackcli/novacli/client_tests.py
Normal file
199
metatests/openstackcli/novacli/client_tests.py
Normal file
@ -0,0 +1,199 @@
|
||||
import unittest
|
||||
from cloudcafe.openstackcli.novacli.client import NovaCLI
|
||||
|
||||
|
||||
class NovaCLI_InitializeClientWithAllArguments(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.novacli = NovaCLI(
|
||||
os_cache=True, timings=True, timeout=30,
|
||||
os_username='fake_username', os_password='fake_password',
|
||||
os_tenant_name='FakeTenantName', os_tenant_id='1234567',
|
||||
os_auth_url='os-auth-url', os_region_name='region_name',
|
||||
os_auth_system='auth_system', service_type='service-type',
|
||||
volume_service_name='vol serv name', endpoint_type='endpoint_type',
|
||||
os_compute_api_version='v111', os_cacert='cert_here',
|
||||
insecure=True, bypass_url='bypass_url')
|
||||
cls.base_cmd = cls.novacli.base_cmd()
|
||||
|
||||
def test_os_cache(self):
|
||||
self.assertIn('--os-cache', self.base_cmd)
|
||||
|
||||
def test_timings(self):
|
||||
self.assertIn('--timings', self.base_cmd)
|
||||
|
||||
def test_timeout(self):
|
||||
self.assertIn('--timeout 30', self.base_cmd)
|
||||
|
||||
def test_os_username(self):
|
||||
self.assertIn('--os-username fake_username', self.base_cmd)
|
||||
|
||||
def test_os_password(self):
|
||||
self.assertIn('--os-password fake_password', self.base_cmd)
|
||||
|
||||
def test_os_tenant_name(self):
|
||||
self.assertIn('--os-tenant-name FakeTenantName', self.base_cmd)
|
||||
|
||||
def test_os_tenant_id(self):
|
||||
self.assertIn('--os-tenant-id 1234567', self.base_cmd)
|
||||
|
||||
def test_os_auth_url(self):
|
||||
self.assertIn('--os-auth-url os-auth-url', self.base_cmd)
|
||||
|
||||
def test_os_region_name(self):
|
||||
self.assertIn('--os-region-name region_name', self.base_cmd)
|
||||
|
||||
def test_os_auth_system(self):
|
||||
self.assertIn('--os-auth-system auth_system', self.base_cmd)
|
||||
|
||||
def test_service_type(self):
|
||||
self.assertIn('--service-type service-type', self.base_cmd)
|
||||
|
||||
def test_volume_service_name(self):
|
||||
self.assertIn('--volume-service-name vol serv name', self.base_cmd)
|
||||
|
||||
def test_endpoint_type(self):
|
||||
self.assertIn('--endpoint-type endpoint_type', self.base_cmd)
|
||||
|
||||
def test_os_compute_api_version(self):
|
||||
self.assertIn('--os-compute-api-version v111', self.base_cmd)
|
||||
|
||||
def test_os_cacert(self):
|
||||
self.assertIn('--os-cacert cert_here', self.base_cmd)
|
||||
|
||||
def test_insecure(self):
|
||||
self.assertIn('--insecure', self.base_cmd)
|
||||
|
||||
def test_bypass_url(self):
|
||||
self.assertIn('--bypass-url bypass_url', self.base_cmd)
|
||||
|
||||
def test_no_arguments_positive(self):
|
||||
novacli = NovaCLI()
|
||||
self.assertEquals(novacli.base_cmd().strip(), 'nova')
|
||||
|
||||
|
||||
class NovaCLI_CommandSerializationTests_CreateServer(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
|
||||
class FakeResponse(object):
|
||||
def __init__(self, cmd):
|
||||
self.command = cmd
|
||||
self.standard_out = "fake standard out"
|
||||
|
||||
cls.novacli = NovaCLI()
|
||||
cls.novacli.run_command = lambda x: FakeResponse(x)
|
||||
cls.command = cls.novacli.create_server(
|
||||
name='fake name',
|
||||
no_service_net=True,
|
||||
no_public=True,
|
||||
disk_config='auto',
|
||||
flavor='fake flavor',
|
||||
image='fake image',
|
||||
boot_volume='fake boot volume',
|
||||
snapshot='fake snapshot',
|
||||
num_instances='55',
|
||||
key_name='SomeKeyName',
|
||||
user_data='SomeUserData',
|
||||
availability_zone='SomeAvailabilityZone',
|
||||
security_groups='SomeSecurityGroups',
|
||||
swap=100, # Just so that there's an int in this test.
|
||||
config_drive='/dev/sda',
|
||||
image_with={'fake_image_with_key': 'fake_image_with_value'},
|
||||
meta={
|
||||
'fake_meta_key1': 'fake_meta_value1',
|
||||
'fake_meta_key2': 'fake_meta_value2'},
|
||||
file_={'dst-path': 'src-path'},
|
||||
block_device_mapping={'dev-name': 'mapping'},
|
||||
block_device={'bdkey': 'bdvalue'},
|
||||
ephemeral={'size': 'SomeSize', 'format': 'SomeFormat'},
|
||||
hint={'HintKey': 'HintValue'},
|
||||
nic={
|
||||
'net-id': 'Some-net-uuid',
|
||||
'port-id': 'Some-port-uuid',
|
||||
'v4-fixed-ip': 'Some-ip-addr'}).command
|
||||
|
||||
def test_no_arguments(self):
|
||||
r = self.novacli.create_server("")
|
||||
self.assertEqual(r.command.strip(), "nova boot")
|
||||
|
||||
def test_name(self):
|
||||
self.assertIn("fake name", self.command)
|
||||
|
||||
def test_no_service_net(self):
|
||||
self.assertIn("--no-service-net", self.command)
|
||||
|
||||
def test_no_public(self):
|
||||
self.assertIn("--no-public", self.command)
|
||||
|
||||
def test_disk_config(self):
|
||||
self.assertIn("--disk-config auto", self.command)
|
||||
|
||||
def test_flavor(self):
|
||||
self.assertIn("--flavor fake flavor", self.command)
|
||||
|
||||
def test_image(self):
|
||||
self.assertIn("--image fake image", self.command)
|
||||
|
||||
def test_boot_volume(self):
|
||||
self.assertIn("--boot-volume fake boot volume", self.command)
|
||||
|
||||
def test_snapshot(self):
|
||||
self.assertIn("--snapshot fake snapshot", self.command)
|
||||
|
||||
def test_num_instances(self):
|
||||
self.assertIn("--num-instances 55", self.command)
|
||||
|
||||
def test_key_name(self):
|
||||
self.assertIn("--key-name SomeKeyName", self.command)
|
||||
|
||||
def test_user_data(self):
|
||||
self.assertIn("--user-data SomeUserData", self.command)
|
||||
|
||||
def test_availability_zone(self):
|
||||
self.assertIn("--availability-zone SomeAvailabilityZone", self.command)
|
||||
|
||||
def test_security_groups(self):
|
||||
self.assertIn("--security-groups SomeSecurityGroups", self.command)
|
||||
|
||||
def test_swap(self):
|
||||
self.assertIn("--swap 100", self.command)
|
||||
|
||||
def test_config_drive(self):
|
||||
self.assertIn("--config-drive /dev/sda", self.command)
|
||||
|
||||
def test_image_with(self):
|
||||
self.assertIn(
|
||||
"--image-with 'fake_image_with_key'='fake_image_with_value'",
|
||||
self.command)
|
||||
|
||||
def test_meta(self):
|
||||
self.assertIn(
|
||||
"--meta 'fake_meta_key1'='fake_meta_value1'", self.command)
|
||||
self.assertIn(
|
||||
"--meta 'fake_meta_key2'='fake_meta_value2'", self.command)
|
||||
|
||||
def test_file(self):
|
||||
self.assertIn("--file 'dst-path'='src-path'", self.command)
|
||||
|
||||
def test_block_device_mapping(self):
|
||||
self.assertIn(
|
||||
"--block-device-mapping 'dev-name'='mapping'",
|
||||
self.command)
|
||||
|
||||
def test_block_device(self):
|
||||
self.assertIn("--block-device 'bdkey'='bdvalue'", self.command)
|
||||
|
||||
def test_ephemeral(self):
|
||||
self.assertIn(
|
||||
"--ephemeral 'format'='SomeFormat' 'size'='SomeSize' ",
|
||||
self.command)
|
||||
|
||||
def test_hint(self):
|
||||
self.assertIn("--hint 'HintKey'='HintValue'", self.command)
|
||||
|
||||
def test_nic(self):
|
||||
self.assertIn(
|
||||
"--nic 'port-id'='Some-port-uuid' 'net-id'='Some-net-uuid' "
|
||||
"'v4-fixed-ip'='Some-ip-addr'", self.command)
|
15
metatests/openstackcli/novacli/models/__init__.py
Normal file
15
metatests/openstackcli/novacli/models/__init__.py
Normal file
@ -0,0 +1,15 @@
|
||||
"""
|
||||
Copyright 2013 Rackspace
|
||||
|
||||
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.
|
||||
"""
|
Loading…
Reference in New Issue
Block a user