[OSC] Implement share network subnet commands

This patch adds the following openstack share commands:

share network subnet create
share network subnet delete
share network subnet show

Partially-implements: bp openstack-client-support
Change-Id: I4e066a982fa40b079f969e7c3ca3276d3a842074
This commit is contained in:
Maari Tamm 2021-10-30 21:05:32 +00:00
parent 0f9ba9a7d3
commit b095429783
5 changed files with 451 additions and 1 deletions

View File

@ -66,7 +66,20 @@ share networks
==============
.. autoprogram-cliff:: openstack.share.v2
:command: share network *
:command: share network [!s]*
.. autoprogram-cliff:: openstack.share.v2
:command: share network show
.. autoprogram-cliff:: openstack.share.v2
:command: share network set
=====================
share network subnets
=====================
.. autoprogram-cliff:: openstack.share.v2
:command: share network subnet *
===========
share types

View File

@ -0,0 +1,162 @@
# 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 operator import xor
from osc_lib.command import command
from osc_lib import exceptions
from osc_lib import utils as oscutils
from manilaclient.common._i18n import _
LOG = logging.getLogger(__name__)
class CreateShareNetworkSubnet(command.ShowOne):
"""Create a share network subnet."""
_description = _("Create a share network subnet")
def get_parser(self, prog_name):
parser = super(CreateShareNetworkSubnet, self).get_parser(prog_name)
parser.add_argument(
"share_network",
metavar="<share-network>",
help=_("Share network name or ID.")
)
parser.add_argument(
"--neutron-net-id",
metavar="<neutron-net-id>",
default=None,
help=_("Neutron network ID. Used to set up network for share "
"servers (optional). Should be defined together with "
"'--neutron-subnet-id'.")
)
parser.add_argument(
"--neutron-subnet-id",
metavar="<neutron-subnet-id>",
default=None,
help=_("Neutron subnet ID. Used to set up network for share "
"servers (optional). Should be defined together with "
"'--neutron-net-id' to which this subnet belongs to. ")
)
parser.add_argument(
"--availability-zone",
metavar="<availability-zone>",
default=None,
help=_("Optional availability zone that the subnet is available "
"within (Default=None). If None, the subnet will be "
"considered as being available across all availability "
"zones.")
)
return parser
def take_action(self, parsed_args):
share_client = self.app.client_manager.share
if xor(bool(parsed_args.neutron_net_id),
bool(parsed_args.neutron_subnet_id)):
raise exceptions.CommandError(
"Both neutron_net_id and neutron_subnet_id should be "
"specified. Alternatively, neither of them should be "
"specified.")
share_network_id = oscutils.find_resource(
share_client.share_networks,
parsed_args.share_network).id
share_network_subnet = share_client.share_network_subnets.create(
neutron_net_id=parsed_args.neutron_net_id,
neutron_subnet_id=parsed_args.neutron_subnet_id,
availability_zone=parsed_args.availability_zone,
share_network_id=share_network_id
)
subnet_data = share_network_subnet._info
return self.dict2columns(subnet_data)
class DeleteShareNetworkSubnet(command.Command):
"""Create a share network subnet."""
_description = _("Create a share network subnet")
def get_parser(self, prog_name):
parser = super(DeleteShareNetworkSubnet, self).get_parser(prog_name)
parser.add_argument(
"share_network",
metavar="<share-network>",
help=_("Share network name or ID.")
)
parser.add_argument(
"share_network_subnet",
metavar="<share-network-subnet>",
nargs="+",
help=_("ID(s) of share network subnet(s) to be deleted.")
)
return parser
def take_action(self, parsed_args):
share_client = self.app.client_manager.share
result = 0
share_network_id = oscutils.find_resource(
share_client.share_networks,
parsed_args.share_network).id
for subnet in parsed_args.share_network_subnet:
try:
share_client.share_network_subnets.delete(
share_network_id,
subnet)
except Exception as e:
result += 1
LOG.error(f"Failed to delete share network subnet with "
f"ID {subnet}: {e}")
if result > 0:
total = len(parsed_args.share_network_subnet)
raise exceptions.CommandError(
f"{result} of {total} share network subnets failed to be "
f"deleted.")
class ShowShareNetworkSubnet(command.ShowOne):
"""Show share network subnet."""
_description = _("Show share network subnet")
def get_parser(self, prog_name):
parser = super(ShowShareNetworkSubnet, self).get_parser(prog_name)
parser.add_argument(
"share_network",
metavar="<share-network>",
help=_("Share network name or ID.")
)
parser.add_argument(
"share_network_subnet",
metavar="<share-network-subnet>",
help=_("ID of share network subnet to show.")
)
return parser
def take_action(self, parsed_args):
share_client = self.app.client_manager.share
share_network_id = oscutils.find_resource(
share_client.share_networks,
parsed_args.share_network).id
share_network_subnet = share_client.share_network_subnets.get(
share_network_id,
parsed_args.share_network_subnet)
return self.dict2columns(share_network_subnet._info)

View File

@ -41,6 +41,7 @@ class FakeShareClient(object):
self.share_replicas = mock.Mock()
self.share_replica_export_locations = mock.Mock()
self.share_networks = mock.Mock()
self.share_network_subnets = mock.Mock()
self.security_services = mock.Mock()
self.shares.resource_class = osc_fakes.FakeResource(None, {})
self.share_instance_export_locations = mock.Mock()
@ -1095,6 +1096,64 @@ class FakeShareNetwork(object):
return share_networks
class FakeShareNetworkSubnet(object):
"""Fake a share network subnet"""
@staticmethod
def create_one_share_subnet(attrs=None):
"""Create a fake share network subnet
:param Dictionary attrs:
A dictionary with all attributes
:return:
A FakeResource object, with project_id, resource and so on
"""
attrs = attrs or {}
share_network_subnet = {
"availability_zone": None,
"cidr": "10.0.0.0/24",
"created_at": datetime.datetime.now().isoformat(),
"gateway": "10.0.0.1",
'id': str(uuid.uuid4()),
"ip_version": 4,
"mtu": "1500",
"network_type": "vlan",
"neutron_net_id": str(uuid.uuid4()),
"neutron_subnet_id": str(uuid.uuid4()),
"segmentation_id": 1010,
"share_network_id": str(uuid.uuid4()),
"share_network_name": str(uuid.uuid4()),
"updated_at": datetime.datetime.now().isoformat(),
}
share_network_subnet.update(attrs)
share_network_subnet = osc_fakes.FakeResource(info=copy.deepcopy(
share_network_subnet),
loaded=True)
return share_network_subnet
@staticmethod
def create_share_network_subnets(attrs=None, count=2):
"""Create multiple fake share network subnets.
:param Dictionary attrs:
A dictionary with all attributes
:param Integer count:
The number of share network subnets to be faked
:return:
A list of FakeResource objects
"""
share_network_subnets = []
for n in range(count):
share_network_subnets.append(
FakeShareNetworkSubnet.create_one_share_subnet(attrs))
return share_network_subnets
class FakeShareGroup(object):
"""Fake a share group"""

View File

@ -0,0 +1,213 @@
# 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 uuid
from osc_lib import exceptions
from manilaclient.osc.v2 import share_network_subnets as osc_share_subnets
from manilaclient.tests.unit.osc import osc_utils
from manilaclient.tests.unit.osc.v2 import fakes as manila_fakes
class TestShareNetworkSubnet(manila_fakes.TestShare):
def setUp(self):
super(TestShareNetworkSubnet, self).setUp()
self.share_networks_mock = self.app.client_manager.share.share_networks
self.share_networks_mock.reset_mock()
self.share_subnets_mock = (
self.app.client_manager.share.share_network_subnets)
self.share_subnets_mock.reset_mock()
class TestShareNetworkSubnetCreate(TestShareNetworkSubnet):
def setUp(self):
super(TestShareNetworkSubnetCreate, self).setUp()
self.share_network = (
manila_fakes.FakeShareNetwork.create_one_share_network())
self.share_networks_mock.get.return_value = self.share_network
self.share_network_subnet = (
manila_fakes.FakeShareNetworkSubnet.create_one_share_subnet())
self.share_subnets_mock.create.return_value = self.share_network_subnet
self.cmd = osc_share_subnets.CreateShareNetworkSubnet(
self.app, None)
self.data = self.share_network_subnet._info.values()
self.columns = self.share_network_subnet._info.keys()
def test_share_network_subnet_create_missing_args(self):
arglist = []
verifylist = []
self.assertRaises(osc_utils.ParserException,
self.check_parser, self.cmd, arglist, verifylist)
def test_share_network_subnet_create(self):
fake_neutron_net_id = str(uuid.uuid4())
fake_neutron_subnet_id = str(uuid.uuid4())
arglist = [
self.share_network.id,
'--neutron-net-id', fake_neutron_net_id,
'--neutron-subnet-id', fake_neutron_subnet_id,
'--availability-zone', 'nova',
]
verifylist = [
('share_network', self.share_network.id),
('neutron_net_id', fake_neutron_net_id),
('neutron_subnet_id', fake_neutron_subnet_id),
('availability_zone', 'nova'),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.share_subnets_mock.create.assert_called_once_with(
neutron_net_id=fake_neutron_net_id,
neutron_subnet_id=fake_neutron_subnet_id,
availability_zone='nova',
share_network_id=self.share_network.id
)
self.assertCountEqual(self.columns, columns)
self.assertCountEqual(self.data, data)
def test_share_network_subnet_create_arg_group_exception(self):
fake_neutron_net_id = str(uuid.uuid4())
arglist = [
self.share_network.id,
'--neutron-net-id', fake_neutron_net_id
]
verifylist = [
('share_network', self.share_network.id),
('neutron_net_id', fake_neutron_net_id)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.assertRaises(exceptions.CommandError,
self.cmd.take_action,
parsed_args)
class TestShareNetworkSubnetDelete(TestShareNetworkSubnet):
def setUp(self):
super(TestShareNetworkSubnetDelete, self).setUp()
self.share_network = (
manila_fakes.FakeShareNetwork.create_one_share_network())
self.share_networks_mock.get.return_value = self.share_network
self.share_network_subnets = (
manila_fakes.FakeShareNetworkSubnet.create_share_network_subnets())
self.cmd = osc_share_subnets.DeleteShareNetworkSubnet(
self.app, None)
def test_share_network_subnet_delete_missing_args(self):
arglist = []
verifylist = []
self.assertRaises(osc_utils.ParserException,
self.check_parser, self.cmd, arglist, verifylist)
def test_share_network_subnets_delete(self):
arglist = [
self.share_network.id,
self.share_network_subnets[0].id,
self.share_network_subnets[1].id,
]
verifylist = [
('share_network', self.share_network.id),
('share_network_subnet', [self.share_network_subnets[0].id,
self.share_network_subnets[1].id]),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.assertEqual(self.share_subnets_mock.delete.call_count,
len(self.share_network_subnets))
self.assertIsNone(result)
def test_share_network_subnet_delete_exception(self):
arglist = [
self.share_network.id,
self.share_network_subnets[0].id,
]
verifylist = [
('share_network', self.share_network.id),
('share_network_subnet', [self.share_network_subnets[0].id]),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
self.share_subnets_mock.delete.side_effect = exceptions.CommandError()
self.assertRaises(exceptions.CommandError,
self.cmd.take_action,
parsed_args)
class TestShareNetworkSubnetShow(TestShareNetworkSubnet):
def setUp(self):
super(TestShareNetworkSubnetShow, self).setUp()
self.share_network = (
manila_fakes.FakeShareNetwork.create_one_share_network())
self.share_networks_mock.get.return_value = self.share_network
self.share_network_subnet = (
manila_fakes.FakeShareNetworkSubnet.create_one_share_subnet())
self.share_subnets_mock.get.return_value = self.share_network_subnet
self.cmd = osc_share_subnets.ShowShareNetworkSubnet(
self.app, None)
self.data = self.share_network_subnet._info.values()
self.columns = self.share_network_subnet._info.keys()
def test_share_network_subnet_show_missing_args(self):
arglist = []
verifylist = []
self.assertRaises(osc_utils.ParserException,
self.check_parser, self.cmd, arglist, verifylist)
def test_share_network_subnet_show(self):
arglist = [
self.share_network.id,
self.share_network_subnet.id,
]
verifylist = [
('share_network', self.share_network.id),
('share_network_subnet', self.share_network_subnet.id),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.share_subnets_mock.get.assert_called_once_with(
self.share_network.id,
self.share_network_subnet.id
)
self.assertCountEqual(self.columns, columns)
self.assertCountEqual(self.data, data)

View File

@ -113,6 +113,9 @@ openstack.share.v2 =
share_network_delete = manilaclient.osc.v2.share_networks:DeleteShareNetwork
share_network_set = manilaclient.osc.v2.share_networks:SetShareNetwork
share_network_unset = manilaclient.osc.v2.share_networks:UnsetShareNetwork
share_network_subnet_create = manilaclient.osc.v2.share_network_subnets:CreateShareNetworkSubnet
share_network_subnet_delete = manilaclient.osc.v2.share_network_subnets:DeleteShareNetworkSubnet
share_network_subnet_show = manilaclient.osc.v2.share_network_subnets:ShowShareNetworkSubnet
share_group_create = manilaclient.osc.v2.share_groups:CreateShareGroup
share_group_delete = manilaclient.osc.v2.share_groups:DeleteShareGroup
share_group_list = manilaclient.osc.v2.share_groups:ListShareGroup