Add network groups support for v2
Examples: To create a new network group: fuel2 network-group create --node-group 1 --release 2 --vlan 100 --cidr 10.0.0.0/24 --meta '{"notation": "cidr"}' New_Network To update network group: fuel2 network-group update --name New_Name --vlan 200 --meta '{"notation": "cidr"}' 1 To delete specified network group: fuel2 network-group delete 1 To list all available network groups: fuel2 network-group list To show specified network group: fuel2 network-group show 1 Partial-Bug: #1478577 Change-Id: I9eaa01af25b68c6d41b02c7d9d99ae42ce998515
This commit is contained in:
parent
142dae5693
commit
fe14afa5bb
|
@ -50,6 +50,7 @@ def get_client(resource, version='v1'):
|
|||
'v1': {
|
||||
'environment': v1.environment,
|
||||
'fuel-version': v1.fuelversion,
|
||||
'network-group': v1.network_group,
|
||||
'node': v1.node,
|
||||
'task': v1.task,
|
||||
}
|
||||
|
|
|
@ -89,8 +89,8 @@ class NetworkGroupAction(Action):
|
|||
fuel network-group --delete --network 2,3,4
|
||||
"""
|
||||
ngs = NetworkGroup.get_by_ids(params.network)
|
||||
for n in ngs:
|
||||
NetworkGroup.delete(n.id)
|
||||
for network_group in ngs:
|
||||
network_group.delete()
|
||||
|
||||
self.serializer.print_to_output(
|
||||
{},
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
# Copyright 2015 Mirantis, 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.
|
||||
|
||||
from cliff import show
|
||||
|
||||
from fuelclient.cli.serializers import Serializer
|
||||
from fuelclient.commands import base
|
||||
from fuelclient.common import data_utils
|
||||
|
||||
|
||||
class NetworkGroupMixin(object):
|
||||
entity_name = 'network-group'
|
||||
|
||||
@staticmethod
|
||||
def add_parser_arguments(parser, for_update=False):
|
||||
parser.add_argument(
|
||||
'-N', '--node-group',
|
||||
type=int,
|
||||
required=not for_update,
|
||||
help='ID of the network group'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'-C', '--cidr',
|
||||
type=str,
|
||||
required=not for_update,
|
||||
help='CIDR of the network'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'-V', '--vlan',
|
||||
type=int,
|
||||
help='VLAN of the network',
|
||||
)
|
||||
|
||||
if not for_update:
|
||||
parser.add_argument(
|
||||
'-r', '--release',
|
||||
type=int,
|
||||
help='Release ID this network group belongs to'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'-g', '--gateway',
|
||||
type=str,
|
||||
help='Gateway of the network'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'-m', '--meta',
|
||||
type=str,
|
||||
help='Metadata in JSON format to override default network metadata'
|
||||
)
|
||||
|
||||
|
||||
class NetworkGroupList(NetworkGroupMixin, base.BaseListCommand):
|
||||
"""List all network groups."""
|
||||
|
||||
columns = (
|
||||
'id',
|
||||
'name',
|
||||
'vlan_start',
|
||||
'cidr',
|
||||
'gateway',
|
||||
'group_id'
|
||||
)
|
||||
|
||||
|
||||
# TODO(asaprykin): Include metadata field to the output
|
||||
class NetworkGroupShow(NetworkGroupMixin, base.BaseShowCommand):
|
||||
"""Show network group."""
|
||||
|
||||
columns = NetworkGroupList.columns
|
||||
|
||||
|
||||
class NetworkGroupCreate(NetworkGroupMixin, base.BaseShowCommand):
|
||||
"""Create a new network group."""
|
||||
|
||||
columns = NetworkGroupList.columns
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = show.ShowOne.get_parser(self, prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'name',
|
||||
type=str,
|
||||
help='Name of the new network group'
|
||||
)
|
||||
|
||||
self.add_parser_arguments(parser)
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
meta = None
|
||||
if parsed_args.meta:
|
||||
serializer = Serializer.from_params(parsed_args)
|
||||
meta = serializer.deserialize(parsed_args.meta)
|
||||
|
||||
net_group = self.client.create(
|
||||
name=parsed_args.name,
|
||||
release=parsed_args.release,
|
||||
vlan=parsed_args.vlan,
|
||||
cidr=parsed_args.cidr,
|
||||
gateway=parsed_args.gateway,
|
||||
group_id=parsed_args.node_group,
|
||||
meta=meta)
|
||||
|
||||
net_group = data_utils.get_display_data_single(self.columns, net_group)
|
||||
return self.columns, net_group
|
||||
|
||||
|
||||
class NetworkGroupUpdate(NetworkGroupMixin, base.BaseShowCommand):
|
||||
"""Set parameters for the specified network group."""
|
||||
|
||||
columns = NetworkGroupList.columns
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = show.ShowOne.get_parser(self, prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'id',
|
||||
type=int,
|
||||
help='ID of the network group to update')
|
||||
parser.add_argument(
|
||||
'-n',
|
||||
'--name',
|
||||
type=str,
|
||||
help='New name for network group')
|
||||
|
||||
self.add_parser_arguments(parser, for_update=True)
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
to_update = {}
|
||||
for attr in self.client.updatable_attributes:
|
||||
value = getattr(parsed_args, attr, None)
|
||||
if value is not None:
|
||||
to_update[attr] = value
|
||||
|
||||
if 'meta' in to_update:
|
||||
serializer = Serializer.from_params(parsed_args)
|
||||
to_update['meta'] = serializer.deserialize(to_update['meta'])
|
||||
|
||||
network_group = self.client.update(parsed_args.id, **to_update)
|
||||
network_group = data_utils.get_display_data_single(
|
||||
self.columns, network_group)
|
||||
|
||||
return self.columns, network_group
|
||||
|
||||
|
||||
class NetworkGroupDelete(NetworkGroupMixin, base.BaseDeleteCommand):
|
||||
"""Delete specified network group."""
|
|
@ -25,3 +25,4 @@ from fuelclient.objects.task import DeployTask
|
|||
from fuelclient.objects.task import SnapshotTask
|
||||
from fuelclient.objects.task import Task
|
||||
from fuelclient.objects.fuelversion import FuelVersion
|
||||
from fuelclient.objects.network_group import NetworkGroup
|
||||
|
|
|
@ -53,15 +53,23 @@ class NetworkGroup(BaseObject):
|
|||
'group_id': group_id,
|
||||
}
|
||||
|
||||
return cls.connection.post_request(
|
||||
data = cls.connection.post_request(
|
||||
cls.class_api_path,
|
||||
network_group,
|
||||
)
|
||||
return cls.init_with_data(data)
|
||||
|
||||
@classmethod
|
||||
def delete(cls, network_id):
|
||||
return cls.connection.delete_request(
|
||||
cls.instance_api_path.format(network_id)
|
||||
def set(self, data):
|
||||
vlan = data.pop('vlan', None)
|
||||
if vlan is not None:
|
||||
data['vlan_start'] = vlan
|
||||
|
||||
return self.connection.put_request(
|
||||
self.instance_api_path.format(self.id), data)
|
||||
|
||||
def delete(self):
|
||||
return self.connection.delete_request(
|
||||
self.instance_api_path.format(self.id)
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
from fuelclient.tests.utils.random_data import random_string
|
||||
from fuelclient.tests.utils.fake_net_conf import get_fake_interface_config
|
||||
from fuelclient.tests.utils.fake_net_conf import get_fake_network_config
|
||||
from fuelclient.tests.utils.fake_network_group import get_fake_network_group
|
||||
from fuelclient.tests.utils.fake_node import get_fake_node
|
||||
from fuelclient.tests.utils.fake_env import get_fake_env
|
||||
from fuelclient.tests.utils.fake_fuel_version import get_fake_fuel_version
|
||||
|
@ -26,6 +27,7 @@ from fuelclient.tests.utils.fake_task import get_fake_task
|
|||
__all__ = (get_fake_env,
|
||||
get_fake_fuel_version,
|
||||
get_fake_interface_config,
|
||||
get_fake_network_group,
|
||||
get_fake_node,
|
||||
get_fake_network_config,
|
||||
get_fake_task,
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2015 Mirantis, 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.
|
||||
|
||||
|
||||
def get_fake_network_group(
|
||||
name=None, release=None, vlan=None, cidr=None, gateway=None,
|
||||
group_id=None, meta=None, net_id=None):
|
||||
"""Create a random fake network group
|
||||
|
||||
Returns the serialized and parametrized representation of a dumped Fuel
|
||||
environment. Represents the average amount of data.
|
||||
|
||||
"""
|
||||
return {
|
||||
'name': name or 'testng',
|
||||
'release': release or 24,
|
||||
'vlan_start': vlan or 10,
|
||||
'cidr': cidr or '10.0.0.0/24',
|
||||
'gateway': gateway or '10.0.0.1',
|
||||
'group_id': group_id or 42,
|
||||
'meta': meta or {'notation': 'cidr'},
|
||||
'id': net_id or 42,
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2015 Mirantis, 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 json
|
||||
import mock
|
||||
|
||||
from fuelclient.tests.utils import fake_network_group
|
||||
from fuelclient.tests.v2.unit.cli import test_engine
|
||||
from fuelclient.v1.network_group import NetworkGroupClient
|
||||
|
||||
|
||||
class TestNetworkGroupCommand(test_engine.BaseCLITest):
|
||||
|
||||
def setUp(self):
|
||||
super(TestNetworkGroupCommand, self).setUp()
|
||||
|
||||
get_fake_ng = fake_network_group.get_fake_network_group
|
||||
|
||||
self.m_client.get_all.return_value = [
|
||||
get_fake_ng() for _ in range(10)]
|
||||
self.m_client.get_by_id.return_value = get_fake_ng()
|
||||
self.m_client.create.return_value = get_fake_ng()
|
||||
|
||||
def test_network_group_list(self):
|
||||
args = 'network-group list'
|
||||
self.exec_command(args)
|
||||
|
||||
self.m_get_client.assert_called_once_with('network-group', mock.ANY)
|
||||
self.m_client.get_all.assert_called_once_with()
|
||||
|
||||
def test_network_group_show(self):
|
||||
args = 'network-group show 1'
|
||||
self.exec_command(args)
|
||||
|
||||
self.m_get_client.assert_called_once_with('network-group', mock.ANY)
|
||||
self.m_client.get_by_id.assert_called_once_with(1)
|
||||
|
||||
def test_network_group_create(self):
|
||||
meta = {'notation': 'cidr'}
|
||||
meta_str = json.dumps(meta).replace(r'"', r'\"')
|
||||
|
||||
args = 'network-group create -N 8 -C 10.10.0.0/24 -g 10.10.0.1' \
|
||||
' -V 16 -r 32 testng --meta "{0}"'.format(meta_str)
|
||||
self.exec_command(args)
|
||||
|
||||
self.m_get_client.assert_called_once_with('network-group', mock.ANY)
|
||||
|
||||
m_client = self.m_client
|
||||
m_client.create.assert_called_once_with(
|
||||
name='testng', group_id=8, cidr='10.10.0.0/24', vlan=16,
|
||||
release=32, gateway='10.10.0.1', meta=meta)
|
||||
|
||||
def test_network_group_update(self):
|
||||
self.m_client.updatable_attributes = \
|
||||
NetworkGroupClient.updatable_attributes
|
||||
|
||||
meta = {'notation': 'cidr'}
|
||||
meta_str = json.dumps(meta).replace(r'"', r'\"')
|
||||
|
||||
args = 'network-group update -C 10.10.0.0/24' \
|
||||
' --meta "{0}" 1'.format(meta_str)
|
||||
self.exec_command(args)
|
||||
|
||||
self.m_get_client.assert_called_once_with('network-group', mock.ANY)
|
||||
|
||||
m_client = self.m_client
|
||||
m_client.update.assert_called_once_with(
|
||||
1, cidr='10.10.0.0/24', meta=meta)
|
||||
|
||||
def test_network_group_delete(self):
|
||||
args = 'network-group delete 42'
|
||||
self.exec_command(args)
|
||||
|
||||
self.m_get_client.assert_called_once_with('network-group', mock.ANY)
|
||||
self.m_client.delete_by_id.assert_called_once_with(42)
|
|
@ -0,0 +1,99 @@
|
|||
# Copyright 2015 Mirantis, 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 fuelclient
|
||||
from fuelclient.tests import utils
|
||||
from fuelclient.tests.v2.unit.lib import test_api
|
||||
|
||||
|
||||
class TestNetworkGroupFacade(test_api.BaseLibTest):
|
||||
|
||||
def setUp(self):
|
||||
super(TestNetworkGroupFacade, self).setUp()
|
||||
|
||||
self.version = 'v1'
|
||||
self.res_uri = '/api/{version}/networks/'.format(version=self.version)
|
||||
|
||||
self.fake_network_group = utils.get_fake_network_group()
|
||||
self.fake_network_groups = [utils.get_fake_network_group()
|
||||
for i in range(10)]
|
||||
|
||||
self.client = fuelclient.get_client('network-group')
|
||||
|
||||
def test_network_group_list(self):
|
||||
matcher = self.m_request.get(
|
||||
self.res_uri, json=self.fake_network_groups)
|
||||
|
||||
self.client.get_all()
|
||||
self.assertTrue(matcher.called)
|
||||
|
||||
def test_network_group_show(self):
|
||||
net_id = 42
|
||||
uri = self.get_object_uri(self.res_uri, net_id)
|
||||
|
||||
matcher = self.m_request.get(
|
||||
uri, json=self.fake_network_group)
|
||||
|
||||
self.client.get_by_id(net_id)
|
||||
|
||||
self.assertTrue(matcher.called)
|
||||
|
||||
def test_network_group_create(self):
|
||||
fake_ng = self.fake_network_group
|
||||
matcher = self.m_request.post(self.res_uri, json=fake_ng)
|
||||
|
||||
self.client.create(
|
||||
name=fake_ng['name'],
|
||||
release=fake_ng['release'],
|
||||
vlan=fake_ng['vlan_start'],
|
||||
cidr=fake_ng['cidr'],
|
||||
gateway=fake_ng['gateway'],
|
||||
group_id=fake_ng['group_id'],
|
||||
meta=fake_ng['meta'],
|
||||
)
|
||||
|
||||
req_data = matcher.last_request.json()
|
||||
|
||||
self.assertTrue(matcher.called)
|
||||
|
||||
self.assertEqual(req_data['name'], fake_ng['name'])
|
||||
self.assertEqual(req_data['release'], fake_ng['release'])
|
||||
self.assertEqual(req_data['vlan_start'], fake_ng['vlan_start'])
|
||||
self.assertEqual(req_data['meta']['notation'],
|
||||
fake_ng['meta']['notation'])
|
||||
|
||||
def test_network_group_update(self):
|
||||
net_id = 42
|
||||
uri = self.get_object_uri(self.res_uri, net_id)
|
||||
|
||||
get_matcher = self.m_request.get(uri, json=self.fake_network_group)
|
||||
put_matcher = self.m_request.put(uri, json=self.fake_network_group)
|
||||
|
||||
self.client.update(net_id, name='new_name')
|
||||
|
||||
self.assertTrue(get_matcher.called)
|
||||
self.assertTrue(put_matcher.called)
|
||||
|
||||
req_data = put_matcher.last_request.json()
|
||||
self.assertEqual('new_name', req_data['name'])
|
||||
|
||||
def test_network_group_delete(self):
|
||||
env_id = 42
|
||||
uri = self.get_object_uri(self.res_uri, env_id)
|
||||
|
||||
matcher = self.m_request.delete(uri, json={})
|
||||
|
||||
self.client.delete_by_id(env_id)
|
||||
|
||||
self.assertTrue(matcher.called)
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
from fuelclient.v1 import environment
|
||||
from fuelclient.v1 import fuelversion
|
||||
from fuelclient.v1 import network_group
|
||||
from fuelclient.v1 import node
|
||||
from fuelclient.v1 import task
|
||||
|
||||
|
@ -21,5 +22,6 @@ from fuelclient.v1 import task
|
|||
# Please keeps the list in alphabetical order
|
||||
__all__ = ('environment',
|
||||
'fuelversion',
|
||||
'network_group',
|
||||
'node',
|
||||
'task')
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
# Copyright 2015 Mirantis, 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.
|
||||
|
||||
from fuelclient.cli import error
|
||||
from fuelclient import objects
|
||||
from fuelclient.v1 import base_v1
|
||||
|
||||
|
||||
class NetworkGroupClient(base_v1.BaseV1Client):
|
||||
|
||||
_entity_wrapper = objects.NetworkGroup
|
||||
|
||||
updatable_attributes = (
|
||||
'name', 'vlan', 'cidr', 'gateway', 'group_id', 'meta')
|
||||
|
||||
def create(self, name, release, vlan, cidr,
|
||||
gateway, group_id, meta=None):
|
||||
net_group = self._entity_wrapper.create(
|
||||
name, release, vlan, cidr, gateway, group_id, meta)
|
||||
return net_group.data
|
||||
|
||||
def update(self, network_id, **kwargs):
|
||||
for attr in kwargs:
|
||||
if attr not in self.updatable_attributes:
|
||||
raise error.ArgumentException(
|
||||
'Update of attribute "{0}" is not allowed'.format(attr))
|
||||
|
||||
net_group = self._entity_wrapper(network_id)
|
||||
net_group.set(kwargs)
|
||||
|
||||
return net_group.data
|
||||
|
||||
def delete_by_id(self, network_id):
|
||||
env_obj = self._entity_wrapper(network_id)
|
||||
env_obj.delete()
|
||||
|
||||
|
||||
def get_client():
|
||||
return NetworkGroupClient()
|
|
@ -51,6 +51,11 @@ fuelclient =
|
|||
network-template_upload=fuelclient.commands.network_template:NetworkTemplateUpload
|
||||
network-template_download=fuelclient.commands.network_template:NetworkTemplateDownload
|
||||
network-template_delete=fuelclient.commands.network_template:NetworkTemplateDelete
|
||||
network-group_list=fuelclient.commands.network_group:NetworkGroupList
|
||||
network-group_show=fuelclient.commands.network_group:NetworkGroupShow
|
||||
network-group_create=fuelclient.commands.network_group:NetworkGroupCreate
|
||||
network-group_update=fuelclient.commands.network_group:NetworkGroupUpdate
|
||||
network-group_delete=fuelclient.commands.network_group:NetworkGroupDelete
|
||||
|
||||
[global]
|
||||
setup-hooks =
|
||||
|
|
Loading…
Reference in New Issue