Add node aggregate commands support
Partially Implements: bp node-aggregate Change-Id: I37a3da4e4f35aba5efda66a62777e70476b07676
This commit is contained in:
parent
bab9a4fc01
commit
01c02f8f7b
228
moganclient/osc/v1/aggregate.py
Normal file
228
moganclient/osc/v1/aggregate.py
Normal file
@ -0,0 +1,228 @@
|
||||
# Copyright 2017 Huawei, Inc. 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.
|
||||
#
|
||||
|
||||
"""Mogan v1 Baremetal node aggregate action implementations"""
|
||||
|
||||
import copy
|
||||
import logging
|
||||
|
||||
from osc_lib.cli import parseractions
|
||||
from osc_lib.command import command
|
||||
from osc_lib import exceptions
|
||||
from osc_lib import utils
|
||||
|
||||
from moganclient.common.i18n import _
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CreateAggregate(command.ShowOne):
|
||||
"""Create a node aggregate"""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CreateAggregate, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
"name",
|
||||
metavar="<name>",
|
||||
help=_("Name of baremetal node aggregate")
|
||||
)
|
||||
parser.add_argument(
|
||||
"--property",
|
||||
metavar="<key=value>",
|
||||
action=parseractions.KeyValueAction,
|
||||
help=_("Property to add to this node aggregate "
|
||||
"(repeat option to set multiple properties)")
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
bc_client = self.app.client_manager.baremetal_compute
|
||||
data = bc_client.aggregate.create(parsed_args.name,
|
||||
parsed_args.property)
|
||||
# Special mapping for columns to make the output easier to read:
|
||||
# 'metadata' --> 'properties'
|
||||
data._info.update(
|
||||
{
|
||||
'properties': utils.format_dict(data._info.pop('metadata')),
|
||||
},
|
||||
)
|
||||
info = copy.copy(data._info)
|
||||
return zip(*sorted(info.items()))
|
||||
|
||||
|
||||
class DeleteAggregate(command.Command):
|
||||
"""Delete existing baremetal node aggregate(s)"""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(DeleteAggregate, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'aggregate',
|
||||
metavar='<aggregate>',
|
||||
nargs='+',
|
||||
help=_("Aggregate(s) to delete (name or UUID)")
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
bc_client = self.app.client_manager.baremetal_compute
|
||||
result = 0
|
||||
for one_aggregate in parsed_args.aggregate:
|
||||
try:
|
||||
data = utils.find_resource(
|
||||
bc_client.aggregate, one_aggregate)
|
||||
bc_client.aggregate.delete(data.uuid)
|
||||
except Exception as e:
|
||||
result += 1
|
||||
LOG.error(_("Failed to delete node aggregate with name or "
|
||||
"UUID '%(aggregate)s': %(e)s") %
|
||||
{'aggregate': one_aggregate, 'e': e})
|
||||
|
||||
if result > 0:
|
||||
total = len(parsed_args.aggregate)
|
||||
msg = (_("%(result)s of %(total)s node aggregates failed "
|
||||
"to delete.") % {'result': result, 'total': total})
|
||||
raise exceptions.CommandError(msg)
|
||||
|
||||
|
||||
class ListAggregate(command.Lister):
|
||||
"""List all baremetal node aggregates"""
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
bc_client = self.app.client_manager.baremetal_compute
|
||||
|
||||
data = bc_client.aggregate.list()
|
||||
|
||||
column_headers = (
|
||||
"UUID",
|
||||
"Name",
|
||||
"Properties",
|
||||
)
|
||||
columns = (
|
||||
"UUID",
|
||||
"Name",
|
||||
"Metadata",
|
||||
)
|
||||
formatters = {'Metadata': utils.format_dict}
|
||||
return (column_headers,
|
||||
(utils.get_item_properties(
|
||||
s, columns, formatters=formatters
|
||||
) for s in data))
|
||||
|
||||
|
||||
class ShowAggregate(command.ShowOne):
|
||||
"""Display baremetal node aggregate details"""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowAggregate, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'aggregate',
|
||||
metavar='<aggregate>',
|
||||
help=_("Aggregate to display (name or UUID)")
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
bc_client = self.app.client_manager.baremetal_compute
|
||||
data = utils.find_resource(
|
||||
bc_client.aggregate,
|
||||
parsed_args.aggregate,
|
||||
)
|
||||
# Special mapping for columns to make the output easier to read:
|
||||
# 'metadata' --> 'properties'
|
||||
data._info.update(
|
||||
{
|
||||
'properties': utils.format_dict(data._info.pop('metadata')),
|
||||
},
|
||||
)
|
||||
|
||||
info = {}
|
||||
info.update(data._info)
|
||||
return zip(*sorted(info.items()))
|
||||
|
||||
|
||||
class SetAggregate(command.Command):
|
||||
"""Set properties for a baremetal node aggregate"""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(SetAggregate, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'aggregate',
|
||||
metavar='<aggregate>',
|
||||
help=_("Aggregate(s) to delete (name or UUID)")
|
||||
)
|
||||
parser.add_argument(
|
||||
'--name',
|
||||
metavar='<name>',
|
||||
help=_('Set a new name to a node aggregate (admin only)')
|
||||
)
|
||||
parser.add_argument(
|
||||
"--property",
|
||||
metavar="<key=value>",
|
||||
action=parseractions.KeyValueAction,
|
||||
help=_("Property to set on this node aggregate "
|
||||
"(repeat option to set multiple properties)")
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
bc_client = self.app.client_manager.baremetal_compute
|
||||
aggregate = utils.find_resource(
|
||||
bc_client.aggregate,
|
||||
parsed_args.aggregate,
|
||||
)
|
||||
updates = []
|
||||
if parsed_args.name:
|
||||
updates.append({"op": "replace",
|
||||
"path": "/name",
|
||||
"value": parsed_args.name})
|
||||
for key, value in (parsed_args.property or {}).items():
|
||||
updates.append({"op": "add",
|
||||
"path": "/metadata/%s" % key,
|
||||
"value": value})
|
||||
if updates:
|
||||
bc_client.aggregate.update(aggregate, updates)
|
||||
|
||||
|
||||
class UnsetAggregate(command.Command):
|
||||
"""Unset properties for a baremetal node aggregate"""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(UnsetAggregate, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'aggregate',
|
||||
metavar='<aggregate>',
|
||||
help=_("Aggregate(s) to delete (name or UUID)")
|
||||
)
|
||||
parser.add_argument(
|
||||
"--property",
|
||||
metavar="<key>",
|
||||
action='append',
|
||||
help=_("Property to remove from this node aggregate "
|
||||
"(repeat option to remove multiple properties)")
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
bc_client = self.app.client_manager.baremetal_compute
|
||||
aggregate = utils.find_resource(
|
||||
bc_client.aggregate,
|
||||
parsed_args.aggregate,
|
||||
)
|
||||
updates = []
|
||||
for key in parsed_args.property or []:
|
||||
updates.append({"op": "remove",
|
||||
"path": "/metadata/%s" % key})
|
||||
if updates:
|
||||
bc_client.aggregate.update(aggregate, updates)
|
@ -21,6 +21,7 @@ from oslo_utils import uuidutils
|
||||
from requests import Response
|
||||
|
||||
from moganclient.common import base
|
||||
from moganclient.v1 import aggregate
|
||||
from moganclient.v1 import availability_zone
|
||||
from moganclient.v1 import flavor
|
||||
from moganclient.v1 import node
|
||||
@ -67,6 +68,7 @@ class FakeBaremetalComputeV1Client(object):
|
||||
self.availability_zone = availability_zone.AvailabilityZoneManager(
|
||||
self.fake_http_client)
|
||||
self.node = node.NodeManager(self.fake_http_client)
|
||||
self.aggregate = aggregate.AggregateManager(self.fake_http_client)
|
||||
|
||||
|
||||
class FakeHTTPClient(object):
|
||||
@ -323,3 +325,74 @@ class FakeServer(object):
|
||||
if servers is None:
|
||||
servers = FakeServer.create_servers(count)
|
||||
return mock.Mock(side_effect=servers)
|
||||
|
||||
|
||||
class FakeAggregate(object):
|
||||
"""Fake one baremetal node aggregate."""
|
||||
|
||||
@staticmethod
|
||||
def create_one_aggregate(attrs=None):
|
||||
"""Create a fake baremetal aggregate.
|
||||
|
||||
:param Dictionary attrs:
|
||||
A dictionary with all attributes
|
||||
:return:
|
||||
A FakeResource object, with uuid and other attributes
|
||||
"""
|
||||
attrs = attrs or {}
|
||||
|
||||
# Set default attribute
|
||||
agg_info = {
|
||||
"created_at": "2016-09-27T02:37:21.966342+00:00",
|
||||
"metadata": {"key1": "value1"},
|
||||
"links": [],
|
||||
"name": "agg-name-" + uuidutils.generate_uuid(dashed=False),
|
||||
"updated_at": None,
|
||||
"uuid": "agg-id-" + uuidutils.generate_uuid(dashed=False),
|
||||
}
|
||||
|
||||
# Overwrite default attributes.
|
||||
agg_info.update(attrs)
|
||||
|
||||
agg = FakeResource(
|
||||
manager=None,
|
||||
info=copy.deepcopy(agg_info),
|
||||
loaded=True)
|
||||
return agg
|
||||
|
||||
@staticmethod
|
||||
def create_aggregates(attrs=None, count=2):
|
||||
"""Create multiple fake baremetal node aggregates.
|
||||
|
||||
:param Dictionary attrs:
|
||||
A dictionary with all attributes
|
||||
:param int count:
|
||||
The number of aggregates to fake
|
||||
:return:
|
||||
A list of FakeResource objects faking the aggregates
|
||||
"""
|
||||
aggs = []
|
||||
for i in range(0, count):
|
||||
aggs.append(
|
||||
FakeAggregate.create_one_aggregate(attrs))
|
||||
|
||||
return aggs
|
||||
|
||||
@staticmethod
|
||||
def get_aggregates(aggregates=None, count=2):
|
||||
"""Get an iterable Mock object with a list of faked aggregates.
|
||||
|
||||
If aggregates list is provided, then initialize the Mock object
|
||||
with the list. Otherwise create one.
|
||||
|
||||
:param List aggregates:
|
||||
A list of FakeResource objects faking aggregates
|
||||
:param int count:
|
||||
The number of aggregates to fake
|
||||
:return:
|
||||
An iterable Mock object with side_effect set to a list of faked
|
||||
baremetal aggregates
|
||||
"""
|
||||
if aggregates is None:
|
||||
aggregates = FakeAggregate.create_aggregates(count)
|
||||
return mock.Mock(side_effect=aggregates)
|
||||
|
224
moganclient/tests/unit/osc/v1/test_aggregate.py
Normal file
224
moganclient/tests/unit/osc/v1/test_aggregate.py
Normal file
@ -0,0 +1,224 @@
|
||||
# Copyright 2017 Huawei, Inc. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
import mock
|
||||
|
||||
from osc_lib import utils
|
||||
|
||||
from moganclient.common import base
|
||||
from moganclient.osc.v1 import aggregate
|
||||
from moganclient.tests.unit import base as test_base
|
||||
from moganclient.tests.unit import fakes
|
||||
from moganclient.v1 import aggregate as aggregate_mgr
|
||||
|
||||
|
||||
class TestAggregateBase(test_base.TestBaremetalComputeV1):
|
||||
def setUp(self):
|
||||
super(TestAggregateBase, self).setUp()
|
||||
self.fake_agg = fakes.FakeAggregate.create_one_aggregate()
|
||||
|
||||
self.columns = (
|
||||
'created_at',
|
||||
'links',
|
||||
'name',
|
||||
'properties',
|
||||
'updated_at',
|
||||
'uuid',
|
||||
)
|
||||
|
||||
self.data = (
|
||||
self.fake_agg.created_at,
|
||||
self.fake_agg.links,
|
||||
self.fake_agg.name,
|
||||
utils.format_dict(self.fake_agg.metadata),
|
||||
self.fake_agg.updated_at,
|
||||
self.fake_agg.uuid,
|
||||
)
|
||||
|
||||
|
||||
@mock.patch.object(aggregate_mgr.AggregateManager, '_create')
|
||||
class TestAggregateCreate(TestAggregateBase):
|
||||
def setUp(self):
|
||||
super(TestAggregateCreate, self).setUp()
|
||||
self.cmd = aggregate.CreateAggregate(self.app, None)
|
||||
|
||||
def test_aggregate_create(self, mock_create):
|
||||
arglist = [
|
||||
'test_agg',
|
||||
'--property', 'k1=v1'
|
||||
]
|
||||
verifylist = [
|
||||
('name', 'test_agg'),
|
||||
('property', {'k1': 'v1'}),
|
||||
]
|
||||
mock_create.return_value = self.fake_agg
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
mock_create.assert_called_once_with('/aggregates',
|
||||
data={
|
||||
'name': 'test_agg',
|
||||
'metadata': {'k1': 'v1'},
|
||||
})
|
||||
self.assertEqual(self.columns, columns)
|
||||
self.assertEqual(self.data, data)
|
||||
|
||||
|
||||
@mock.patch.object(utils, 'find_resource')
|
||||
@mock.patch.object(aggregate_mgr.AggregateManager, '_delete')
|
||||
class TestAggregateDelete(TestAggregateBase):
|
||||
def setUp(self):
|
||||
super(TestAggregateDelete, self).setUp()
|
||||
self.cmd = aggregate.DeleteAggregate(self.app, None)
|
||||
|
||||
def test_aggregate_delete(self, mock_delete, mock_find):
|
||||
arglist = [
|
||||
'test_agg1',
|
||||
]
|
||||
verifylist = [
|
||||
('aggregate', ['test_agg1']),
|
||||
]
|
||||
mock_find.return_value = self.fake_agg
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
expected_url = '/aggregates/%s' % base.getid(self.fake_agg)
|
||||
mock_delete.assert_called_once_with(expected_url)
|
||||
self.assertIsNone(result)
|
||||
|
||||
def test_aggregate_multiple_delete(self, mock_delete, mock_find):
|
||||
arglist = [
|
||||
'agg1',
|
||||
'agg2',
|
||||
'agg3'
|
||||
]
|
||||
verifylist = [
|
||||
('aggregate', ['agg1', 'agg2', 'agg3']),
|
||||
]
|
||||
mock_find.return_value = self.fake_agg
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
expected_url = '/aggregates/%s' % base.getid(self.fake_agg)
|
||||
expected_call = [mock.call(expected_url), mock.call(expected_url),
|
||||
mock.call(expected_url)]
|
||||
mock_delete.assert_has_calls(expected_call)
|
||||
self.assertIsNone(result)
|
||||
|
||||
|
||||
@mock.patch.object(aggregate_mgr.AggregateManager, '_list')
|
||||
class TestAggregateList(TestAggregateBase):
|
||||
def setUp(self):
|
||||
super(TestAggregateList, self).setUp()
|
||||
self.list_columns = (
|
||||
"UUID",
|
||||
"Name",
|
||||
"Properties"
|
||||
)
|
||||
|
||||
self.list_data = (
|
||||
(self.fake_agg.uuid,
|
||||
self.fake_agg.name,
|
||||
utils.format_dict(self.fake_agg.metadata),
|
||||
),)
|
||||
|
||||
self.cmd = aggregate.ListAggregate(self.app, None)
|
||||
|
||||
def test_aggregate_list(self, mock_list):
|
||||
arglist = []
|
||||
verifylist = []
|
||||
mock_list.return_value = [self.fake_agg]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
mock_list.assert_called_once_with('/aggregates',
|
||||
response_key='aggregates')
|
||||
self.assertEqual(self.list_columns, columns)
|
||||
self.assertEqual(self.list_data, tuple(data))
|
||||
|
||||
|
||||
@mock.patch.object(aggregate_mgr.AggregateManager, '_get')
|
||||
class TestAggregateShow(TestAggregateBase):
|
||||
def setUp(self):
|
||||
super(TestAggregateShow, self).setUp()
|
||||
self.cmd = aggregate.ShowAggregate(self.app, None)
|
||||
|
||||
def test_agregate_show(self, mock_get):
|
||||
arglist = [
|
||||
'agg1',
|
||||
]
|
||||
verifylist = [
|
||||
('aggregate', 'agg1'),
|
||||
]
|
||||
mock_get.return_value = self.fake_agg
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
expected_url = '/aggregates/%s' % parsed_args.aggregate
|
||||
mock_get.assert_called_once_with(expected_url)
|
||||
self.assertEqual(self.columns, columns)
|
||||
self.assertEqual(self.data, data)
|
||||
|
||||
|
||||
@mock.patch.object(utils, 'find_resource')
|
||||
@mock.patch.object(aggregate_mgr.AggregateManager, '_update')
|
||||
class TestAggregateSet(TestAggregateBase):
|
||||
def setUp(self):
|
||||
super(TestAggregateSet, self).setUp()
|
||||
self.cmd = aggregate.SetAggregate(self.app, None)
|
||||
|
||||
def test_aggregate_update(self, mock_update, mock_find):
|
||||
mock_find.return_value = self.fake_agg
|
||||
arglist = [
|
||||
'--name', 'test_agg',
|
||||
'--property', 'k1=v1',
|
||||
self.fake_agg.uuid,
|
||||
]
|
||||
verifylist = [
|
||||
('aggregate', self.fake_agg.uuid),
|
||||
('name', 'test_agg'),
|
||||
('property', {'k1': 'v1'}),
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.cmd.take_action(parsed_args)
|
||||
expected_url = '/aggregates/%s' % base.getid(self.fake_agg)
|
||||
expected_args = [
|
||||
{'path': '/name', 'value': 'test_agg', 'op': 'replace'},
|
||||
{'path': '/metadata/k1', 'value': 'v1', 'op': 'add'},
|
||||
]
|
||||
mock_update.assert_called_once_with(expected_url,
|
||||
data=expected_args)
|
||||
|
||||
|
||||
@mock.patch.object(utils, 'find_resource')
|
||||
@mock.patch.object(aggregate_mgr.AggregateManager, '_update')
|
||||
class TestAggregateUnset(TestAggregateBase):
|
||||
def setUp(self):
|
||||
super(TestAggregateUnset, self).setUp()
|
||||
self.cmd = aggregate.UnsetAggregate(self.app, None)
|
||||
|
||||
def test_aggregate_update(self, mock_update, mock_find):
|
||||
mock_find.return_value = self.fake_agg
|
||||
arglist = [
|
||||
'--property', 'key1',
|
||||
self.fake_agg.uuid,
|
||||
]
|
||||
verifylist = [
|
||||
('aggregate', self.fake_agg.uuid),
|
||||
('property', ['key1']),
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.cmd.take_action(parsed_args)
|
||||
expected_url = '/aggregates/%s' % base.getid(self.fake_agg)
|
||||
expected_args = [
|
||||
{'path': '/metadata/key1', 'op': 'remove'}
|
||||
]
|
||||
mock_update.assert_called_once_with(expected_url,
|
||||
data=expected_args)
|
47
moganclient/v1/aggregate.py
Normal file
47
moganclient/v1/aggregate.py
Normal file
@ -0,0 +1,47 @@
|
||||
# Copyright 2017 Huawei, Inc. 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.
|
||||
#
|
||||
|
||||
from moganclient.common import base
|
||||
|
||||
|
||||
class Aggregate(base.Resource):
|
||||
pass
|
||||
|
||||
|
||||
class AggregateManager(base.ManagerWithFind):
|
||||
resource_class = Aggregate
|
||||
|
||||
def create(self, name, metadata=None):
|
||||
url = '/aggregates'
|
||||
data = {'name': name}
|
||||
if metadata:
|
||||
data['metadata'] = metadata
|
||||
return self._create(url, data=data)
|
||||
|
||||
def delete(self, aggregate):
|
||||
url = '/aggregates/%s' % base.getid(aggregate)
|
||||
return self._delete(url)
|
||||
|
||||
def get(self, aggregate):
|
||||
url = '/aggregates/%s' % base.getid(aggregate)
|
||||
return self._get(url)
|
||||
|
||||
def list(self):
|
||||
url = '/aggregates'
|
||||
return self._list(url, response_key='aggregates')
|
||||
|
||||
def update(self, aggregate, updates):
|
||||
url = '/aggregates/%s' % base.getid(aggregate)
|
||||
return self._update(url, data=updates)
|
@ -14,6 +14,7 @@
|
||||
#
|
||||
|
||||
from moganclient.common import http
|
||||
from moganclient.v1 import aggregate
|
||||
from moganclient.v1 import availability_zone
|
||||
from moganclient.v1 import flavor
|
||||
from moganclient.v1 import keypair
|
||||
@ -35,3 +36,4 @@ class Client(object):
|
||||
self.http_client)
|
||||
self.keypair = keypair.KeyPairManager(self.http_client)
|
||||
self.node = node.NodeManager(self.http_client)
|
||||
self.aggregate = aggregate.AggregateManager(self.http_client)
|
||||
|
@ -59,7 +59,12 @@ openstack.baremetal_compute.v1 =
|
||||
# TODO(liusheng): may change the "baremetal" to another word to avoid
|
||||
# conflict with Ironic
|
||||
baremetal_compute_node_list = moganclient.osc.v1.node:ListNode
|
||||
|
||||
baremetal_aggregate_create = moganclient.osc.v1.aggregate:CreateAggregate
|
||||
baremetal_aggregate_show = moganclient.osc.v1.aggregate:ShowAggregate
|
||||
baremetal_aggregate_list = moganclient.osc.v1.aggregate:ListAggregate
|
||||
baremetal_aggregate_delete = moganclient.osc.v1.aggregate:DeleteAggregate
|
||||
baremetal_aggregate_set = moganclient.osc.v1.aggregate:SetAggregate
|
||||
baremetal_aggregate_unset = moganclient.osc.v1.aggregate:UnsetAggregate
|
||||
|
||||
[build_sphinx]
|
||||
source-dir = doc/source
|
||||
|
Loading…
x
Reference in New Issue
Block a user