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:
Alexander Saprykin 2015-07-30 13:56:38 +03:00 committed by Artem Roma
parent 142dae5693
commit fe14afa5bb
12 changed files with 464 additions and 7 deletions

View File

@ -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,
}

View File

@ -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(
{},

View File

@ -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."""

View File

@ -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

View File

@ -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)
)

View File

@ -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,

View File

@ -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,
}

View File

@ -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)

View File

@ -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)

View File

@ -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')

View File

@ -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()

View File

@ -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 =