Introduce openstackclient plugin
Adds the code necessary for ironicclient to work as a plugin for openstackclient. * baremetal list * baremetal show * baremetal delete * baremetal create * baremetal set * baremetal unset Change-Id: I91ea4f4a63b0e7a8ea004c47422d19ca0f288dcd
This commit is contained in:
parent
b5a720f7a4
commit
a5a15e40a5
0
ironicclient/osc/__init__.py
Normal file
0
ironicclient/osc/__init__.py
Normal file
51
ironicclient/osc/client.py
Normal file
51
ironicclient/osc/client.py
Normal file
@ -0,0 +1,51 @@
|
||||
# Copyright 2010 Jacob Kaplan-Moss
|
||||
# Copyright 2011 OpenStack Foundation
|
||||
# Copyright 2011 Piston Cloud Computing, Inc.
|
||||
#
|
||||
# Modified by: Brad P. Crochet <brad@redhat.com>
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""
|
||||
OpenStack Client factory.
|
||||
"""
|
||||
|
||||
from oslo_utils import importutils
|
||||
|
||||
from ironicclient.common.i18n import _
|
||||
from ironicclient import exceptions
|
||||
|
||||
|
||||
def get_client_class(version):
|
||||
version_map = {
|
||||
'1': 'ironicclient.v1.client.Client',
|
||||
'1.5': 'ironicclient.v1.client.Client',
|
||||
'1.6': 'ironicclient.v1.client.Client',
|
||||
'1.9': 'ironicclient.v1.client.Client',
|
||||
}
|
||||
try:
|
||||
client_path = version_map[str(version)]
|
||||
except (KeyError, ValueError):
|
||||
msg = _("Invalid client version '%(version)s'. must be one of: "
|
||||
"%(keys)s") % {'version': version,
|
||||
'keys': ', '.join(version_map)}
|
||||
raise exceptions.UnsupportedVersion(msg)
|
||||
|
||||
return importutils.import_class(client_path)
|
||||
|
||||
|
||||
def Client(version, *args, **kwargs):
|
||||
client_class = get_client_class(version)
|
||||
return client_class(*args, **kwargs)
|
70
ironicclient/osc/plugin.py
Normal file
70
ironicclient/osc/plugin.py
Normal file
@ -0,0 +1,70 @@
|
||||
#
|
||||
# Copyright 2015 Red Hat, Inc.
|
||||
#
|
||||
# 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 logging
|
||||
|
||||
from openstackclient.common import exceptions
|
||||
from openstackclient.common import utils
|
||||
|
||||
from ironicclient.osc import client as ironic_client
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
DEFAULT_BAREMETAL_API_VERSION = '1.6'
|
||||
API_VERSION_OPTION = 'os_baremetal_api_version'
|
||||
API_NAME = 'baremetal'
|
||||
API_VERSIONS = {
|
||||
'1': 'ironicclient.osc.client',
|
||||
'1.5': 'ironicclient.osc.client',
|
||||
'1.6': 'ironicclient.osc.client',
|
||||
'1.9': 'ironicclient.osc.client',
|
||||
}
|
||||
|
||||
|
||||
def make_client(instance):
|
||||
"""Returns a baremetal service client."""
|
||||
try:
|
||||
baremetal_client = ironic_client.get_client_class(
|
||||
instance._api_version[API_NAME])
|
||||
except Exception:
|
||||
msg = "Invalid %s client version '%s'. Must be one of %s" % (
|
||||
(API_NAME, instance._api_version[API_NAME],
|
||||
", ".join(sorted(API_VERSIONS))))
|
||||
raise exceptions.UnsupportedVersion(msg)
|
||||
LOG.debug('Instantiating baremetal client: %s', baremetal_client)
|
||||
|
||||
client = baremetal_client(
|
||||
os_ironic_api_version=instance._api_version[API_NAME],
|
||||
session=instance.session,
|
||||
region_name=instance._region_name,
|
||||
endpoint=instance.auth_ref.auth_url,
|
||||
)
|
||||
|
||||
return client
|
||||
|
||||
|
||||
def build_option_parser(parser):
|
||||
"""Hook to add global options."""
|
||||
parser.add_argument(
|
||||
'--os-baremetal-api-version',
|
||||
metavar='<baremetal-api-version>',
|
||||
default=utils.env(
|
||||
'OS_BAREMETAL_API_VERSION',
|
||||
default=DEFAULT_BAREMETAL_API_VERSION),
|
||||
help='Baremetal API version, default=' +
|
||||
DEFAULT_BAREMETAL_API_VERSION +
|
||||
' (Env: OS_BAREMETAL_API_VERSION)')
|
||||
return parser
|
0
ironicclient/osc/v1/__init__.py
Normal file
0
ironicclient/osc/v1/__init__.py
Normal file
320
ironicclient/osc/v1/baremetal.py
Normal file
320
ironicclient/osc/v1/baremetal.py
Normal file
@ -0,0 +1,320 @@
|
||||
#
|
||||
# Copyright 2015 Red Hat, Inc.
|
||||
#
|
||||
# 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 logging
|
||||
import six
|
||||
|
||||
from cliff import command
|
||||
from cliff import lister
|
||||
from cliff import show
|
||||
from openstackclient.common import utils as oscutils
|
||||
|
||||
from ironicclient.common.i18n import _
|
||||
from ironicclient.common import utils
|
||||
from ironicclient import exc
|
||||
from ironicclient.v1 import resource_fields as res_fields
|
||||
|
||||
|
||||
class CreateBaremetal(show.ShowOne):
|
||||
"""Register a new node with the baremetal service"""
|
||||
|
||||
log = logging.getLogger(__name__ + ".CreateBaremetal")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CreateBaremetal, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'--chassis-uuid',
|
||||
dest='chassis_uuid',
|
||||
metavar='<chassis>',
|
||||
help='UUID of the chassis that this node belongs to.')
|
||||
parser.add_argument(
|
||||
'--driver',
|
||||
metavar='<driver>',
|
||||
required=True,
|
||||
help='Driver used to control the node [REQUIRED].')
|
||||
parser.add_argument(
|
||||
'--driver-info',
|
||||
metavar='<key=value>',
|
||||
action='append',
|
||||
help='Key/value pair used by the driver, such as out-of-band '
|
||||
'management credentials. Can be specified multiple times.')
|
||||
parser.add_argument(
|
||||
'--property',
|
||||
dest='properties',
|
||||
metavar='<key=value>',
|
||||
action='append',
|
||||
help='Key/value pair describing the physical characteristics of '
|
||||
'the node. This is exported to Nova and used by the '
|
||||
'scheduler. Can be specified multiple times.')
|
||||
parser.add_argument(
|
||||
'--extra',
|
||||
metavar='<key=value>',
|
||||
action='append',
|
||||
help="Record arbitrary key/value metadata. "
|
||||
"Can be specified multiple times.")
|
||||
parser.add_argument(
|
||||
'--uuid',
|
||||
metavar='<uuid>',
|
||||
help="Unique UUID for the node.")
|
||||
parser.add_argument(
|
||||
'--name',
|
||||
metavar='<name>',
|
||||
help="Unique name for the node.")
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)", parsed_args)
|
||||
|
||||
baremetal_client = self.app.client_manager.baremetal
|
||||
|
||||
field_list = ['chassis_uuid', 'driver', 'driver_info',
|
||||
'properties', 'extra', 'uuid', 'name']
|
||||
fields = dict((k, v) for (k, v) in vars(parsed_args).items()
|
||||
if k in field_list and not (v is None))
|
||||
fields = utils.args_array_to_dict(fields, 'driver_info')
|
||||
fields = utils.args_array_to_dict(fields, 'extra')
|
||||
fields = utils.args_array_to_dict(fields, 'properties')
|
||||
node = baremetal_client.node.create(**fields)._info
|
||||
|
||||
node.pop('links', None)
|
||||
|
||||
return self.dict2columns(node)
|
||||
|
||||
|
||||
class DeleteBaremetal(command.Command):
|
||||
"""Unregister a baremetal node"""
|
||||
|
||||
log = logging.getLogger(__name__ + ".DeleteBaremetal")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(DeleteBaremetal, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
"node",
|
||||
metavar="<node>",
|
||||
help="Node to delete (name or ID)")
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)", parsed_args)
|
||||
|
||||
baremetal_client = self.app.client_manager.baremetal
|
||||
|
||||
node = oscutils.find_resource(baremetal_client.node,
|
||||
parsed_args.node)
|
||||
baremetal_client.node.delete(node.uuid)
|
||||
|
||||
|
||||
class ListBaremetal(lister.Lister):
|
||||
"""List baremetal nodes"""
|
||||
|
||||
log = logging.getLogger(__name__ + ".ListBaremetal")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListBaremetal, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'--limit',
|
||||
metavar='<limit>',
|
||||
type=int,
|
||||
help='Maximum number of nodes to return per request, '
|
||||
'0 for no limit. Default is the maximum number used '
|
||||
'by the Baremetal API Service.'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--marker',
|
||||
metavar='<node>',
|
||||
help='Node UUID (for example, of the last node in the list from '
|
||||
'a previous request). Returns the list of nodes after this '
|
||||
'UUID.'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--sort',
|
||||
metavar="<key>[:<direction>]",
|
||||
help='Sort output by selected keys and directions(asc or desc) '
|
||||
'(default: asc), multiple keys and directions can be '
|
||||
'specified separated by comma',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--maintenance',
|
||||
dest='maintenance',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help="List nodes in maintenance mode.",
|
||||
)
|
||||
parser.add_argument(
|
||||
'--associated',
|
||||
dest='associated',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help="List only nodes associated with an instance."
|
||||
)
|
||||
parser.add_argument(
|
||||
'--long',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help="Show detailed information about the nodes."
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)" % parsed_args)
|
||||
client = self.app.client_manager.baremetal
|
||||
|
||||
columns = res_fields.NODE_RESOURCE
|
||||
|
||||
params = {}
|
||||
if parsed_args.limit is not None and parsed_args.limit < 0:
|
||||
raise exc.CommandError(
|
||||
_('Expected non-negative --limit, got %s') %
|
||||
parsed_args.limit)
|
||||
params['limit'] = parsed_args.limit
|
||||
params['marker'] = parsed_args.marker
|
||||
if parsed_args.associated:
|
||||
params['associated'] = parsed_args.associated
|
||||
if parsed_args.maintenance:
|
||||
params['maintenance'] = parsed_args.maintenance
|
||||
|
||||
if parsed_args.long:
|
||||
columns = res_fields.NODE_DETAILED_RESOURCE
|
||||
params['detail'] = parsed_args.long
|
||||
|
||||
self.log.debug("params(%s)" % params)
|
||||
data = client.node.list(**params)
|
||||
|
||||
data = oscutils.sort_items(data, parsed_args.sort)
|
||||
|
||||
return (columns.labels,
|
||||
(oscutils.get_item_properties(s, columns.fields, formatters={
|
||||
'Properties': oscutils.format_dict},) for s in data))
|
||||
|
||||
|
||||
class SetBaremetal(command.Command):
|
||||
"""Set baremetal properties"""
|
||||
|
||||
log = logging.getLogger(__name__ + ".SetBaremetal")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(SetBaremetal, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'node',
|
||||
metavar='<node>',
|
||||
help="Name or UUID of the node."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--property",
|
||||
metavar="<path=value>",
|
||||
action='append',
|
||||
help='Property to add to this baremetal host '
|
||||
'(repeat option to set multiple properties)',
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)", parsed_args)
|
||||
|
||||
baremetal_client = self.app.client_manager.baremetal
|
||||
|
||||
properties = []
|
||||
if parsed_args.property:
|
||||
properties = utils.args_array_to_patch(
|
||||
'add', parsed_args.property)
|
||||
baremetal_client.node.update(parsed_args.node, properties)
|
||||
|
||||
|
||||
class ShowBaremetal(show.ShowOne):
|
||||
"""Show baremetal node details"""
|
||||
|
||||
log = logging.getLogger(__name__ + ".ShowBaremetal")
|
||||
LONG_FIELDS = [
|
||||
'extra',
|
||||
'properties',
|
||||
'ports',
|
||||
'driver_info',
|
||||
'driver_internal_info',
|
||||
'instance_info',
|
||||
]
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowBaremetal, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
"node",
|
||||
metavar="<node>",
|
||||
help="Name or UUID of the node (or instance UUID if --instance "
|
||||
"is specified)")
|
||||
parser.add_argument(
|
||||
'--instance',
|
||||
dest='instance_uuid',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='<node> is an instance UUID.')
|
||||
parser.add_argument(
|
||||
'--long',
|
||||
action='store_true')
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)", parsed_args)
|
||||
|
||||
baremetal_client = self.app.client_manager.baremetal
|
||||
if parsed_args.instance_uuid:
|
||||
node = baremetal_client.node.get_by_instance_uuid(
|
||||
parsed_args.node)._info
|
||||
else:
|
||||
node = oscutils.find_resource(baremetal_client.node,
|
||||
parsed_args.node)._info
|
||||
node.pop("links", None)
|
||||
if not parsed_args.long:
|
||||
for field in self.LONG_FIELDS:
|
||||
node.pop(field, None)
|
||||
|
||||
return zip(*sorted(six.iteritems(node)))
|
||||
|
||||
|
||||
class UnsetBaremetal(command.Command):
|
||||
"""Unset baremetal properties"""
|
||||
log = logging.getLogger(__name__ + ".UnsetBaremetal")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(UnsetBaremetal, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'node',
|
||||
metavar='<node>',
|
||||
help="Name or UUID of the node."
|
||||
)
|
||||
parser.add_argument(
|
||||
'--property',
|
||||
metavar='<path>',
|
||||
action='append',
|
||||
help='Property to unset on this baremetal host '
|
||||
'(repeat option to unset multiple properties)',
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)", parsed_args)
|
||||
|
||||
baremetal_client = self.app.client_manager.baremetal
|
||||
|
||||
if not parsed_args.node and not parsed_args.property:
|
||||
return
|
||||
|
||||
patch = utils.args_array_to_patch('remove', parsed_args.property)
|
||||
baremetal_client.node.update(parsed_args.node, patch)
|
0
ironicclient/tests/unit/osc/__init__.py
Normal file
0
ironicclient/tests/unit/osc/__init__.py
Normal file
58
ironicclient/tests/unit/osc/fakes.py
Normal file
58
ironicclient/tests/unit/osc/fakes.py
Normal file
@ -0,0 +1,58 @@
|
||||
#
|
||||
# Copyright 2015 Red Hat, Inc.
|
||||
#
|
||||
# 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 sys
|
||||
|
||||
import six
|
||||
|
||||
|
||||
AUTH_TOKEN = "foobar"
|
||||
AUTH_URL = "http://0.0.0.0"
|
||||
|
||||
|
||||
class FakeApp(object):
|
||||
def __init__(self):
|
||||
_stdout = None
|
||||
self.client_manager = None
|
||||
self.stdin = sys.stdin
|
||||
self.stdout = _stdout or sys.stdout
|
||||
self.stderr = sys.stderr
|
||||
self.restapi = None
|
||||
|
||||
|
||||
class FakeClientManager(object):
|
||||
def __init__(self):
|
||||
self.identity = None
|
||||
self.auth_ref = None
|
||||
|
||||
|
||||
class FakeResource(object):
|
||||
def __init__(self, manager, info, loaded=False):
|
||||
self.__name__ = type(self).__name__
|
||||
self.manager = manager
|
||||
self._info = info
|
||||
self._add_details(info)
|
||||
self._loaded = loaded
|
||||
|
||||
def _add_details(self, info):
|
||||
for (k, v) in six.iteritems(info):
|
||||
setattr(self, k, v)
|
||||
|
||||
def __repr__(self):
|
||||
reprkeys = sorted(k for k in self.__dict__.keys() if k[0] != '_' and
|
||||
k != 'manager')
|
||||
info = ", ".join("%s=%s" % (k, getattr(self, k)) for k in reprkeys)
|
||||
return "<%s %s>" % (self.__class__.__name__, info)
|
0
ironicclient/tests/unit/osc/v1/__init__.py
Normal file
0
ironicclient/tests/unit/osc/v1/__init__.py
Normal file
52
ironicclient/tests/unit/osc/v1/fakes.py
Normal file
52
ironicclient/tests/unit/osc/v1/fakes.py
Normal file
@ -0,0 +1,52 @@
|
||||
#
|
||||
# Copyright 2015 Red Hat, Inc.
|
||||
#
|
||||
# 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 mock
|
||||
from openstackclient.tests import utils
|
||||
|
||||
from ironicclient.tests.unit.osc import fakes
|
||||
|
||||
baremetal_uuid = 'xxx-xxxxxx-xxxx'
|
||||
baremetal_name = 'fake name'
|
||||
baremetal_instance_uuid = 'yyy-yyyyyy-yyyy'
|
||||
baremetal_power_state = None
|
||||
baremetal_provision_state = None
|
||||
baremetal_maintenance = False
|
||||
|
||||
BAREMETAL = {
|
||||
'uuid': baremetal_uuid,
|
||||
'name': baremetal_name,
|
||||
'instance_uuid': baremetal_instance_uuid,
|
||||
'power_state': baremetal_power_state,
|
||||
'provision_state': baremetal_provision_state,
|
||||
'maintenance': baremetal_maintenance,
|
||||
'links': []
|
||||
}
|
||||
|
||||
|
||||
class TestBaremetal(utils.TestCommand):
|
||||
|
||||
def setUp(self):
|
||||
super(TestBaremetal, self).setUp()
|
||||
|
||||
self.app.client_manager.auth_ref = mock.Mock(auth_token="TOKEN")
|
||||
self.app.client_manager.baremetal = mock.Mock()
|
||||
|
||||
|
||||
class FakeBaremetalResource(fakes.FakeResource):
|
||||
|
||||
def get_keys(self):
|
||||
return {'property': 'value'}
|
515
ironicclient/tests/unit/osc/v1/test_baremetal.py
Normal file
515
ironicclient/tests/unit/osc/v1/test_baremetal.py
Normal file
@ -0,0 +1,515 @@
|
||||
#
|
||||
# Copyright 2015 Red Hat, Inc.
|
||||
#
|
||||
# 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 copy
|
||||
|
||||
from openstackclient.tests import utils as oscutils
|
||||
|
||||
from ironicclient.osc.v1 import baremetal
|
||||
from ironicclient.tests.unit.osc.v1 import fakes as baremetal_fakes
|
||||
|
||||
|
||||
class TestBaremetal(baremetal_fakes.TestBaremetal):
|
||||
|
||||
def setUp(self):
|
||||
super(TestBaremetal, self).setUp()
|
||||
|
||||
# Get a shortcut to the FlavorManager Mock
|
||||
self.baremetal_mock = self.app.client_manager.baremetal
|
||||
self.baremetal_mock.reset_mock()
|
||||
|
||||
|
||||
class TestBaremetalCreate(TestBaremetal):
|
||||
def setUp(self):
|
||||
super(TestBaremetalCreate, self).setUp()
|
||||
|
||||
self.baremetal_mock.node.create.return_value = (
|
||||
baremetal_fakes.FakeBaremetalResource(
|
||||
None,
|
||||
copy.deepcopy(baremetal_fakes.BAREMETAL),
|
||||
loaded=True,
|
||||
))
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = baremetal.CreateBaremetal(self.app, None)
|
||||
self.arglist = ['--driver', 'fake_driver']
|
||||
self.verifylist = [('driver', 'fake_driver')]
|
||||
self.collist = (
|
||||
'instance_uuid',
|
||||
'maintenance',
|
||||
'name',
|
||||
'power_state',
|
||||
'provision_state',
|
||||
'uuid'
|
||||
)
|
||||
self.datalist = (
|
||||
'yyy-yyyyyy-yyyy',
|
||||
baremetal_fakes.baremetal_maintenance,
|
||||
baremetal_fakes.baremetal_name,
|
||||
baremetal_fakes.baremetal_power_state,
|
||||
baremetal_fakes.baremetal_provision_state,
|
||||
baremetal_fakes.baremetal_uuid,
|
||||
)
|
||||
self.actual_kwargs = {
|
||||
'driver': 'fake_driver',
|
||||
}
|
||||
|
||||
def check_with_options(self, addl_arglist, addl_verifylist, addl_kwargs):
|
||||
arglist = copy.copy(self.arglist) + addl_arglist
|
||||
verifylist = copy.copy(self.verifylist) + addl_verifylist
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
# DisplayCommandBase.take_action() returns two tuples
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
collist = copy.copy(self.collist)
|
||||
self.assertEqual(collist, columns)
|
||||
|
||||
datalist = copy.copy(self.datalist)
|
||||
self.assertEqual(datalist, tuple(data))
|
||||
|
||||
kwargs = copy.copy(self.actual_kwargs)
|
||||
kwargs.update(addl_kwargs)
|
||||
|
||||
self.baremetal_mock.node.create.assert_called_once_with(**kwargs)
|
||||
|
||||
def test_baremetal_create_no_options(self):
|
||||
arglist = []
|
||||
verifylist = []
|
||||
|
||||
self.assertRaises(oscutils.ParserException,
|
||||
self.check_parser,
|
||||
self.cmd, arglist, verifylist)
|
||||
|
||||
def test_baremetal_create_with_driver(self):
|
||||
arglist = copy.copy(self.arglist)
|
||||
|
||||
verifylist = copy.copy(self.verifylist)
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
# DisplayCommandBase.take_action() returns two tuples
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
collist = copy.copy(self.collist)
|
||||
self.assertEqual(collist, columns)
|
||||
|
||||
datalist = copy.copy(self.datalist)
|
||||
self.assertEqual(datalist, tuple(data))
|
||||
|
||||
kwargs = copy.copy(self.actual_kwargs)
|
||||
|
||||
self.baremetal_mock.node.create.assert_called_once_with(**kwargs)
|
||||
|
||||
def test_baremetal_create_with_chassis(self):
|
||||
self.check_with_options(['--chassis', 'chassis_uuid'],
|
||||
[('chassis_uuid', 'chassis_uuid')],
|
||||
{'chassis_uuid': 'chassis_uuid'})
|
||||
|
||||
def test_baremetal_create_with_driver_info(self):
|
||||
self.check_with_options(['--driver-info', 'arg1=val1',
|
||||
'--driver-info', 'arg2=val2'],
|
||||
[('driver_info',
|
||||
['arg1=val1',
|
||||
'arg2=val2'])],
|
||||
{'driver_info': {
|
||||
'arg1': 'val1',
|
||||
'arg2': 'val2'}})
|
||||
|
||||
def test_baremetal_create_with_properties(self):
|
||||
self.check_with_options(['--property', 'arg1=val1',
|
||||
'--property', 'arg2=val2'],
|
||||
[('properties',
|
||||
['arg1=val1',
|
||||
'arg2=val2'])],
|
||||
{'properties': {
|
||||
'arg1': 'val1',
|
||||
'arg2': 'val2'}})
|
||||
|
||||
def test_baremetal_create_with_extra(self):
|
||||
self.check_with_options(['--extra', 'arg1=val1',
|
||||
'--extra', 'arg2=val2'],
|
||||
[('extra',
|
||||
['arg1=val1',
|
||||
'arg2=val2'])],
|
||||
{'extra': {
|
||||
'arg1': 'val1',
|
||||
'arg2': 'val2'}})
|
||||
|
||||
def test_baremetal_create_with_uuid(self):
|
||||
self.check_with_options(['--uuid', 'uuid'],
|
||||
[('uuid', 'uuid')],
|
||||
{'uuid': 'uuid'})
|
||||
|
||||
def test_baremetal_create_with_name(self):
|
||||
self.check_with_options(['--name', 'name'],
|
||||
[('name', 'name')],
|
||||
{'name': 'name'})
|
||||
|
||||
|
||||
class TestBaremetalDelete(TestBaremetal):
|
||||
def setUp(self):
|
||||
super(TestBaremetalDelete, self).setUp()
|
||||
|
||||
self.baremetal_mock.node.get.return_value = (
|
||||
baremetal_fakes.FakeBaremetalResource(
|
||||
None,
|
||||
copy.deepcopy(baremetal_fakes.BAREMETAL),
|
||||
loaded=True,
|
||||
))
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = baremetal.DeleteBaremetal(self.app, None)
|
||||
|
||||
def test_baremetal_delete(self):
|
||||
arglist = ['xxx-xxxxxx-xxxx']
|
||||
verifylist = []
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
# Set expected values
|
||||
args = ['xxx-xxxxxx-xxxx']
|
||||
|
||||
self.baremetal_mock.node.delete.assert_called_with(
|
||||
*args
|
||||
)
|
||||
|
||||
|
||||
class TestBaremetalList(TestBaremetal):
|
||||
|
||||
def setUp(self):
|
||||
super(TestBaremetalList, self).setUp()
|
||||
|
||||
self.baremetal_mock.node.list.return_value = [
|
||||
baremetal_fakes.FakeBaremetalResource(
|
||||
None,
|
||||
copy.deepcopy(baremetal_fakes.BAREMETAL),
|
||||
loaded=True,
|
||||
),
|
||||
]
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = baremetal.ListBaremetal(self.app, None)
|
||||
|
||||
def test_baremetal_list_no_options(self):
|
||||
arglist = []
|
||||
verifylist = []
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
# DisplayCommandBase.take_action() returns two tuples
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
# Set expected values
|
||||
kwargs = {
|
||||
'detail': False,
|
||||
'marker': None,
|
||||
'limit': None,
|
||||
}
|
||||
|
||||
self.baremetal_mock.node.list.assert_called_with(
|
||||
**kwargs
|
||||
)
|
||||
|
||||
collist = (
|
||||
"UUID",
|
||||
"Name",
|
||||
"Instance UUID",
|
||||
"Power State",
|
||||
"Provisioning State",
|
||||
"Maintenance"
|
||||
)
|
||||
self.assertEqual(collist, columns)
|
||||
datalist = ((
|
||||
baremetal_fakes.baremetal_uuid,
|
||||
baremetal_fakes.baremetal_name,
|
||||
baremetal_fakes.baremetal_instance_uuid,
|
||||
baremetal_fakes.baremetal_power_state,
|
||||
baremetal_fakes.baremetal_provision_state,
|
||||
baremetal_fakes.baremetal_maintenance,
|
||||
), )
|
||||
self.assertEqual(datalist, tuple(data))
|
||||
|
||||
def test_baremetal_list_long(self):
|
||||
arglist = [
|
||||
'--long',
|
||||
]
|
||||
verifylist = [
|
||||
('long', True),
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
# DisplayCommandBase.take_action() returns two tuples
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
# Set expected values
|
||||
kwargs = {
|
||||
'detail': True,
|
||||
'marker': None,
|
||||
'limit': None,
|
||||
}
|
||||
|
||||
self.baremetal_mock.node.list.assert_called_with(
|
||||
**kwargs
|
||||
)
|
||||
|
||||
collist = ('Chassis UUID', 'Created At', 'Clean Step',
|
||||
'Console Enabled', 'Driver', 'Driver Info',
|
||||
'Driver Internal Info', 'Extra', 'Instance Info',
|
||||
'Instance UUID', 'Last Error', 'Maintenance',
|
||||
'Maintenance Reason', 'Power State', 'Properties',
|
||||
'Provisioning State', 'Provision Updated At', 'Reservation',
|
||||
'Target Power State', 'Target Provision State',
|
||||
'Updated At', 'Inspection Finished At',
|
||||
'Inspection Started At', 'UUID', 'Name')
|
||||
self.assertEqual(collist, columns)
|
||||
datalist = ((
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
baremetal_fakes.baremetal_instance_uuid,
|
||||
'',
|
||||
baremetal_fakes.baremetal_maintenance,
|
||||
'',
|
||||
baremetal_fakes.baremetal_power_state,
|
||||
'',
|
||||
baremetal_fakes.baremetal_provision_state,
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
baremetal_fakes.baremetal_uuid,
|
||||
baremetal_fakes.baremetal_name,
|
||||
), )
|
||||
self.assertEqual(datalist, tuple(data))
|
||||
|
||||
|
||||
class TestBaremetalSet(TestBaremetal):
|
||||
def setUp(self):
|
||||
super(TestBaremetalSet, self).setUp()
|
||||
|
||||
self.baremetal_mock.node.update.return_value = (
|
||||
baremetal_fakes.FakeBaremetalResource(
|
||||
None,
|
||||
copy.deepcopy(baremetal_fakes.BAREMETAL),
|
||||
loaded=True,
|
||||
))
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = baremetal.SetBaremetal(self.app, None)
|
||||
|
||||
def test_baremetal_set_no_options(self):
|
||||
arglist = []
|
||||
verifylist = []
|
||||
|
||||
self.assertRaises(oscutils.ParserException,
|
||||
self.check_parser,
|
||||
self.cmd, arglist, verifylist)
|
||||
|
||||
def test_baremetal_set_one_property(self):
|
||||
arglist = ['node_uuid', '--property', 'path/to/property=value']
|
||||
verifylist = [
|
||||
('node', 'node_uuid'),
|
||||
('property', ['path/to/property=value']),
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
self.baremetal_mock.node.update.assert_called_once_with(
|
||||
'node_uuid',
|
||||
[{'path': '/path/to/property', 'value': 'value', 'op': 'add'}])
|
||||
|
||||
def test_baremetal_set_multiple_properties(self):
|
||||
arglist = [
|
||||
'node_uuid',
|
||||
'--property', 'path/to/property=value',
|
||||
'--property', 'other/path=value2'
|
||||
]
|
||||
verifylist = [
|
||||
('node', 'node_uuid'),
|
||||
('property',
|
||||
[
|
||||
'path/to/property=value',
|
||||
'other/path=value2',
|
||||
]),
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
self.baremetal_mock.node.update.assert_called_once_with(
|
||||
'node_uuid',
|
||||
[{'path': '/path/to/property', 'value': 'value', 'op': 'add'},
|
||||
{'path': '/other/path', 'value': 'value2', 'op': 'add'}]
|
||||
)
|
||||
|
||||
|
||||
class TestBaremetalShow(TestBaremetal):
|
||||
def setUp(self):
|
||||
super(TestBaremetalShow, self).setUp()
|
||||
|
||||
self.baremetal_mock.node.get.return_value = (
|
||||
baremetal_fakes.FakeBaremetalResource(
|
||||
None,
|
||||
copy.deepcopy(baremetal_fakes.BAREMETAL),
|
||||
loaded=True,
|
||||
))
|
||||
|
||||
self.baremetal_mock.node.get_by_instance_uuid.return_value = (
|
||||
baremetal_fakes.FakeBaremetalResource(
|
||||
None,
|
||||
copy.deepcopy(baremetal_fakes.BAREMETAL),
|
||||
loaded=True,
|
||||
))
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = baremetal.ShowBaremetal(self.app, None)
|
||||
|
||||
def test_baremetal_show(self):
|
||||
arglist = ['xxx-xxxxxx-xxxx']
|
||||
verifylist = []
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
# DisplayCommandBase.take_action() returns two tuples
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
# Set expected values
|
||||
args = ['xxx-xxxxxx-xxxx']
|
||||
|
||||
self.baremetal_mock.node.get.assert_called_with(
|
||||
*args
|
||||
)
|
||||
|
||||
collist = (
|
||||
'instance_uuid',
|
||||
'maintenance',
|
||||
'name',
|
||||
'power_state',
|
||||
'provision_state',
|
||||
'uuid'
|
||||
)
|
||||
self.assertEqual(collist, columns)
|
||||
datalist = (
|
||||
'yyy-yyyyyy-yyyy',
|
||||
baremetal_fakes.baremetal_maintenance,
|
||||
baremetal_fakes.baremetal_name,
|
||||
baremetal_fakes.baremetal_power_state,
|
||||
baremetal_fakes.baremetal_provision_state,
|
||||
baremetal_fakes.baremetal_uuid
|
||||
)
|
||||
self.assertEqual(datalist, tuple(data))
|
||||
|
||||
def test_baremetal_show_no_node(self):
|
||||
arglist = []
|
||||
verifylist = []
|
||||
|
||||
self.assertRaises(oscutils.ParserException,
|
||||
self.check_parser,
|
||||
self.cmd, arglist, verifylist)
|
||||
|
||||
def test_baremetal_show_with_instance_uuid(self):
|
||||
arglist = [
|
||||
'xxx-xxxxxx-xxxx',
|
||||
'--instance',
|
||||
]
|
||||
|
||||
verifylist = [
|
||||
('instance_uuid', True)
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
# DisplayCommandBase.take_action() returns two tuples
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
# Set expected values
|
||||
args = ['xxx-xxxxxx-xxxx']
|
||||
|
||||
self.baremetal_mock.node.get_by_instance_uuid.assert_called_with(
|
||||
*args
|
||||
)
|
||||
|
||||
|
||||
class TestBaremetalUnset(TestBaremetal):
|
||||
def setUp(self):
|
||||
super(TestBaremetalUnset, self).setUp()
|
||||
|
||||
self.baremetal_mock.node.update.return_value = (
|
||||
baremetal_fakes.FakeBaremetalResource(
|
||||
None,
|
||||
copy.deepcopy(baremetal_fakes.BAREMETAL),
|
||||
loaded=True,
|
||||
))
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = baremetal.UnsetBaremetal(self.app, None)
|
||||
|
||||
def test_baremetal_unset_no_options(self):
|
||||
arglist = []
|
||||
verifylist = []
|
||||
|
||||
self.assertRaises(oscutils.ParserException,
|
||||
self.check_parser,
|
||||
self.cmd, arglist, verifylist)
|
||||
|
||||
def test_baremetal_unset_one_property(self):
|
||||
arglist = ['node_uuid', '--property', 'path/to/property']
|
||||
verifylist = [('node', 'node_uuid'),
|
||||
('property', ['path/to/property'])]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
self.baremetal_mock.node.update.assert_called_once_with(
|
||||
'node_uuid',
|
||||
[{'path': '/path/to/property', 'op': 'remove'}])
|
||||
|
||||
def test_baremetal_unset_multiple_properties(self):
|
||||
arglist = ['node_uuid',
|
||||
'--property', 'path/to/property',
|
||||
'--property', 'other/path']
|
||||
verifylist = [('node', 'node_uuid'),
|
||||
('property',
|
||||
['path/to/property',
|
||||
'other/path'])]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.cmd.take_action(parsed_args)
|
||||
|
||||
self.baremetal_mock.node.update.assert_called_once_with(
|
||||
'node_uuid',
|
||||
[{'path': '/path/to/property', 'op': 'remove'},
|
||||
{'path': '/other/path', 'op': 'remove'}]
|
||||
)
|
@ -5,10 +5,12 @@ pbr<2.0,>=1.4
|
||||
anyjson>=0.3.3
|
||||
appdirs>=1.3.0 # MIT License
|
||||
dogpile.cache>=0.5.4
|
||||
cliff>=1.14.0 # Apache-2.0
|
||||
httplib2>=0.7.5
|
||||
lxml>=2.3
|
||||
oslo.i18n>=1.5.0 # Apache-2.0
|
||||
oslo.utils>=2.0.0 # Apache-2.0
|
||||
PrettyTable<0.8,>=0.7
|
||||
python-keystoneclient>=1.6.0
|
||||
python-openstackclient>=1.5.0
|
||||
six>=1.9.0
|
||||
|
11
setup.cfg
11
setup.cfg
@ -25,6 +25,17 @@ packages = ironicclient
|
||||
console_scripts =
|
||||
ironic = ironicclient.shell:main
|
||||
|
||||
openstack.cli.extension =
|
||||
baremetal = ironicclient.osc.plugin
|
||||
|
||||
openstack.baremetal.v1 =
|
||||
baremetal_create = ironicclient.osc.v1.baremetal:CreateBaremetal
|
||||
baremetal_delete = ironicclient.osc.v1.baremetal:DeleteBaremetal
|
||||
baremetal_list = ironicclient.osc.v1.baremetal:ListBaremetal
|
||||
baremetal_set = ironicclient.osc.v1.baremetal:SetBaremetal
|
||||
baremetal_show = ironicclient.osc.v1.baremetal:ShowBaremetal
|
||||
baremetal_unset = ironicclient.osc.v1.baremetal:UnsetBaremetal
|
||||
|
||||
[pbr]
|
||||
autodoc_index_modules = True
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user