Add CLI commands for Share Networks with multiple Subnets
- Added CLI commands for subnets creation, deletion and exhibition. - Updated commands for share server manage and added a new parameter to share server list. API microverion has been bumped to 2.51. Closes-Bug: #1588144 Partially-implements: bp share-network-multiple-subnets Change-Id: I55c85285cbdc9aaf2c0bab2f12477212b32b799a Depends-On: Id8814a8b26c9b9dcb1fe71d0d7e9b79e8b8a9210 Co-Authored-By: lseki <luciomitsuru.seki@fit-tecnologia.org.br>
This commit is contained in:
parent
cc401e5333
commit
b7d0d0d128
manilaclient
api_versions.pyconfig.py
tests
functional
base.pyclient.pytest_share_network_subnets.pytest_share_networks.pytest_share_servers.pytest_shares.pyutils.py
unit/v2
v2
releasenotes/notes
@ -27,7 +27,7 @@ from manilaclient import utils
|
|||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
MAX_VERSION = '2.50'
|
MAX_VERSION = '2.51'
|
||||||
MIN_VERSION = '2.0'
|
MIN_VERSION = '2.0'
|
||||||
DEPRECATED_VERSION = '1.0'
|
DEPRECATED_VERSION = '1.0'
|
||||||
_VERSIONED_METHOD_MAP = {}
|
_VERSIONED_METHOD_MAP = {}
|
||||||
|
@ -110,6 +110,9 @@ share_opts = [
|
|||||||
help="Share network Name or ID, that will be used for shares. "
|
help="Share network Name or ID, that will be used for shares. "
|
||||||
"Some backend drivers require a share network for share "
|
"Some backend drivers require a share network for share "
|
||||||
"creation."),
|
"creation."),
|
||||||
|
cfg.StrOpt("share_network_subnet",
|
||||||
|
help="Share network subnet ID. Some backend drivers require a "
|
||||||
|
"share network for share creation."),
|
||||||
cfg.StrOpt("admin_share_network",
|
cfg.StrOpt("admin_share_network",
|
||||||
help="Share network Name or ID, that will be used for shares "
|
help="Share network Name or ID, that will be used for shares "
|
||||||
"in admin tenant."),
|
"in admin tenant."),
|
||||||
|
@ -76,7 +76,19 @@ class BaseTestCase(base.ClientTestBase):
|
|||||||
if it is not found, assume it was deleted in test itself.
|
if it is not found, assume it was deleted in test itself.
|
||||||
It is expected, that all resources were added as LIFO
|
It is expected, that all resources were added as LIFO
|
||||||
due to restriction of deletion resources, that are in the chain.
|
due to restriction of deletion resources, that are in the chain.
|
||||||
:param resources: dict with keys 'type','id','client' and 'deleted'
|
:param resources: dict with keys 'type','id','client',
|
||||||
|
'deletion_params' and 'deleted'. Optional 'deletion_params'
|
||||||
|
contains additional data needed to delete some type of resources.
|
||||||
|
Ex:
|
||||||
|
params = {
|
||||||
|
'type': 'share_network_subnet',
|
||||||
|
'id': 'share-network-subnet-id',
|
||||||
|
'client': None,
|
||||||
|
'deletion_params': {
|
||||||
|
'share_network': 'share-network-id',
|
||||||
|
},
|
||||||
|
'deleted': False,
|
||||||
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if resources is None:
|
if resources is None:
|
||||||
@ -89,6 +101,7 @@ class BaseTestCase(base.ClientTestBase):
|
|||||||
if not(res["deleted"]):
|
if not(res["deleted"]):
|
||||||
res_id = res["id"]
|
res_id = res["id"]
|
||||||
client = res["client"]
|
client = res["client"]
|
||||||
|
deletion_params = res.get("deletion_params")
|
||||||
with handle_cleanup_exceptions():
|
with handle_cleanup_exceptions():
|
||||||
# TODO(vponomaryov): add support for other resources
|
# TODO(vponomaryov): add support for other resources
|
||||||
if res["type"] is "share_type":
|
if res["type"] is "share_type":
|
||||||
@ -101,6 +114,15 @@ class BaseTestCase(base.ClientTestBase):
|
|||||||
res_id, microversion=res["microversion"])
|
res_id, microversion=res["microversion"])
|
||||||
client.wait_for_share_network_deletion(
|
client.wait_for_share_network_deletion(
|
||||||
res_id, microversion=res["microversion"])
|
res_id, microversion=res["microversion"])
|
||||||
|
elif res["type"] is "share_network_subnet":
|
||||||
|
client.delete_share_network_subnet(
|
||||||
|
share_network_subnet=res_id,
|
||||||
|
share_network=deletion_params["share_network"],
|
||||||
|
microversion=res["microversion"])
|
||||||
|
client.wait_for_share_network_subnet_deletion(
|
||||||
|
share_network_subnet=res_id,
|
||||||
|
share_network=deletion_params["share_network"],
|
||||||
|
microversion=res["microversion"])
|
||||||
elif res["type"] is "share":
|
elif res["type"] is "share":
|
||||||
client.delete_share(
|
client.delete_share(
|
||||||
res_id, microversion=res["microversion"])
|
res_id, microversion=res["microversion"])
|
||||||
@ -233,7 +255,8 @@ class BaseTestCase(base.ClientTestBase):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def create_share_network(cls, name=None, description=None,
|
def create_share_network(cls, name=None, description=None,
|
||||||
neutron_net_id=None,
|
neutron_net_id=None,
|
||||||
neutron_subnet_id=None, client=None,
|
neutron_subnet_id=None,
|
||||||
|
availability_zone=None, client=None,
|
||||||
cleanup_in_class=True, microversion=None):
|
cleanup_in_class=True, microversion=None):
|
||||||
if client is None:
|
if client is None:
|
||||||
client = cls.get_admin_client()
|
client = cls.get_admin_client()
|
||||||
@ -242,6 +265,7 @@ class BaseTestCase(base.ClientTestBase):
|
|||||||
description=description,
|
description=description,
|
||||||
neutron_net_id=neutron_net_id,
|
neutron_net_id=neutron_net_id,
|
||||||
neutron_subnet_id=neutron_subnet_id,
|
neutron_subnet_id=neutron_subnet_id,
|
||||||
|
availability_zone=availability_zone,
|
||||||
microversion=microversion,
|
microversion=microversion,
|
||||||
)
|
)
|
||||||
resource = {
|
resource = {
|
||||||
@ -256,6 +280,31 @@ class BaseTestCase(base.ClientTestBase):
|
|||||||
cls.method_resources.insert(0, resource)
|
cls.method_resources.insert(0, resource)
|
||||||
return share_network
|
return share_network
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def add_share_network_subnet(cls, share_network,
|
||||||
|
neutron_net_id=None, neutron_subnet_id=None,
|
||||||
|
availability_zone=None, client=None,
|
||||||
|
cleanup_in_class=True, microversion=None):
|
||||||
|
if client is None:
|
||||||
|
client = cls.get_admin_client()
|
||||||
|
share_network_subnet = client.add_share_network_subnet(
|
||||||
|
share_network, neutron_net_id, neutron_subnet_id,
|
||||||
|
availability_zone)
|
||||||
|
resource = {
|
||||||
|
"type": "share_network_subnet",
|
||||||
|
"id": share_network_subnet["id"],
|
||||||
|
"client": client,
|
||||||
|
"deletion_params": {
|
||||||
|
"share_network": share_network,
|
||||||
|
},
|
||||||
|
"microversion": microversion,
|
||||||
|
}
|
||||||
|
if cleanup_in_class:
|
||||||
|
cls.class_resources.insert(0, resource)
|
||||||
|
else:
|
||||||
|
cls.method_resources.insert(0, resource)
|
||||||
|
return share_network_subnet
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_share(cls, share_protocol=None, size=None, share_network=None,
|
def create_share(cls, share_protocol=None, size=None, share_network=None,
|
||||||
share_type=None, name=None, description=None,
|
share_type=None, name=None, description=None,
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import ast
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
|
|
||||||
@ -33,6 +34,7 @@ MESSAGE = 'message'
|
|||||||
SHARE = 'share'
|
SHARE = 'share'
|
||||||
SHARE_TYPE = 'share_type'
|
SHARE_TYPE = 'share_type'
|
||||||
SHARE_NETWORK = 'share_network'
|
SHARE_NETWORK = 'share_network'
|
||||||
|
SHARE_NETWORK_SUBNET = 'share_network_subnet'
|
||||||
SHARE_SERVER = 'share_server'
|
SHARE_SERVER = 'share_server'
|
||||||
SNAPSHOT = 'snapshot'
|
SNAPSHOT = 'snapshot'
|
||||||
SHARE_REPLICA = 'share_replica'
|
SHARE_REPLICA = 'share_replica'
|
||||||
@ -115,20 +117,21 @@ class ManilaCLIClient(base.CLIClient):
|
|||||||
'manila', action, flags, params, fail_ok, merge_stderr)
|
'manila', action, flags, params, fail_ok, merge_stderr)
|
||||||
|
|
||||||
def wait_for_resource_deletion(self, res_type, res_id, interval=3,
|
def wait_for_resource_deletion(self, res_type, res_id, interval=3,
|
||||||
timeout=180, microversion=None):
|
timeout=180, microversion=None, **kwargs):
|
||||||
"""Resource deletion waiter.
|
"""Resource deletion waiter.
|
||||||
|
|
||||||
:param res_type: text -- type of resource. Supported only 'share_type'.
|
:param res_type: text -- type of resource
|
||||||
Other types support is TODO.
|
|
||||||
:param res_id: text -- ID of resource to use for deletion check
|
:param res_id: text -- ID of resource to use for deletion check
|
||||||
:param interval: int -- interval between requests in seconds
|
:param interval: int -- interval between requests in seconds
|
||||||
:param timeout: int -- total time in seconds to wait for deletion
|
:param timeout: int -- total time in seconds to wait for deletion
|
||||||
|
:param args: dict -- additional keyword arguments for deletion func
|
||||||
"""
|
"""
|
||||||
# TODO(vponomaryov): add support for other resource types
|
|
||||||
if res_type == SHARE_TYPE:
|
if res_type == SHARE_TYPE:
|
||||||
func = self.is_share_type_deleted
|
func = self.is_share_type_deleted
|
||||||
elif res_type == SHARE_NETWORK:
|
elif res_type == SHARE_NETWORK:
|
||||||
func = self.is_share_network_deleted
|
func = self.is_share_network_deleted
|
||||||
|
elif res_type == SHARE_NETWORK_SUBNET:
|
||||||
|
func = self.is_share_network_subnet_deleted
|
||||||
elif res_type == SHARE_SERVER:
|
elif res_type == SHARE_SERVER:
|
||||||
func = self.is_share_server_deleted
|
func = self.is_share_server_deleted
|
||||||
elif res_type == SHARE:
|
elif res_type == SHARE:
|
||||||
@ -143,11 +146,11 @@ class ManilaCLIClient(base.CLIClient):
|
|||||||
raise exceptions.InvalidResource(message=res_type)
|
raise exceptions.InvalidResource(message=res_type)
|
||||||
|
|
||||||
end_loop_time = time.time() + timeout
|
end_loop_time = time.time() + timeout
|
||||||
deleted = func(res_id, microversion=microversion)
|
deleted = func(res_id, microversion=microversion, **kwargs)
|
||||||
|
|
||||||
while not (deleted or time.time() > end_loop_time):
|
while not (deleted or time.time() > end_loop_time):
|
||||||
time.sleep(interval)
|
time.sleep(interval)
|
||||||
deleted = func(res_id, microversion=microversion)
|
deleted = func(res_id, microversion=microversion, **kwargs)
|
||||||
|
|
||||||
if not deleted:
|
if not deleted:
|
||||||
raise exceptions.ResourceReleaseFailed(
|
raise exceptions.ResourceReleaseFailed(
|
||||||
@ -451,7 +454,8 @@ class ManilaCLIClient(base.CLIClient):
|
|||||||
|
|
||||||
def create_share_network(self, name=None, description=None,
|
def create_share_network(self, name=None, description=None,
|
||||||
nova_net_id=None, neutron_net_id=None,
|
nova_net_id=None, neutron_net_id=None,
|
||||||
neutron_subnet_id=None, microversion=None):
|
neutron_subnet_id=None, availability_zone=None,
|
||||||
|
microversion=None):
|
||||||
"""Creates share network.
|
"""Creates share network.
|
||||||
|
|
||||||
:param name: text -- desired name of new share network
|
:param name: text -- desired name of new share network
|
||||||
@ -468,7 +472,9 @@ class ManilaCLIClient(base.CLIClient):
|
|||||||
description=description,
|
description=description,
|
||||||
nova_net_id=nova_net_id,
|
nova_net_id=nova_net_id,
|
||||||
neutron_net_id=neutron_net_id,
|
neutron_net_id=neutron_net_id,
|
||||||
neutron_subnet_id=neutron_subnet_id)
|
neutron_subnet_id=neutron_subnet_id,
|
||||||
|
availability_zone=availability_zone
|
||||||
|
)
|
||||||
share_network_raw = self.manila(
|
share_network_raw = self.manila(
|
||||||
'share-network-create %s' % params, microversion=microversion)
|
'share-network-create %s' % params, microversion=microversion)
|
||||||
share_network = output_parser.details(share_network_raw)
|
share_network = output_parser.details(share_network_raw)
|
||||||
@ -476,7 +482,8 @@ class ManilaCLIClient(base.CLIClient):
|
|||||||
|
|
||||||
def _combine_share_network_data(self, name=None, description=None,
|
def _combine_share_network_data(self, name=None, description=None,
|
||||||
nova_net_id=None, neutron_net_id=None,
|
nova_net_id=None, neutron_net_id=None,
|
||||||
neutron_subnet_id=None):
|
neutron_subnet_id=None,
|
||||||
|
availability_zone=None):
|
||||||
"""Combines params for share network operations 'create' and 'update'.
|
"""Combines params for share network operations 'create' and 'update'.
|
||||||
|
|
||||||
:returns: text -- set of CLI parameters
|
:returns: text -- set of CLI parameters
|
||||||
@ -492,9 +499,11 @@ class ManilaCLIClient(base.CLIClient):
|
|||||||
data['--neutron_net_id'] = neutron_net_id
|
data['--neutron_net_id'] = neutron_net_id
|
||||||
if neutron_subnet_id is not None:
|
if neutron_subnet_id is not None:
|
||||||
data['--neutron_subnet_id'] = neutron_subnet_id
|
data['--neutron_subnet_id'] = neutron_subnet_id
|
||||||
|
if availability_zone is not None:
|
||||||
|
data['--availability_zone'] = availability_zone
|
||||||
cmd = ''
|
cmd = ''
|
||||||
for key, value in data.items():
|
for key, value in data.items():
|
||||||
cmd += "%(k)s=%(v)s " % dict(k=key, v=value)
|
cmd += "%(k)s=%(v)s " % {'k': key, 'v': value}
|
||||||
return cmd
|
return cmd
|
||||||
|
|
||||||
@not_found_wrapper
|
@not_found_wrapper
|
||||||
@ -598,6 +607,106 @@ class ManilaCLIClient(base.CLIClient):
|
|||||||
SHARE_NETWORK, res_id=share_network, interval=2, timeout=6,
|
SHARE_NETWORK, res_id=share_network, interval=2, timeout=6,
|
||||||
microversion=microversion)
|
microversion=microversion)
|
||||||
|
|
||||||
|
# Share Network Subnets
|
||||||
|
|
||||||
|
def _combine_share_network_subnet_data(self, neutron_net_id=None,
|
||||||
|
neutron_subnet_id=None,
|
||||||
|
availability_zone=None):
|
||||||
|
"""Combines params for share network subnet 'create' operation.
|
||||||
|
|
||||||
|
:returns: text -- set of CLI parameters
|
||||||
|
"""
|
||||||
|
data = dict()
|
||||||
|
if neutron_net_id is not None:
|
||||||
|
data['--neutron_net_id'] = neutron_net_id
|
||||||
|
if neutron_subnet_id is not None:
|
||||||
|
data['--neutron_subnet_id'] = neutron_subnet_id
|
||||||
|
if availability_zone is not None:
|
||||||
|
data['--availability_zone'] = availability_zone
|
||||||
|
cmd = ''
|
||||||
|
for key, value in data.items():
|
||||||
|
cmd += "%(k)s=%(v)s " % dict(k=key, v=value)
|
||||||
|
return cmd
|
||||||
|
|
||||||
|
def add_share_network_subnet(self, share_network,
|
||||||
|
neutron_net_id=None, neutron_subnet_id=None,
|
||||||
|
availability_zone=None, microversion=None):
|
||||||
|
"""Create new share network subnet for the given share network."""
|
||||||
|
params = self._combine_share_network_subnet_data(
|
||||||
|
neutron_net_id=neutron_net_id,
|
||||||
|
neutron_subnet_id=neutron_subnet_id,
|
||||||
|
availability_zone=availability_zone)
|
||||||
|
share_network_subnet_raw = self.manila(
|
||||||
|
'share-network-subnet-create %(sn)s %(params)s' %
|
||||||
|
{'sn': share_network, 'params': params}, microversion=microversion)
|
||||||
|
share_network_subnet = output_parser.details(share_network_subnet_raw)
|
||||||
|
return share_network_subnet
|
||||||
|
|
||||||
|
def get_share_network_subnet(self, share_network, share_network_subnet,
|
||||||
|
microversion=None):
|
||||||
|
"""Returns share network subnet by share network ID and subnet ID."""
|
||||||
|
|
||||||
|
share_network_subnet_raw = self.manila(
|
||||||
|
'share-network-subnet-show %(share_net)s %(share_subnet)s' % {
|
||||||
|
'share_net': share_network,
|
||||||
|
'share_subnet': share_network_subnet,
|
||||||
|
})
|
||||||
|
share_network_subnet = output_parser.details(share_network_subnet_raw)
|
||||||
|
return share_network_subnet
|
||||||
|
|
||||||
|
def get_share_network_subnets(self, share_network, microversion=None):
|
||||||
|
share_network = self.get_share_network(share_network,
|
||||||
|
microversion=microversion)
|
||||||
|
raw_subnets = share_network.get('share_network_subnets')
|
||||||
|
subnets = ast.literal_eval(raw_subnets)
|
||||||
|
# NOTE(lseki): convert literal None to string 'None'
|
||||||
|
for subnet in subnets:
|
||||||
|
for k, v in subnet.items():
|
||||||
|
subnet[k] = str(v) if v is None else v
|
||||||
|
return subnets
|
||||||
|
|
||||||
|
@not_found_wrapper
|
||||||
|
def delete_share_network_subnet(self, share_network, share_network_subnet,
|
||||||
|
microversion=None):
|
||||||
|
"""Delete a share_network."""
|
||||||
|
self.manila(
|
||||||
|
'share-network-subnet-delete %(share_net)s %(share_subnet)s' % {
|
||||||
|
'share_net': share_network,
|
||||||
|
'share_subnet': share_network_subnet,
|
||||||
|
}, microversion=microversion)
|
||||||
|
|
||||||
|
def is_share_network_subnet_deleted(self, share_network_subnet,
|
||||||
|
share_network, microversion=None):
|
||||||
|
# NOTE(lseki): the parameter share_network_subnet comes before
|
||||||
|
# share_network, because the wrapper method wait_for_resource_deletion
|
||||||
|
# expects the resource id in first place (subnet ID in this case).
|
||||||
|
"""Says whether share network subnet is deleted or not.
|
||||||
|
|
||||||
|
:param share_network_subnet: text -- Name or ID of share network subnet
|
||||||
|
:param share_network: text -- Name or ID of share network the subnet
|
||||||
|
belongs to
|
||||||
|
"""
|
||||||
|
subnets = self.get_share_network_subnets(share_network)
|
||||||
|
return not any(subnet['id'] == share_network_subnet
|
||||||
|
for subnet in subnets)
|
||||||
|
|
||||||
|
def wait_for_share_network_subnet_deletion(self, share_network_subnet,
|
||||||
|
share_network,
|
||||||
|
microversion=None):
|
||||||
|
# NOTE(lseki): the parameter share_network_subnet comes before
|
||||||
|
# share_network, because the wrapper method wait_for_resource_deletion
|
||||||
|
# expects the resource id in first place (subnet ID in this case).
|
||||||
|
"""Wait for share network subnet deletion by its Name or ID.
|
||||||
|
|
||||||
|
:param share_network_subnet: text -- Name or ID of share network subnet
|
||||||
|
:param share_network: text -- Name or ID of share network the subnet
|
||||||
|
belongs to
|
||||||
|
"""
|
||||||
|
args = {'share_network': share_network}
|
||||||
|
self.wait_for_resource_deletion(
|
||||||
|
SHARE_NETWORK_SUBNET, res_id=share_network_subnet,
|
||||||
|
interval=2, timeout=6, microversion=microversion, **args)
|
||||||
|
|
||||||
# Shares
|
# Shares
|
||||||
|
|
||||||
def create_share(self, share_protocol, size, share_network=None,
|
def create_share(self, share_protocol, size, share_network=None,
|
||||||
|
120
manilaclient/tests/functional/test_share_network_subnets.py
Normal file
120
manilaclient/tests/functional/test_share_network_subnets.py
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
# Copyright 2019 NetApp
|
||||||
|
# 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 ddt
|
||||||
|
from manilaclient.tests.functional import base
|
||||||
|
from manilaclient.tests.functional import utils
|
||||||
|
from tempest.lib.common.utils import data_utils
|
||||||
|
from tempest.lib import exceptions
|
||||||
|
|
||||||
|
|
||||||
|
@ddt.ddt
|
||||||
|
@utils.skip_if_microversion_not_supported('2.51')
|
||||||
|
class ShareNetworkSubnetsReadWriteTest(base.BaseTestCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
super(ShareNetworkSubnetsReadWriteTest, cls).setUpClass()
|
||||||
|
cls.name = data_utils.rand_name('autotest')
|
||||||
|
cls.description = 'fake_description'
|
||||||
|
cls.neutron_net_id = 'fake_neutron_net_id'
|
||||||
|
cls.neutron_subnet_id = 'fake_neutron_subnet_id'
|
||||||
|
|
||||||
|
cls.sn = cls.create_share_network(
|
||||||
|
name=cls.name,
|
||||||
|
description=cls.description,
|
||||||
|
neutron_net_id=cls.neutron_net_id,
|
||||||
|
neutron_subnet_id=cls.neutron_subnet_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_get_share_network_subnet(self):
|
||||||
|
default_subnet = utils.get_default_subnet(self.user_client,
|
||||||
|
self.sn['id'])
|
||||||
|
|
||||||
|
subnet = self.user_client.get_share_network_subnet(
|
||||||
|
self.sn['id'], default_subnet['id'])
|
||||||
|
|
||||||
|
self.assertEqual(self.neutron_net_id, subnet['neutron_net_id'])
|
||||||
|
self.assertEqual(self.neutron_subnet_id, subnet['neutron_subnet_id'])
|
||||||
|
|
||||||
|
def test_get_invalid_share_network_subnet(self):
|
||||||
|
self.assertRaises(
|
||||||
|
exceptions.CommandFailed,
|
||||||
|
self.user_client.get_share_network_subnet,
|
||||||
|
self.sn['id'], 'invalid_subnet_id')
|
||||||
|
|
||||||
|
def _get_availability_zone(self):
|
||||||
|
availability_zones = self.user_client.list_availability_zones()
|
||||||
|
return availability_zones[0]['Name']
|
||||||
|
|
||||||
|
def test_add_share_network_subnet_to_share_network(self):
|
||||||
|
neutron_net_id = 'new_neutron_net_id'
|
||||||
|
neutron_subnet_id = 'new_neutron_subnet_id'
|
||||||
|
availability_zone = self._get_availability_zone()
|
||||||
|
|
||||||
|
subnet = self.add_share_network_subnet(
|
||||||
|
self.sn['id'],
|
||||||
|
neutron_net_id, neutron_subnet_id,
|
||||||
|
availability_zone,
|
||||||
|
cleanup_in_class=False)
|
||||||
|
|
||||||
|
self.assertEqual(neutron_net_id, subnet['neutron_net_id'])
|
||||||
|
self.assertEqual(neutron_subnet_id, subnet['neutron_subnet_id'])
|
||||||
|
self.assertEqual(availability_zone, subnet['availability_zone'])
|
||||||
|
|
||||||
|
@ddt.data(
|
||||||
|
{'neutron_net_id': None, 'neutron_subnet_id': 'fake_subnet_id'},
|
||||||
|
{'neutron_net_id': 'fake_net_id', 'neutron_subnet_id': None},
|
||||||
|
{'availability_zone': 'invalid_availability_zone'},
|
||||||
|
)
|
||||||
|
def test_add_invalid_share_network_subnet_to_share_network(self, params):
|
||||||
|
self.assertRaises(
|
||||||
|
exceptions.CommandFailed,
|
||||||
|
self.add_share_network_subnet,
|
||||||
|
self.sn['id'],
|
||||||
|
**params)
|
||||||
|
|
||||||
|
def test_add_share_network_subnet_to_invalid_share_network(self):
|
||||||
|
self.assertRaises(
|
||||||
|
exceptions.CommandFailed,
|
||||||
|
self.add_share_network_subnet,
|
||||||
|
'invalid_share_network',
|
||||||
|
self.neutron_net_id,
|
||||||
|
self.neutron_subnet_id)
|
||||||
|
|
||||||
|
def test_add_delete_share_network_subnet_from_share_network(self):
|
||||||
|
neutron_net_id = 'new_neutron_net_id'
|
||||||
|
neutron_subnet_id = 'new_neutron_subnet_id'
|
||||||
|
availability_zone = self._get_availability_zone()
|
||||||
|
|
||||||
|
subnet = self.add_share_network_subnet(
|
||||||
|
self.sn['id'],
|
||||||
|
neutron_net_id, neutron_subnet_id,
|
||||||
|
availability_zone,
|
||||||
|
cleanup_in_class=False)
|
||||||
|
self.user_client.delete_share_network_subnet(
|
||||||
|
share_network_subnet=subnet['id'],
|
||||||
|
share_network=self.sn['id'])
|
||||||
|
|
||||||
|
self.user_client.wait_for_share_network_subnet_deletion(
|
||||||
|
share_network_subnet=subnet['id'],
|
||||||
|
share_network=self.sn['id'])
|
||||||
|
|
||||||
|
def test_delete_invalid_share_network_subnet(self):
|
||||||
|
self.assertRaises(
|
||||||
|
exceptions.NotFound,
|
||||||
|
self.user_client.delete_share_network_subnet,
|
||||||
|
share_network_subnet='invalid_subnet_id',
|
||||||
|
share_network=self.sn['id'])
|
@ -14,11 +14,13 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import ast
|
||||||
import ddt
|
import ddt
|
||||||
from tempest.lib.common.utils import data_utils
|
from tempest.lib.common.utils import data_utils
|
||||||
from tempest.lib import exceptions as tempest_lib_exc
|
from tempest.lib import exceptions as tempest_lib_exc
|
||||||
|
|
||||||
from manilaclient.tests.functional import base
|
from manilaclient.tests.functional import base
|
||||||
|
from manilaclient.tests.functional import utils
|
||||||
|
|
||||||
|
|
||||||
@ddt.ddt
|
@ddt.ddt
|
||||||
@ -46,7 +48,14 @@ class ShareNetworksReadWriteTest(base.BaseTestCase):
|
|||||||
'neutron_subnet_id': 'fake_neutron_subnet_id'},
|
'neutron_subnet_id': 'fake_neutron_subnet_id'},
|
||||||
)
|
)
|
||||||
def test_create_delete_share_network(self, net_data):
|
def test_create_delete_share_network(self, net_data):
|
||||||
|
share_subnet_support = utils.share_network_subnets_are_supported()
|
||||||
|
share_subnet_fields = (
|
||||||
|
['neutron_net_id', 'neutron_subnet_id', 'availability_zone']
|
||||||
|
if share_subnet_support else [])
|
||||||
sn = self.create_share_network(cleanup_in_class=False, **net_data)
|
sn = self.create_share_network(cleanup_in_class=False, **net_data)
|
||||||
|
default_subnet = (utils.get_default_subnet(self.user_client, sn['id'])
|
||||||
|
if share_subnet_support
|
||||||
|
else None)
|
||||||
|
|
||||||
expected_data = {
|
expected_data = {
|
||||||
'name': 'None',
|
'name': 'None',
|
||||||
@ -55,9 +64,54 @@ class ShareNetworksReadWriteTest(base.BaseTestCase):
|
|||||||
'neutron_subnet_id': 'None',
|
'neutron_subnet_id': 'None',
|
||||||
}
|
}
|
||||||
expected_data.update(net_data)
|
expected_data.update(net_data)
|
||||||
|
share_network_expected_data = [
|
||||||
|
(k, v) for k, v in expected_data.items()
|
||||||
|
if k not in share_subnet_fields]
|
||||||
|
share_subnet_expected_data = [
|
||||||
|
(k, v) for k, v in expected_data.items()
|
||||||
|
if k in share_subnet_fields]
|
||||||
|
|
||||||
for k, v in expected_data.items():
|
for k, v in share_network_expected_data:
|
||||||
self.assertEqual(v, sn[k])
|
self.assertEqual(v, sn[k])
|
||||||
|
for k, v in share_subnet_expected_data:
|
||||||
|
self.assertEqual(v, default_subnet[k])
|
||||||
|
|
||||||
|
self.admin_client.delete_share_network(sn['id'])
|
||||||
|
self.admin_client.wait_for_share_network_deletion(sn['id'])
|
||||||
|
|
||||||
|
@utils.skip_if_microversion_not_supported('2.51')
|
||||||
|
def test_create_delete_share_network_with_az(self):
|
||||||
|
share_subnet_fields = (
|
||||||
|
['neutron_net_id', 'neutron_subnet_id', 'availability_zone'])
|
||||||
|
az = self.user_client.list_availability_zones()[0]
|
||||||
|
net_data = {
|
||||||
|
'neutron_net_id': 'fake_neutron_net_id',
|
||||||
|
'neutron_subnet_id': 'fake_neutron_subnet_id',
|
||||||
|
'availability_zone': az['Name']
|
||||||
|
}
|
||||||
|
sn = self.create_share_network(cleanup_in_class=False, **net_data)
|
||||||
|
default_subnet = utils.get_subnet_by_availability_zone_name(
|
||||||
|
self.user_client, sn['id'], az['Name'])
|
||||||
|
|
||||||
|
expected_data = {
|
||||||
|
'name': 'None',
|
||||||
|
'description': 'None',
|
||||||
|
'neutron_net_id': 'None',
|
||||||
|
'neutron_subnet_id': 'None',
|
||||||
|
'availability_zone': 'None',
|
||||||
|
}
|
||||||
|
expected_data.update(net_data)
|
||||||
|
share_network_expected_data = [
|
||||||
|
(k, v) for k, v in expected_data.items()
|
||||||
|
if k not in share_subnet_fields]
|
||||||
|
share_subnet_expected_data = [
|
||||||
|
(k, v) for k, v in expected_data.items()
|
||||||
|
if k in share_subnet_fields]
|
||||||
|
|
||||||
|
for k, v in share_network_expected_data:
|
||||||
|
self.assertEqual(v, sn[k])
|
||||||
|
for k, v in share_subnet_expected_data:
|
||||||
|
self.assertEqual(v, default_subnet[k])
|
||||||
|
|
||||||
self.admin_client.delete_share_network(sn['id'])
|
self.admin_client.delete_share_network(sn['id'])
|
||||||
self.admin_client.wait_for_share_network_deletion(sn['id'])
|
self.admin_client.wait_for_share_network_deletion(sn['id'])
|
||||||
@ -67,6 +121,7 @@ class ShareNetworksReadWriteTest(base.BaseTestCase):
|
|||||||
|
|
||||||
self.assertEqual(self.name, get['name'])
|
self.assertEqual(self.name, get['name'])
|
||||||
self.assertEqual(self.description, get['description'])
|
self.assertEqual(self.description, get['description'])
|
||||||
|
if not utils.share_network_subnets_are_supported():
|
||||||
self.assertEqual(self.neutron_net_id, get['neutron_net_id'])
|
self.assertEqual(self.neutron_net_id, get['neutron_net_id'])
|
||||||
self.assertEqual(self.neutron_subnet_id, get['neutron_subnet_id'])
|
self.assertEqual(self.neutron_subnet_id, get['neutron_subnet_id'])
|
||||||
|
|
||||||
@ -91,11 +146,21 @@ class ShareNetworksReadWriteTest(base.BaseTestCase):
|
|||||||
'neutron_net_id': 'None',
|
'neutron_net_id': 'None',
|
||||||
'neutron_subnet_id': 'None',
|
'neutron_subnet_id': 'None',
|
||||||
}
|
}
|
||||||
|
subnet_keys = []
|
||||||
|
if utils.share_network_subnets_are_supported():
|
||||||
|
subnet_keys = ['neutron_net_id', 'neutron_subnet_id']
|
||||||
|
subnet = ast.literal_eval(update['share_network_subnets'])
|
||||||
|
expected_data['neutron_net_id'] = None
|
||||||
|
expected_data['neutron_subnet_id'] = None
|
||||||
|
|
||||||
update_values = dict([(k, v) for k, v in net_data.items()
|
update_values = dict([(k, v) for k, v in net_data.items()
|
||||||
if v != '""'])
|
if v != '""'])
|
||||||
expected_data.update(update_values)
|
expected_data.update(update_values)
|
||||||
|
|
||||||
for k, v in expected_data.items():
|
for k, v in expected_data.items():
|
||||||
|
if k in subnet_keys:
|
||||||
|
self.assertEqual(v, subnet[0][k])
|
||||||
|
else:
|
||||||
self.assertEqual(v, update[k])
|
self.assertEqual(v, update[k])
|
||||||
|
|
||||||
self.admin_client.delete_share_network(sn['id'])
|
self.admin_client.delete_share_network(sn['id'])
|
||||||
@ -119,6 +184,14 @@ class ShareNetworksReadWriteTest(base.BaseTestCase):
|
|||||||
self.assertTrue(all('name' not in s for s in share_networks))
|
self.assertTrue(all('name' not in s for s in share_networks))
|
||||||
|
|
||||||
def _list_share_networks_with_filters(self, filters):
|
def _list_share_networks_with_filters(self, filters):
|
||||||
|
assert_subnet_fields = utils.share_network_subnets_are_supported()
|
||||||
|
share_subnet_fields = (['neutron_subnet_id', 'neutron_net_id']
|
||||||
|
if assert_subnet_fields
|
||||||
|
else [])
|
||||||
|
share_network_filters = [(k, v) for k, v in filters.items()
|
||||||
|
if k not in share_subnet_fields]
|
||||||
|
share_network_subnet_filters = [(k, v) for k, v in filters.items()
|
||||||
|
if k in share_subnet_fields]
|
||||||
share_networks = self.admin_client.list_share_networks(filters=filters)
|
share_networks = self.admin_client.list_share_networks(filters=filters)
|
||||||
|
|
||||||
self.assertGreater(len(share_networks), 0)
|
self.assertGreater(len(share_networks), 0)
|
||||||
@ -126,14 +199,21 @@ class ShareNetworksReadWriteTest(base.BaseTestCase):
|
|||||||
any(self.sn['id'] == sn['id'] for sn in share_networks))
|
any(self.sn['id'] == sn['id'] for sn in share_networks))
|
||||||
for sn in share_networks:
|
for sn in share_networks:
|
||||||
try:
|
try:
|
||||||
get = self.admin_client.get_share_network(sn['id'])
|
share_network = self.admin_client.get_share_network(sn['id'])
|
||||||
|
default_subnet = (
|
||||||
|
utils.get_default_subnet(self.user_client, sn['id'])
|
||||||
|
if assert_subnet_fields
|
||||||
|
else None)
|
||||||
except tempest_lib_exc.NotFound:
|
except tempest_lib_exc.NotFound:
|
||||||
# NOTE(vponomaryov): Case when some share network was deleted
|
# NOTE(vponomaryov): Case when some share network was deleted
|
||||||
# between our 'list' and 'get' requests. Skip such case.
|
# between our 'list' and 'get' requests. Skip such case.
|
||||||
continue
|
continue
|
||||||
for k, v in filters.items():
|
for k, v in share_network_filters:
|
||||||
self.assertIn(k, get)
|
self.assertIn(k, share_network)
|
||||||
self.assertEqual(v, get[k])
|
self.assertEqual(v, share_network[k])
|
||||||
|
for k, v in share_network_subnet_filters:
|
||||||
|
self.assertIn(k, default_subnet)
|
||||||
|
self.assertEqual(v, default_subnet[k])
|
||||||
|
|
||||||
def test_list_share_networks_filter_by_project_id(self):
|
def test_list_share_networks_filter_by_project_id(self):
|
||||||
project_id = self.admin_client.get_project_id(
|
project_id = self.admin_client.get_project_id(
|
||||||
|
@ -89,13 +89,18 @@ class ShareServersReadWriteBase(base.BaseTestCase):
|
|||||||
|
|
||||||
common_share_network = self.client.get_share_network(
|
common_share_network = self.client.get_share_network(
|
||||||
self.client.share_network)
|
self.client.share_network)
|
||||||
|
share_net_info = (
|
||||||
|
utils.get_default_subnet(self.user_client,
|
||||||
|
common_share_network['id'])
|
||||||
|
if utils.share_network_subnets_are_supported()
|
||||||
|
else common_share_network)
|
||||||
neutron_net_id = (
|
neutron_net_id = (
|
||||||
common_share_network['neutron_net_id']
|
share_net_info['neutron_net_id']
|
||||||
if 'none' not in common_share_network['neutron_net_id'].lower()
|
if 'none' not in share_net_info['neutron_net_id'].lower()
|
||||||
else None)
|
else None)
|
||||||
neutron_subnet_id = (
|
neutron_subnet_id = (
|
||||||
common_share_network['neutron_subnet_id']
|
share_net_info['neutron_subnet_id']
|
||||||
if 'none' not in common_share_network['neutron_subnet_id'].lower()
|
if 'none' not in share_net_info['neutron_subnet_id'].lower()
|
||||||
else None)
|
else None)
|
||||||
share_network = self.client.create_share_network(
|
share_network = self.client.create_share_network(
|
||||||
neutron_net_id=neutron_net_id,
|
neutron_net_id=neutron_net_id,
|
||||||
@ -142,6 +147,7 @@ class ShareServersReadWriteBase(base.BaseTestCase):
|
|||||||
self.assertIn(key, server)
|
self.assertIn(key, server)
|
||||||
|
|
||||||
self._delete_share_and_share_server(self.share['id'], share_server_id)
|
self._delete_share_and_share_server(self.share['id'], share_server_id)
|
||||||
|
self.client.delete_share_network(share_network['id'])
|
||||||
|
|
||||||
@testtools.skipUnless(
|
@testtools.skipUnless(
|
||||||
CONF.run_manage_tests, 'Share Manage/Unmanage tests are disabled.')
|
CONF.run_manage_tests, 'Share Manage/Unmanage tests are disabled.')
|
||||||
@ -189,6 +195,7 @@ class ShareServersReadWriteBase(base.BaseTestCase):
|
|||||||
|
|
||||||
self._delete_share_and_share_server(managed_share_id,
|
self._delete_share_and_share_server(managed_share_id,
|
||||||
managed_share_server_id)
|
managed_share_server_id)
|
||||||
|
self.client.delete_share_network(share_network['id'])
|
||||||
|
|
||||||
|
|
||||||
class ShareServersReadWriteNFSTest(ShareServersReadWriteBase):
|
class ShareServersReadWriteNFSTest(ShareServersReadWriteBase):
|
||||||
|
@ -113,9 +113,14 @@ class SharesTestMigration(base.BaseTestCase):
|
|||||||
|
|
||||||
cls.old_share_net = cls.get_user_client().get_share_network(
|
cls.old_share_net = cls.get_user_client().get_share_network(
|
||||||
cls.get_user_client().share_network)
|
cls.get_user_client().share_network)
|
||||||
|
share_net_info = (
|
||||||
|
utils.get_default_subnet(cls.get_user_client(),
|
||||||
|
cls.old_share_net['id'])
|
||||||
|
if utils.share_network_subnets_are_supported()
|
||||||
|
else cls.old_share_net)
|
||||||
cls.new_share_net = cls.create_share_network(
|
cls.new_share_net = cls.create_share_network(
|
||||||
neutron_net_id=cls.old_share_net['neutron_net_id'],
|
neutron_net_id=share_net_info['neutron_net_id'],
|
||||||
neutron_subnet_id=cls.old_share_net['neutron_subnet_id'])
|
neutron_subnet_id=share_net_info['neutron_subnet_id'])
|
||||||
|
|
||||||
@utils.skip_if_microversion_not_supported('2.22')
|
@utils.skip_if_microversion_not_supported('2.22')
|
||||||
@ddt.data('migration_error', 'migration_success', 'None')
|
@ddt.data('migration_error', 'migration_success', 'None')
|
||||||
|
@ -138,3 +138,18 @@ def choose_matching_backend(share, pools, share_type):
|
|||||||
None)
|
None)
|
||||||
|
|
||||||
return selected_pool['Name']
|
return selected_pool['Name']
|
||||||
|
|
||||||
|
|
||||||
|
def share_network_subnets_are_supported():
|
||||||
|
return is_microversion_supported('2.51')
|
||||||
|
|
||||||
|
|
||||||
|
def get_subnet_by_availability_zone_name(client, share_network_id, az_name):
|
||||||
|
subnets = client.get_share_network_subnets(share_network_id)
|
||||||
|
return next((subnet for subnet in subnets
|
||||||
|
if subnet['availability_zone'] == az_name), None)
|
||||||
|
|
||||||
|
|
||||||
|
def get_default_subnet(client, share_network_id):
|
||||||
|
return get_subnet_by_availability_zone_name(client, share_network_id,
|
||||||
|
'None')
|
||||||
|
@ -579,6 +579,9 @@ class FakeHTTPClient(fakes.FakeHTTPClient):
|
|||||||
def post_share_networks(self, **kwargs):
|
def post_share_networks(self, **kwargs):
|
||||||
return (202, {}, {'share_network': {}})
|
return (202, {}, {'share_network': {}})
|
||||||
|
|
||||||
|
def post_share_networks_1234_subnets(self, **kwargs):
|
||||||
|
return (202, {}, {'share_network_subnet': {}})
|
||||||
|
|
||||||
def post_shares(self, **kwargs):
|
def post_shares(self, **kwargs):
|
||||||
return (202, {}, {'share': {}})
|
return (202, {}, {'share': {}})
|
||||||
|
|
||||||
@ -609,6 +612,12 @@ class FakeHTTPClient(fakes.FakeHTTPClient):
|
|||||||
def delete_share_networks_fake_share_network2(self, **kwargs):
|
def delete_share_networks_fake_share_network2(self, **kwargs):
|
||||||
return (202, {}, None)
|
return (202, {}, None)
|
||||||
|
|
||||||
|
def delete_share_networks_1234_subnets_fake_subnet1(self, **kwargs):
|
||||||
|
return (202, {}, None)
|
||||||
|
|
||||||
|
def delete_share_networks_1234_subnets_fake_subnet2(self, **kwargs):
|
||||||
|
return (202, {}, None)
|
||||||
|
|
||||||
def delete_snapshots_fake_snapshot1(self, **kwargs):
|
def delete_snapshots_fake_snapshot1(self, **kwargs):
|
||||||
return (202, {}, None)
|
return (202, {}, None)
|
||||||
|
|
||||||
@ -663,6 +672,14 @@ class FakeHTTPClient(fakes.FakeHTTPClient):
|
|||||||
}
|
}
|
||||||
return (200, {}, share_nw)
|
return (200, {}, share_nw)
|
||||||
|
|
||||||
|
def get_share_networks_1234_subnets_fake_subnet_id(self, **kw):
|
||||||
|
subnet = {
|
||||||
|
'share_network_subnet': {
|
||||||
|
'id': 'fake_subnet_id',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return (200, {}, subnet)
|
||||||
|
|
||||||
def get_security_services(self, **kw):
|
def get_security_services(self, **kw):
|
||||||
security_services = {
|
security_services = {
|
||||||
'security_services': [
|
'security_services': [
|
||||||
|
82
manilaclient/tests/unit/v2/test_share_network_subnets.py
Normal file
82
manilaclient/tests/unit/v2/test_share_network_subnets.py
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
# Copyright 2019 NetApp
|
||||||
|
# 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 ddt
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from manilaclient.tests.unit import utils
|
||||||
|
from manilaclient.tests.unit.v2 import fakes
|
||||||
|
from manilaclient.v2 import share_network_subnets
|
||||||
|
|
||||||
|
|
||||||
|
@ddt.ddt
|
||||||
|
class ShareNetworkSubnetTest(utils.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(ShareNetworkSubnetTest, self).setUp()
|
||||||
|
self.manager = share_network_subnets.ShareNetworkSubnetManager(
|
||||||
|
fakes.FakeClient())
|
||||||
|
|
||||||
|
def test_create(self):
|
||||||
|
share_network_id = 'fake_share_net_id'
|
||||||
|
expected_url = share_network_subnets.RESOURCES_PATH % {
|
||||||
|
'share_network_id': share_network_id
|
||||||
|
}
|
||||||
|
expected_values = {
|
||||||
|
'neutron_net_id': 'fake_net_id',
|
||||||
|
'neutron_subnet_id': 'fake_subnet_id',
|
||||||
|
'availability_zone': 'fake_availability_zone',
|
||||||
|
}
|
||||||
|
expected_body = {'share-network-subnet': expected_values}
|
||||||
|
payload = expected_values.copy()
|
||||||
|
payload.update({'share_network_id': share_network_id})
|
||||||
|
|
||||||
|
with mock.patch.object(self.manager, '_create', fakes.fake_create):
|
||||||
|
result = self.manager.create(**payload)
|
||||||
|
|
||||||
|
self.assertEqual(expected_url, result['url'])
|
||||||
|
self.assertEqual(
|
||||||
|
share_network_subnets.RESOURCE_NAME,
|
||||||
|
result['resp_key'])
|
||||||
|
self.assertEqual(
|
||||||
|
expected_body,
|
||||||
|
result['body'])
|
||||||
|
|
||||||
|
def test_get(self):
|
||||||
|
share_network = 'fake_share_network'
|
||||||
|
share_subnet = 'fake_share_subnet'
|
||||||
|
|
||||||
|
with mock.patch.object(self.manager, '_get', mock.Mock()):
|
||||||
|
self.manager.get(share_network, share_subnet)
|
||||||
|
|
||||||
|
self.manager._get.assert_called_once_with(
|
||||||
|
share_network_subnets.RESOURCE_PATH % {
|
||||||
|
'share_network_id': share_network,
|
||||||
|
'share_network_subnet_id': share_subnet
|
||||||
|
},
|
||||||
|
share_network_subnets.RESOURCE_NAME)
|
||||||
|
|
||||||
|
def test_delete(self):
|
||||||
|
share_network = 'fake_share_network'
|
||||||
|
share_subnet = 'fake_share_subnet'
|
||||||
|
|
||||||
|
with mock.patch.object(self.manager, '_delete', mock.Mock()):
|
||||||
|
self.manager.delete(share_network, share_subnet)
|
||||||
|
|
||||||
|
self.manager._delete.assert_called_once_with(
|
||||||
|
share_network_subnets.RESOURCE_PATH % {
|
||||||
|
'share_network_id': share_network,
|
||||||
|
'share_network_subnet_id': share_subnet
|
||||||
|
})
|
@ -42,14 +42,6 @@ class ShareReplicasTest(utils.TestCase):
|
|||||||
}
|
}
|
||||||
self._create_common(values)
|
self._create_common(values)
|
||||||
|
|
||||||
def test_create_with_share_network(self):
|
|
||||||
values = {
|
|
||||||
'availability_zone': 'az1',
|
|
||||||
'share': 's1',
|
|
||||||
'share_network': 'sn1',
|
|
||||||
}
|
|
||||||
self._create_common(values)
|
|
||||||
|
|
||||||
def _create_common(self, values):
|
def _create_common(self, values):
|
||||||
|
|
||||||
with mock.patch.object(self.manager, '_create', fakes.fake_create):
|
with mock.patch.object(self.manager, '_create', fakes.fake_create):
|
||||||
|
@ -87,6 +87,7 @@ class ShareServerManagerTest(utils.TestCase):
|
|||||||
def test_manage(self, driver_options):
|
def test_manage(self, driver_options):
|
||||||
host = 'fake_host'
|
host = 'fake_host'
|
||||||
share_network_id = 'fake_share_net_id'
|
share_network_id = 'fake_share_net_id'
|
||||||
|
share_network_subnet_id = 'fake_share_network_subnet_id'
|
||||||
identifier = 'ff-aa-kk-ee-00'
|
identifier = 'ff-aa-kk-ee-00'
|
||||||
if driver_options is None:
|
if driver_options is None:
|
||||||
driver_options = {}
|
driver_options = {}
|
||||||
@ -94,12 +95,15 @@ class ShareServerManagerTest(utils.TestCase):
|
|||||||
'host': host,
|
'host': host,
|
||||||
'share_network_id': share_network_id,
|
'share_network_id': share_network_id,
|
||||||
'identifier': identifier,
|
'identifier': identifier,
|
||||||
'driver_options': driver_options
|
'driver_options': driver_options,
|
||||||
|
'share_network_subnet_id': share_network_subnet_id,
|
||||||
}
|
}
|
||||||
with mock.patch.object(self.manager, '_create',
|
with mock.patch.object(self.manager, '_create',
|
||||||
mock.Mock(return_value='fake')):
|
mock.Mock(return_value='fake')):
|
||||||
result = self.manager.manage(host, share_network_id, identifier,
|
result = self.manager.manage(
|
||||||
driver_options)
|
host, share_network_id, identifier,
|
||||||
|
driver_options=driver_options,
|
||||||
|
share_network_subnet_id=share_network_subnet_id)
|
||||||
self.manager._create.assert_called_once_with(
|
self.manager._create.assert_called_once_with(
|
||||||
share_servers.RESOURCES_PATH + '/manage',
|
share_servers.RESOURCES_PATH + '/manage',
|
||||||
{'share_server': expected_body}, 'share_server'
|
{'share_server': expected_body}, 'share_server'
|
||||||
|
@ -35,6 +35,7 @@ from manilaclient import utils
|
|||||||
from manilaclient.v2 import messages
|
from manilaclient.v2 import messages
|
||||||
from manilaclient.v2 import security_services
|
from manilaclient.v2 import security_services
|
||||||
from manilaclient.v2 import share_instances
|
from manilaclient.v2 import share_instances
|
||||||
|
from manilaclient.v2 import share_network_subnets
|
||||||
from manilaclient.v2 import share_networks
|
from manilaclient.v2 import share_networks
|
||||||
from manilaclient.v2 import share_servers
|
from manilaclient.v2 import share_servers
|
||||||
from manilaclient.v2 import share_snapshots
|
from manilaclient.v2 import share_snapshots
|
||||||
@ -734,36 +735,96 @@ class ShellTest(test_utils.TestCase):
|
|||||||
+ ' --share_type fake_share_type'
|
+ ' --share_type fake_share_type'
|
||||||
+ ' --share_server_id fake_server')
|
+ ' --share_server_id fake_server')
|
||||||
|
|
||||||
|
def test_share_server_manage_unsupported_version(self):
|
||||||
|
self.assertRaises(
|
||||||
|
exceptions.UnsupportedVersion,
|
||||||
|
self.run_command,
|
||||||
|
'--os-share-api-version 2.48 ' +
|
||||||
|
'share-server-manage fake_host fake_share_net_id fake_id')
|
||||||
|
|
||||||
|
def test_share_server_manage_invalid_param_subnet_id(self):
|
||||||
|
self.assertRaises(
|
||||||
|
exceptions.CommandError,
|
||||||
|
self.run_command,
|
||||||
|
'--os-share-api-version 2.49 ' +
|
||||||
|
'share-server-manage fake_host fake_share_net_id fake_id ' +
|
||||||
|
'--share-network-subnet fake_subnet_id')
|
||||||
|
|
||||||
@ddt.data({'driver_args': '--driver_options opt1=opt1 opt2=opt2',
|
@ddt.data({'driver_args': '--driver_options opt1=opt1 opt2=opt2',
|
||||||
'valid_params': {
|
'valid_params': {
|
||||||
'driver_options': {'opt1': 'opt1', 'opt2': 'opt2'},
|
'driver_options': {'opt1': 'opt1', 'opt2': 'opt2'},
|
||||||
},
|
}},
|
||||||
'version': '--os-share-api-version 2.49',
|
{'driver_args': '--driver_options opt1=opt1 opt2=opt2',
|
||||||
},
|
'subnet_id': 'fake_subnet_1',
|
||||||
|
'valid_params': {
|
||||||
|
'driver_options': {'opt1': 'opt1', 'opt2': 'opt2'},
|
||||||
|
}},
|
||||||
{'driver_args': '--driver_options opt1=opt1 opt2=opt2',
|
{'driver_args': '--driver_options opt1=opt1 opt2=opt2',
|
||||||
'valid_params': {
|
'valid_params': {
|
||||||
'driver_options': {'opt1': 'opt1', 'opt2': 'opt2'},
|
'driver_options': {'opt1': 'opt1', 'opt2': 'opt2'},
|
||||||
},
|
},
|
||||||
|
'version': '2.51',
|
||||||
|
},
|
||||||
|
{'driver_args': '--driver_options opt1=opt1 opt2=opt2',
|
||||||
|
'subnet_id': 'fake_subnet_1',
|
||||||
|
'valid_params': {
|
||||||
|
'driver_options': {'opt1': 'opt1', 'opt2': 'opt2'},
|
||||||
|
},
|
||||||
|
'version': '2.51',
|
||||||
},
|
},
|
||||||
{'driver_args': "",
|
{'driver_args': "",
|
||||||
'valid_params': {
|
'valid_params': {
|
||||||
'driver_options': {}
|
'driver_options': {}
|
||||||
},
|
},
|
||||||
'version': '--os-share-api-version 2.49',
|
'version': '2.51',
|
||||||
})
|
},
|
||||||
|
{'driver_args': '--driver_options opt1=opt1 opt2=opt2',
|
||||||
|
'valid_params': {
|
||||||
|
'driver_options': {'opt1': 'opt1', 'opt2': 'opt2'},
|
||||||
|
},
|
||||||
|
'version': '2.49',
|
||||||
|
},
|
||||||
|
{'driver_args': '',
|
||||||
|
'valid_params': {
|
||||||
|
'driver_options': {},
|
||||||
|
},
|
||||||
|
'network_id': 'fake_network_id',
|
||||||
|
'version': '2.49',
|
||||||
|
},
|
||||||
|
{'driver_args': "",
|
||||||
|
'valid_params': {
|
||||||
|
'driver_options': {}
|
||||||
|
},
|
||||||
|
'version': '2.49',
|
||||||
|
},
|
||||||
|
)
|
||||||
@ddt.unpack
|
@ddt.unpack
|
||||||
def test_share_server_manage(self, driver_args, valid_params,
|
def test_share_server_manage(self, driver_args, valid_params,
|
||||||
version=None):
|
version=None, network_id=None,
|
||||||
|
subnet_id=None):
|
||||||
|
subnet_support = (version is None or
|
||||||
|
api_versions.APIVersion(version) >=
|
||||||
|
api_versions.APIVersion('2.51'))
|
||||||
|
|
||||||
|
network_id = '3456' if network_id is None else network_id
|
||||||
fake_share_network = type(
|
fake_share_network = type(
|
||||||
'FakeShareNetwork', (object,), {'id': '3456'})
|
'FakeShareNetwork', (object,), {'id': network_id})
|
||||||
self.mock_object(
|
self.mock_object(
|
||||||
shell_v2, '_find_share_network',
|
shell_v2, '_find_share_network',
|
||||||
mock.Mock(return_value=fake_share_network))
|
mock.Mock(return_value=fake_share_network))
|
||||||
command = "" if version is None else version
|
command = ('share-server-manage '
|
||||||
command += (' share-server-manage fake_host fake_share_net_id '
|
'%(host)s '
|
||||||
+ ' 88-as-23-f3-45 ' + driver_args)
|
'%(share_network_id)s '
|
||||||
|
'%(identifier)s '
|
||||||
|
'%(driver_args)s ' % {
|
||||||
|
'host': 'fake_host',
|
||||||
|
'share_network_id': fake_share_network.id,
|
||||||
|
'identifier': '88-as-23-f3-45',
|
||||||
|
'driver_args': driver_args,
|
||||||
|
})
|
||||||
|
command += '--share-network-subnet %s' % subnet_id if subnet_id else ''
|
||||||
|
|
||||||
self.run_command(command)
|
self.run_command(command, version=version)
|
||||||
|
|
||||||
expected = {
|
expected = {
|
||||||
'share_server': {
|
'share_server': {
|
||||||
@ -773,6 +834,8 @@ class ShellTest(test_utils.TestCase):
|
|||||||
'driver_options': driver_args
|
'driver_options': driver_args
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if subnet_support:
|
||||||
|
expected['share_server']['share_network_subnet_id'] = subnet_id
|
||||||
expected['share_server'].update(valid_params)
|
expected['share_server'].update(valid_params)
|
||||||
|
|
||||||
self.assert_called('POST', '/share-servers/manage', body=expected)
|
self.assert_called('POST', '/share-servers/manage', body=expected)
|
||||||
@ -1425,25 +1488,39 @@ class ShellTest(test_utils.TestCase):
|
|||||||
|
|
||||||
self.assert_called('POST', '/share-networks')
|
self.assert_called('POST', '/share-networks')
|
||||||
|
|
||||||
|
@ddt.unpack
|
||||||
@ddt.data(
|
@ddt.data(
|
||||||
{'--name': 'fake_name'},
|
{'data': {'--name': 'fake_name'}},
|
||||||
{'--description': 'fake_description'},
|
{'data': {'--description': 'fake_description'}},
|
||||||
{'--neutron_net_id': 'fake_neutron_net_id'},
|
{'data': {'--neutron_net_id': 'fake_neutron_net_id'},
|
||||||
{'--neutron_subnet_id': 'fake_neutron_subnet_id'},
|
'version': '2.49',
|
||||||
{'--description': 'fake_description',
|
},
|
||||||
|
{'data': {'--neutron_subnet_id': 'fake_neutron_subnet_id'},
|
||||||
|
'version': '2.49',
|
||||||
|
},
|
||||||
|
{'data': {
|
||||||
|
'--description': 'fake_description',
|
||||||
'--name': 'fake_name',
|
'--name': 'fake_name',
|
||||||
'--neutron_net_id': 'fake_neutron_net_id',
|
'--neutron_net_id': 'fake_neutron_net_id',
|
||||||
'--neutron_subnet_id': 'fake_neutron_subnet_id'},
|
'--neutron_subnet_id': 'fake_neutron_subnet_id'},
|
||||||
{'--name': '""'},
|
'version': '2.49',
|
||||||
{'--description': '""'},
|
},
|
||||||
{'--neutron_net_id': '""'},
|
{'data': {'--name': '""'}},
|
||||||
{'--neutron_subnet_id': '""'},
|
{'data': {'--description': '""'}},
|
||||||
{'--description': '""',
|
{'data': {'--neutron_net_id': '""'},
|
||||||
|
'version': '2.49',
|
||||||
|
},
|
||||||
|
{'data': {'--neutron_subnet_id': '""'},
|
||||||
|
'version': '2.49',
|
||||||
|
},
|
||||||
|
{'data': {
|
||||||
|
'--description': '""',
|
||||||
'--name': '""',
|
'--name': '""',
|
||||||
'--neutron_net_id': '""',
|
'--neutron_net_id': '""',
|
||||||
'--neutron_subnet_id': '""',
|
'--neutron_subnet_id': '""'},
|
||||||
},)
|
'version': '2.49',
|
||||||
def test_share_network_update(self, data):
|
})
|
||||||
|
def test_share_network_update(self, data, version=None):
|
||||||
cmd = 'share-network-update 1111'
|
cmd = 'share-network-update 1111'
|
||||||
expected = dict()
|
expected = dict()
|
||||||
for k, v in data.items():
|
for k, v in data.items():
|
||||||
@ -1451,7 +1528,7 @@ class ShellTest(test_utils.TestCase):
|
|||||||
expected[k[2:]] = v
|
expected[k[2:]] = v
|
||||||
expected = dict(share_network=expected)
|
expected = dict(share_network=expected)
|
||||||
|
|
||||||
self.run_command(cmd)
|
self.run_command(cmd, version=version)
|
||||||
|
|
||||||
self.assert_called('PUT', '/share-networks/1111', body=expected)
|
self.assert_called('PUT', '/share-networks/1111', body=expected)
|
||||||
|
|
||||||
@ -1723,6 +1800,143 @@ class ShellTest(test_utils.TestCase):
|
|||||||
'/security-services/detail?share_network_id=1111',
|
'/security-services/detail?share_network_id=1111',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ddt.data(
|
||||||
|
{},
|
||||||
|
{'--neutron_net_id': 'fake_neutron_net_id',
|
||||||
|
'--neutron_subnet_id': 'fake_neutron_subnet_id'},
|
||||||
|
{'--availability-zone': 'fake_availability_zone_id'},
|
||||||
|
{'--neutron_net_id': 'fake_neutron_net_id',
|
||||||
|
'--neutron_subnet_id': 'fake_neutron_subnet_id',
|
||||||
|
'--availability-zone': 'fake_availability_zone_id'})
|
||||||
|
def test_share_network_subnet_add(self, data):
|
||||||
|
fake_share_network = type(
|
||||||
|
'FakeShareNetwork', (object,), {'id': '1234'})
|
||||||
|
self.mock_object(
|
||||||
|
shell_v2, '_find_share_network',
|
||||||
|
mock.Mock(return_value=fake_share_network))
|
||||||
|
|
||||||
|
cmd = 'share-network-subnet-create'
|
||||||
|
for k, v in data.items():
|
||||||
|
cmd += ' ' + k + ' ' + v
|
||||||
|
cmd += ' ' + fake_share_network.id
|
||||||
|
self.run_command(cmd)
|
||||||
|
|
||||||
|
shell_v2._find_share_network.assert_called_once_with(
|
||||||
|
mock.ANY, fake_share_network.id)
|
||||||
|
self.assert_called('POST', '/share-networks/1234/subnets')
|
||||||
|
|
||||||
|
@ddt.data(
|
||||||
|
{'--neutron_net_id': 'fake_neutron_net_id'},
|
||||||
|
{'--neutron_subnet_id': 'fake_neutron_subnet_id'},
|
||||||
|
{'--neutron_net_id': 'fake_neutron_net_id',
|
||||||
|
'--availability-zone': 'fake_availability_zone_id'},
|
||||||
|
{'--neutron_subnet_id': 'fake_neutron_subnet_id',
|
||||||
|
'--availability-zone': 'fake_availability_zone_id'})
|
||||||
|
def test_share_network_subnet_add_invalid_param(self, data):
|
||||||
|
cmd = 'share-network-subnet-create'
|
||||||
|
for k, v in data.items():
|
||||||
|
cmd += ' ' + k + ' ' + v
|
||||||
|
cmd += ' fake_network_id'
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
exceptions.CommandError,
|
||||||
|
self.run_command,
|
||||||
|
cmd)
|
||||||
|
|
||||||
|
def test_share_network_subnet_add_invalid_share_network(self):
|
||||||
|
cmd = 'share-network-subnet-create not-found-id'
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
exceptions.CommandError,
|
||||||
|
self.run_command,
|
||||||
|
cmd)
|
||||||
|
|
||||||
|
@ddt.data(('fake_subnet1', ),
|
||||||
|
('fake_subnet1', 'fake_subnet2'))
|
||||||
|
def test_share_network_subnet_delete(self, subnet_ids):
|
||||||
|
fake_share_network = type(
|
||||||
|
'FakeShareNetwork', (object,), {'id': '1234'})
|
||||||
|
self.mock_object(
|
||||||
|
shell_v2, '_find_share_network',
|
||||||
|
mock.Mock(return_value=fake_share_network))
|
||||||
|
fake_share_network_subnets = [
|
||||||
|
share_network_subnets.ShareNetworkSubnet(
|
||||||
|
'fake', {'id': subnet_id}, True)
|
||||||
|
for subnet_id in subnet_ids
|
||||||
|
]
|
||||||
|
|
||||||
|
self.run_command(
|
||||||
|
'share-network-subnet-delete %(network_id)s %(subnet_ids)s' % {
|
||||||
|
'network_id': fake_share_network.id,
|
||||||
|
'subnet_ids': ' '.join(subnet_ids)
|
||||||
|
})
|
||||||
|
|
||||||
|
shell_v2._find_share_network.assert_called_once_with(
|
||||||
|
mock.ANY, fake_share_network.id)
|
||||||
|
for subnet in fake_share_network_subnets:
|
||||||
|
self.assert_called_anytime(
|
||||||
|
'DELETE', '/share-networks/1234/subnets/%s' % subnet.id,
|
||||||
|
clear_callstack=False)
|
||||||
|
|
||||||
|
def test_share_network_subnet_delete_invalid_share_network(self):
|
||||||
|
command = 'share-network-subnet-delete %(net_id)s %(subnet_id)s' % {
|
||||||
|
'net_id': 'not-found-id',
|
||||||
|
'subnet_id': '1234',
|
||||||
|
}
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
exceptions.CommandError,
|
||||||
|
self.run_command,
|
||||||
|
command)
|
||||||
|
|
||||||
|
def test_share_network_subnet_delete_invalid_share_network_subnet(self):
|
||||||
|
fake_share_network = type(
|
||||||
|
'FakeShareNetwork', (object,), {'id': '1234'})
|
||||||
|
self.mock_object(
|
||||||
|
shell_v2, '_find_share_network',
|
||||||
|
mock.Mock(return_value=fake_share_network))
|
||||||
|
command = 'share-network-subnet-delete %(net_id)s %(subnet_id)s' % {
|
||||||
|
'net_id': fake_share_network.id,
|
||||||
|
'subnet_id': 'not-found-id',
|
||||||
|
}
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
exceptions.CommandError,
|
||||||
|
self.run_command,
|
||||||
|
command)
|
||||||
|
|
||||||
|
@mock.patch.object(cliutils, 'print_dict', mock.Mock())
|
||||||
|
def test_share_network_subnet_show(self):
|
||||||
|
fake_share_network = type(
|
||||||
|
'FakeShareNetwork', (object,), {'id': '1234'})
|
||||||
|
self.mock_object(
|
||||||
|
shell_v2, '_find_share_network',
|
||||||
|
mock.Mock(return_value=fake_share_network))
|
||||||
|
args = {
|
||||||
|
'share_net_id': fake_share_network.id,
|
||||||
|
'subnet_id': 'fake_subnet_id',
|
||||||
|
}
|
||||||
|
|
||||||
|
self.run_command(
|
||||||
|
'share-network-subnet-show %(share_net_id)s %(subnet_id)s' % args)
|
||||||
|
|
||||||
|
self.assert_called(
|
||||||
|
'GET',
|
||||||
|
'/share-networks/%(share_net_id)s/subnets/%(subnet_id)s' % args,
|
||||||
|
)
|
||||||
|
cliutils.print_dict.assert_called_once_with(mock.ANY)
|
||||||
|
|
||||||
|
def test_share_network_subnet_show_invalid_share_network(self):
|
||||||
|
command = 'share-network-subnet-show %(net_id)s %(subnet_id)s' % {
|
||||||
|
'net_id': 'not-found-id',
|
||||||
|
'subnet_id': 1234,
|
||||||
|
}
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
exceptions.CommandError,
|
||||||
|
self.run_command,
|
||||||
|
command)
|
||||||
|
|
||||||
@mock.patch.object(cliutils, 'print_list', mock.Mock())
|
@mock.patch.object(cliutils, 'print_list', mock.Mock())
|
||||||
def test_share_server_list_select_column(self):
|
def test_share_server_list_select_column(self):
|
||||||
self.run_command('share-server-list --columns id,host,status')
|
self.run_command('share-server-list --columns id,host,status')
|
||||||
@ -2848,19 +3062,14 @@ class ShellTest(test_utils.TestCase):
|
|||||||
|
|
||||||
@ddt.data(
|
@ddt.data(
|
||||||
'fake-share-id --az fake-az',
|
'fake-share-id --az fake-az',
|
||||||
'fake-share-id --availability-zone fake-az --share-network '
|
'fake-share-id --availability-zone fake-az',
|
||||||
'fake-network',
|
|
||||||
)
|
)
|
||||||
@mock.patch.object(shell_v2, '_find_share_network', mock.Mock())
|
|
||||||
@mock.patch.object(shell_v2, '_find_share', mock.Mock())
|
@mock.patch.object(shell_v2, '_find_share', mock.Mock())
|
||||||
def test_share_replica_create(self, data):
|
def test_share_replica_create(self, data):
|
||||||
|
|
||||||
fshare = type('FakeShare', (object,), {'id': 'fake-share-id'})
|
fshare = type('FakeShare', (object,), {'id': 'fake-share-id'})
|
||||||
shell_v2._find_share.return_value = fshare
|
shell_v2._find_share.return_value = fshare
|
||||||
|
|
||||||
fnetwork = type('FakeShareNetwork', (object,), {'id': 'fake-network'})
|
|
||||||
shell_v2._find_share_network.return_value = fnetwork
|
|
||||||
|
|
||||||
cmd = 'share-replica-create' + ' ' + data
|
cmd = 'share-replica-create' + ' ' + data
|
||||||
|
|
||||||
self.run_command(cmd)
|
self.run_command(cmd)
|
||||||
|
@ -36,6 +36,7 @@ from manilaclient.v2 import share_group_types
|
|||||||
from manilaclient.v2 import share_groups
|
from manilaclient.v2 import share_groups
|
||||||
from manilaclient.v2 import share_instance_export_locations
|
from manilaclient.v2 import share_instance_export_locations
|
||||||
from manilaclient.v2 import share_instances
|
from manilaclient.v2 import share_instances
|
||||||
|
from manilaclient.v2 import share_network_subnets
|
||||||
from manilaclient.v2 import share_networks
|
from manilaclient.v2 import share_networks
|
||||||
from manilaclient.v2 import share_replica_export_locations
|
from manilaclient.v2 import share_replica_export_locations
|
||||||
from manilaclient.v2 import share_replicas
|
from manilaclient.v2 import share_replicas
|
||||||
@ -207,6 +208,8 @@ class Client(object):
|
|||||||
self.services = services.ServiceManager(self)
|
self.services = services.ServiceManager(self)
|
||||||
self.security_services = security_services.SecurityServiceManager(self)
|
self.security_services = security_services.SecurityServiceManager(self)
|
||||||
self.share_networks = share_networks.ShareNetworkManager(self)
|
self.share_networks = share_networks.ShareNetworkManager(self)
|
||||||
|
self.share_network_subnets = (
|
||||||
|
share_network_subnets.ShareNetworkSubnetManager(self))
|
||||||
|
|
||||||
self.quota_classes = quota_classes.QuotaClassSetManager(self)
|
self.quota_classes = quota_classes.QuotaClassSetManager(self)
|
||||||
self.quotas = quotas.QuotaSetManager(self)
|
self.quotas = quotas.QuotaSetManager(self)
|
||||||
|
92
manilaclient/v2/share_network_subnets.py
Normal file
92
manilaclient/v2/share_network_subnets.py
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
# Copyright 2019 NetApp
|
||||||
|
# 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 manilaclient import base
|
||||||
|
from manilaclient.common.apiclient import base as common_base
|
||||||
|
|
||||||
|
RESOURCES_PATH = '/share-networks/%(share_network_id)s/subnets'
|
||||||
|
RESOURCE_PATH = RESOURCES_PATH + '/%(share_network_subnet_id)s'
|
||||||
|
RESOURCE_NAME = 'share_network_subnet'
|
||||||
|
|
||||||
|
|
||||||
|
class ShareNetworkSubnet(common_base.Resource):
|
||||||
|
"""Network subnet info for Manila share networks."""
|
||||||
|
def __repr__(self):
|
||||||
|
return "<ShareNetworkSubnet: %s>" % self.id
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
return self._info[key]
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
"""Delete this share network subnet."""
|
||||||
|
self.manager.delete(self)
|
||||||
|
|
||||||
|
|
||||||
|
class ShareNetworkSubnetManager(base.ManagerWithFind):
|
||||||
|
"""Manage :class:`ShareNetworkSubnet` resources."""
|
||||||
|
|
||||||
|
resource_class = ShareNetworkSubnet
|
||||||
|
|
||||||
|
def create(self, neutron_net_id=None, neutron_subnet_id=None,
|
||||||
|
availability_zone=None, share_network_id=None):
|
||||||
|
"""Create share network subnet.
|
||||||
|
|
||||||
|
:param neutron_net_id: ID of Neutron network
|
||||||
|
:param neutron_subnet_id: ID of Neutron subnet
|
||||||
|
:param availability_zone: Name of the target availability zone
|
||||||
|
:rtype: :class:`ShareNetworkSubnet`
|
||||||
|
"""
|
||||||
|
values = {}
|
||||||
|
if neutron_net_id:
|
||||||
|
values['neutron_net_id'] = neutron_net_id
|
||||||
|
if neutron_subnet_id:
|
||||||
|
values['neutron_subnet_id'] = neutron_subnet_id
|
||||||
|
if availability_zone:
|
||||||
|
values['availability_zone'] = availability_zone
|
||||||
|
|
||||||
|
body = {'share-network-subnet': values}
|
||||||
|
url = '/share-networks/%(share_network_id)s/subnets' % {
|
||||||
|
'share_network_id': share_network_id
|
||||||
|
}
|
||||||
|
|
||||||
|
return self._create(url, body, RESOURCE_NAME)
|
||||||
|
|
||||||
|
def get(self, share_network, share_network_subnet):
|
||||||
|
"""Get a share network subnet.
|
||||||
|
|
||||||
|
:param policy: share network subnet to get.
|
||||||
|
:rtype: :class:`NetworkSubnetInfo`
|
||||||
|
"""
|
||||||
|
share_network_id = common_base.getid(share_network)
|
||||||
|
share_network_subnet_id = common_base.getid(share_network_subnet)
|
||||||
|
url = ('/share-networks/%(share_network_id)s/subnets'
|
||||||
|
'/%(share_network_subnet)s') % {
|
||||||
|
'share_network_id': share_network_id,
|
||||||
|
'share_network_subnet': share_network_subnet_id
|
||||||
|
}
|
||||||
|
return self._get(url, "share_network_subnet")
|
||||||
|
|
||||||
|
def delete(self, share_network, share_network_subnet):
|
||||||
|
"""Delete a share network subnet.
|
||||||
|
|
||||||
|
:param share_network: share network that owns the subnet.
|
||||||
|
:param share_network_subnet: share network subnet to be deleted.
|
||||||
|
"""
|
||||||
|
url = ('/share-networks/%(share_network_id)s/subnets'
|
||||||
|
'/%(share_network_subnet)s') % {
|
||||||
|
'share_network_id': common_base.getid(share_network),
|
||||||
|
'share_network_subnet': share_network_subnet
|
||||||
|
}
|
||||||
|
self._delete(url)
|
@ -70,7 +70,7 @@ class ShareNetworkManager(base.ManagerWithFind):
|
|||||||
|
|
||||||
return self._create(RESOURCES_PATH, body, RESOURCE_NAME)
|
return self._create(RESOURCES_PATH, body, RESOURCE_NAME)
|
||||||
|
|
||||||
@api_versions.wraps("2.26") # noqa
|
@api_versions.wraps("2.26", "2.50") # noqa
|
||||||
def create(self, neutron_net_id=None, neutron_subnet_id=None,
|
def create(self, neutron_net_id=None, neutron_subnet_id=None,
|
||||||
name=None, description=None):
|
name=None, description=None):
|
||||||
"""Create share network.
|
"""Create share network.
|
||||||
@ -95,6 +95,26 @@ class ShareNetworkManager(base.ManagerWithFind):
|
|||||||
|
|
||||||
return self._create(RESOURCES_PATH, body, RESOURCE_NAME)
|
return self._create(RESOURCES_PATH, body, RESOURCE_NAME)
|
||||||
|
|
||||||
|
@api_versions.wraps("2.51") # noqa
|
||||||
|
def create(self, neutron_net_id=None, neutron_subnet_id=None,
|
||||||
|
name=None, description=None, availability_zone=None):
|
||||||
|
values = {}
|
||||||
|
|
||||||
|
if neutron_net_id:
|
||||||
|
values['neutron_net_id'] = neutron_net_id
|
||||||
|
if neutron_subnet_id:
|
||||||
|
values['neutron_subnet_id'] = neutron_subnet_id
|
||||||
|
if name:
|
||||||
|
values['name'] = name
|
||||||
|
if description:
|
||||||
|
values['description'] = description
|
||||||
|
if availability_zone:
|
||||||
|
values['availability_zone'] = availability_zone
|
||||||
|
|
||||||
|
body = {RESOURCE_NAME: values}
|
||||||
|
|
||||||
|
return self._create(RESOURCES_PATH, body, RESOURCE_NAME)
|
||||||
|
|
||||||
def add_security_service(self, share_network, security_service):
|
def add_security_service(self, share_network, security_service):
|
||||||
"""Associate given security service with a share network.
|
"""Associate given security service with a share network.
|
||||||
|
|
||||||
|
@ -89,13 +89,12 @@ class ShareReplicaManager(base.ManagerWithFind):
|
|||||||
|
|
||||||
@api_versions.wraps("2.11")
|
@api_versions.wraps("2.11")
|
||||||
@api_versions.experimental_api
|
@api_versions.experimental_api
|
||||||
def create(self, share, availability_zone=None, share_network=None):
|
def create(self, share, availability_zone=None):
|
||||||
"""Create a replica for a share.
|
"""Create a replica for a share.
|
||||||
|
|
||||||
:param share: The share to create the replica of. Can be the share
|
:param share: The share to create the replica of. Can be the share
|
||||||
object or its UUID.
|
object or its UUID.
|
||||||
:param availability_zone: The 'availability_zone' object or its UUID.
|
:param availability_zone: The 'availability_zone' object or its UUID.
|
||||||
:param share_network: either share network object or its UUID.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
share_id = common_base.getid(share)
|
share_id = common_base.getid(share)
|
||||||
@ -104,9 +103,6 @@ class ShareReplicaManager(base.ManagerWithFind):
|
|||||||
if availability_zone:
|
if availability_zone:
|
||||||
body['availability_zone'] = common_base.getid(availability_zone)
|
body['availability_zone'] = common_base.getid(availability_zone)
|
||||||
|
|
||||||
if share_network:
|
|
||||||
body['share_network'] = common_base.getid(share_network)
|
|
||||||
|
|
||||||
return self._create(RESOURCES_PATH,
|
return self._create(RESOURCES_PATH,
|
||||||
{RESOURCE_NAME: body},
|
{RESOURCE_NAME: body},
|
||||||
RESOURCE_NAME)
|
RESOURCE_NAME)
|
||||||
|
@ -97,7 +97,7 @@ class ShareServerManager(base.ManagerWithFind):
|
|||||||
query_string = self._build_query_string(search_opts)
|
query_string = self._build_query_string(search_opts)
|
||||||
return self._list(RESOURCES_PATH + query_string, RESOURCES_NAME)
|
return self._list(RESOURCES_PATH + query_string, RESOURCES_NAME)
|
||||||
|
|
||||||
@api_versions.wraps("2.49")
|
@api_versions.wraps("2.49", "2.50")
|
||||||
def manage(self, host, share_network_id, identifier, driver_options=None):
|
def manage(self, host, share_network_id, identifier, driver_options=None):
|
||||||
|
|
||||||
driver_options = driver_options or {}
|
driver_options = driver_options or {}
|
||||||
@ -112,6 +112,23 @@ class ShareServerManager(base.ManagerWithFind):
|
|||||||
return self._create(resource_path, {'share_server': body},
|
return self._create(resource_path, {'share_server': body},
|
||||||
'share_server')
|
'share_server')
|
||||||
|
|
||||||
|
@api_versions.wraps("2.51") # noqa
|
||||||
|
def manage(self, host, share_network_id, identifier,
|
||||||
|
share_network_subnet_id=None, driver_options=None):
|
||||||
|
|
||||||
|
driver_options = driver_options or {}
|
||||||
|
body = {
|
||||||
|
'host': host,
|
||||||
|
'share_network_id': share_network_id,
|
||||||
|
'identifier': identifier,
|
||||||
|
'share_network_subnet_id': share_network_subnet_id,
|
||||||
|
'driver_options': driver_options,
|
||||||
|
}
|
||||||
|
|
||||||
|
resource_path = RESOURCE_PATH % 'manage'
|
||||||
|
return self._create(resource_path, {'share_server': body},
|
||||||
|
'share_server')
|
||||||
|
|
||||||
@api_versions.wraps("2.49")
|
@api_versions.wraps("2.49")
|
||||||
def unmanage(self, share_server, force=False):
|
def unmanage(self, share_server, force=False):
|
||||||
return self._action("unmanage", share_server, {'force': force})
|
return self._action("unmanage", share_server, {'force': force})
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
|
|
||||||
|
from operator import xor
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
@ -1178,15 +1179,32 @@ def do_manage(cs, args):
|
|||||||
help='One or more driver-specific key=value pairs that may be necessary to'
|
help='One or more driver-specific key=value pairs that may be necessary to'
|
||||||
' manage the share server (Optional, Default=None).',
|
' manage the share server (Optional, Default=None).',
|
||||||
default=None)
|
default=None)
|
||||||
|
@cliutils.arg(
|
||||||
|
'--share-network-subnet', '--share_network_subnet',
|
||||||
|
type=str,
|
||||||
|
metavar='<share_network_subnet>',
|
||||||
|
help="Share network subnet where share server has network allocations in. "
|
||||||
|
"The default subnet will be used if it's not specified. Available "
|
||||||
|
"for microversion >= 2.51 (Optional, Default=None).",
|
||||||
|
default=None)
|
||||||
def do_share_server_manage(cs, args):
|
def do_share_server_manage(cs, args):
|
||||||
"""Manage share server not handled by Manila (Admin only)."""
|
"""Manage share server not handled by Manila (Admin only)."""
|
||||||
driver_options = _extract_key_value_options(args, 'driver_options')
|
driver_options = _extract_key_value_options(args, 'driver_options')
|
||||||
|
|
||||||
share_network = _find_share_network(cs, args.share_network)
|
manage_kwargs = {
|
||||||
|
'driver_options': driver_options,
|
||||||
|
}
|
||||||
|
if cs.api_version < api_versions.APIVersion("2.51"):
|
||||||
|
if getattr(args, 'share_network_subnet'):
|
||||||
|
raise exceptions.CommandError(
|
||||||
|
"Share network subnet option is only available with manila "
|
||||||
|
"API version >= 2.51")
|
||||||
|
else:
|
||||||
|
manage_kwargs['share_network_subnet_id'] = args.share_network_subnet
|
||||||
|
|
||||||
share_server = cs.share_servers.manage(
|
share_server = cs.share_servers.manage(
|
||||||
args.host, share_network.id, args.identifier,
|
args.host, args.share_network, args.identifier,
|
||||||
driver_options=driver_options)
|
**manage_kwargs)
|
||||||
|
|
||||||
cliutils.print_dict(share_server._info)
|
cliutils.print_dict(share_server._info)
|
||||||
|
|
||||||
@ -2693,6 +2711,16 @@ def do_share_network_create(cs, args):
|
|||||||
metavar='<description>',
|
metavar='<description>',
|
||||||
default=None,
|
default=None,
|
||||||
help="Share network description.")
|
help="Share network description.")
|
||||||
|
@cliutils.arg(
|
||||||
|
'--availability-zone', '--availability_zone', '--az',
|
||||||
|
metavar='<availability_zone>',
|
||||||
|
default=None,
|
||||||
|
action='single_alias',
|
||||||
|
help="Availability zone in which the subnet should be created. Share "
|
||||||
|
"networks can have one or more subnets in different availability "
|
||||||
|
"zones when the driver is operating with "
|
||||||
|
"'driver_handles_share_servers' extra_spec set to True. Available "
|
||||||
|
"only for microversion >= 2.51. (Default=None)")
|
||||||
def do_share_network_create(cs, args):
|
def do_share_network_create(cs, args):
|
||||||
"""Create description for network used by the tenant."""
|
"""Create description for network used by the tenant."""
|
||||||
values = {
|
values = {
|
||||||
@ -2701,6 +2729,12 @@ def do_share_network_create(cs, args):
|
|||||||
'name': args.name,
|
'name': args.name,
|
||||||
'description': args.description,
|
'description': args.description,
|
||||||
}
|
}
|
||||||
|
if cs.api_version >= api_versions.APIVersion("2.51"):
|
||||||
|
values['availability_zone'] = args.availability_zone
|
||||||
|
elif args.availability_zone:
|
||||||
|
raise exceptions.CommandError(
|
||||||
|
"Creating share networks with a given az is only "
|
||||||
|
"available with manila API version >= 2.51")
|
||||||
share_network = cs.share_networks.create(**values)
|
share_network = cs.share_networks.create(**values)
|
||||||
info = share_network._info.copy()
|
info = share_network._info.copy()
|
||||||
cliutils.print_dict(info)
|
cliutils.print_dict(info)
|
||||||
@ -2771,9 +2805,8 @@ def do_share_network_update(cs, args):
|
|||||||
metavar='<neutron-net-id>',
|
metavar='<neutron-net-id>',
|
||||||
default=None,
|
default=None,
|
||||||
action='single_alias',
|
action='single_alias',
|
||||||
help="Neutron network ID. Used to set up network for share servers. This "
|
help="Neutron network ID. Used to set up network for share servers. "
|
||||||
"option is deprecated and will be rejected in newer releases of "
|
"This option is deprecated for microversion >= 2.51.")
|
||||||
"OpenStack Manila.")
|
|
||||||
@cliutils.arg(
|
@cliutils.arg(
|
||||||
'--neutron-subnet-id',
|
'--neutron-subnet-id',
|
||||||
'--neutron-subnet_id', '--neutron_subnet_id', '--neutron_subnet-id',
|
'--neutron-subnet_id', '--neutron_subnet_id', '--neutron_subnet-id',
|
||||||
@ -2781,7 +2814,8 @@ def do_share_network_update(cs, args):
|
|||||||
default=None,
|
default=None,
|
||||||
action='single_alias',
|
action='single_alias',
|
||||||
help="Neutron subnet ID. Used to set up network for share servers. "
|
help="Neutron subnet ID. Used to set up network for share servers. "
|
||||||
"This subnet should belong to specified neutron network.")
|
"This subnet should belong to specified neutron network. "
|
||||||
|
"This option is deprecated for microversion >= 2.51.")
|
||||||
@cliutils.arg(
|
@cliutils.arg(
|
||||||
'--name',
|
'--name',
|
||||||
metavar='<name>',
|
metavar='<name>',
|
||||||
@ -2794,6 +2828,7 @@ def do_share_network_update(cs, args):
|
|||||||
help="Share network description.")
|
help="Share network description.")
|
||||||
def do_share_network_update(cs, args):
|
def do_share_network_update(cs, args):
|
||||||
"""Update share network data."""
|
"""Update share network data."""
|
||||||
|
|
||||||
values = {
|
values = {
|
||||||
'neutron_net_id': args.neutron_net_id,
|
'neutron_net_id': args.neutron_net_id,
|
||||||
'neutron_subnet_id': args.neutron_subnet_id,
|
'neutron_subnet_id': args.neutron_subnet_id,
|
||||||
@ -3189,6 +3224,100 @@ def do_share_network_security_service_list(cs, args):
|
|||||||
cliutils.print_list(security_services, fields=fields)
|
cliutils.print_list(security_services, fields=fields)
|
||||||
|
|
||||||
|
|
||||||
|
@cliutils.arg(
|
||||||
|
'share_network',
|
||||||
|
metavar='<share-network>',
|
||||||
|
help='Share network name or ID.')
|
||||||
|
@cliutils.arg(
|
||||||
|
'--neutron-net-id',
|
||||||
|
'--neutron-net_id', '--neutron_net_id', '--neutron_net-id',
|
||||||
|
metavar='<neutron-net-id>',
|
||||||
|
default=None,
|
||||||
|
action='single_alias',
|
||||||
|
help="Neutron network ID. Used to set up network for share servers. "
|
||||||
|
"Optional, Default = None.")
|
||||||
|
@cliutils.arg(
|
||||||
|
'--neutron-subnet-id',
|
||||||
|
'--neutron-subnet_id', '--neutron_subnet_id', '--neutron_subnet-id',
|
||||||
|
metavar='<neutron-subnet-id>',
|
||||||
|
default=None,
|
||||||
|
action='single_alias',
|
||||||
|
help="Neutron subnet ID. Used to set up network for share servers. "
|
||||||
|
"This subnet should belong to specified neutron network. "
|
||||||
|
"Optional, Default = None.")
|
||||||
|
@cliutils.arg(
|
||||||
|
'--availability-zone',
|
||||||
|
'--availability_zone',
|
||||||
|
'--az',
|
||||||
|
default=None,
|
||||||
|
action='single_alias',
|
||||||
|
metavar='<availability-zone>',
|
||||||
|
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.')
|
||||||
|
def do_share_network_subnet_create(cs, args):
|
||||||
|
"""Add a new subnet into a share network."""
|
||||||
|
if xor(bool(args.neutron_net_id), bool(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 = _find_share_network(cs, args.share_network)
|
||||||
|
values = {
|
||||||
|
'share_network_id': share_network.id,
|
||||||
|
'neutron_net_id': args.neutron_net_id,
|
||||||
|
'neutron_subnet_id': args.neutron_subnet_id,
|
||||||
|
'availability_zone': args.availability_zone,
|
||||||
|
}
|
||||||
|
share_network_subnet = cs.share_network_subnets.create(**values)
|
||||||
|
info = share_network_subnet._info.copy()
|
||||||
|
cliutils.print_dict(info)
|
||||||
|
|
||||||
|
|
||||||
|
@cliutils.arg(
|
||||||
|
'share_network',
|
||||||
|
metavar='<share-network>',
|
||||||
|
help='Share network name or ID.')
|
||||||
|
@cliutils.arg(
|
||||||
|
'share_network_subnet',
|
||||||
|
metavar='<share-network-subnet>',
|
||||||
|
nargs='+',
|
||||||
|
help='Name or ID of share network subnet(s) to be deleted.')
|
||||||
|
def do_share_network_subnet_delete(cs, args):
|
||||||
|
"""Delete one or more share network subnets."""
|
||||||
|
failure_count = 0
|
||||||
|
share_network_ref = _find_share_network(cs, args.share_network)
|
||||||
|
|
||||||
|
for subnet in args.share_network_subnet:
|
||||||
|
try:
|
||||||
|
cs.share_network_subnets.delete(share_network_ref, subnet)
|
||||||
|
except Exception as e:
|
||||||
|
failure_count += 1
|
||||||
|
print("Deletion of share network subnet %s failed: %s" % (
|
||||||
|
subnet, e), file=sys.stderr)
|
||||||
|
|
||||||
|
if failure_count == len(args.share_network_subnet):
|
||||||
|
raise exceptions.CommandError("Unable to delete any of the specified "
|
||||||
|
"share network subnets.")
|
||||||
|
|
||||||
|
|
||||||
|
@cliutils.arg(
|
||||||
|
'share_network',
|
||||||
|
metavar='<share-network>',
|
||||||
|
help='Name or ID of share network(s) to which the subnet belongs.')
|
||||||
|
@cliutils.arg(
|
||||||
|
'share_network_subnet',
|
||||||
|
metavar='<share-network-subnet>',
|
||||||
|
help='Share network subnet ID to show.')
|
||||||
|
def do_share_network_subnet_show(cs, args):
|
||||||
|
"""Show share network subnet."""
|
||||||
|
share_network = _find_share_network(cs, args.share_network)
|
||||||
|
share_network_subnet = cs.share_network_subnets.get(
|
||||||
|
share_network.id, args.share_network_subnet)
|
||||||
|
view_data = share_network_subnet._info.copy()
|
||||||
|
cliutils.print_dict(view_data)
|
||||||
|
|
||||||
|
|
||||||
@cliutils.arg(
|
@cliutils.arg(
|
||||||
'share_network',
|
'share_network',
|
||||||
metavar='<share-network>',
|
metavar='<share-network>',
|
||||||
@ -3538,6 +3667,14 @@ def do_security_service_delete(cs, args):
|
|||||||
default=None,
|
default=None,
|
||||||
help='Comma separated list of columns to be displayed '
|
help='Comma separated list of columns to be displayed '
|
||||||
'example --columns "id,host,status".')
|
'example --columns "id,host,status".')
|
||||||
|
@cliutils.arg(
|
||||||
|
'--share-network-subnet', '--share_network_subnet',
|
||||||
|
type=str,
|
||||||
|
metavar='<share_network_subnet>',
|
||||||
|
help="Filter results by share network subnet that the share server's "
|
||||||
|
"network allocation exists whithin. Available for micro version "
|
||||||
|
">= 2.51 (Optional, Default=None).",
|
||||||
|
default=None)
|
||||||
def do_share_server_list(cs, args):
|
def do_share_server_list(cs, args):
|
||||||
"""List all share servers (Admin only)."""
|
"""List all share servers (Admin only)."""
|
||||||
search_opts = {
|
search_opts = {
|
||||||
@ -3555,6 +3692,15 @@ def do_share_server_list(cs, args):
|
|||||||
"Updated_at",
|
"Updated_at",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if cs.api_version < api_versions.APIVersion("2.51"):
|
||||||
|
if getattr(args, 'share_network_subnet'):
|
||||||
|
raise exceptions.CommandError(
|
||||||
|
"Share network subnet option is only available with manila "
|
||||||
|
"API version >= 2.51")
|
||||||
|
else:
|
||||||
|
search_opts.update({'share_network_subnet': args.share_network_subnet})
|
||||||
|
fields.append("Share Network Subnet Id")
|
||||||
|
|
||||||
if args.columns is not None:
|
if args.columns is not None:
|
||||||
fields = _split_columns(columns=args.columns)
|
fields = _split_columns(columns=args.columns)
|
||||||
|
|
||||||
@ -5197,25 +5343,12 @@ def do_share_replica_list(cs, args):
|
|||||||
action='single_alias',
|
action='single_alias',
|
||||||
metavar='<availability-zone>',
|
metavar='<availability-zone>',
|
||||||
help='Optional Availability zone in which replica should be created.')
|
help='Optional Availability zone in which replica should be created.')
|
||||||
@cliutils.arg(
|
|
||||||
'--share-network',
|
|
||||||
'--share_network',
|
|
||||||
metavar='<network-info>',
|
|
||||||
default=None,
|
|
||||||
action='single_alias',
|
|
||||||
help='Optional network info ID or name.')
|
|
||||||
@api_versions.wraps("2.11")
|
@api_versions.wraps("2.11")
|
||||||
def do_share_replica_create(cs, args):
|
def do_share_replica_create(cs, args):
|
||||||
"""Create a share replica (Experimental)."""
|
"""Create a share replica (Experimental)."""
|
||||||
share = _find_share(cs, args.share)
|
share = _find_share(cs, args.share)
|
||||||
|
|
||||||
share_network = None
|
replica = cs.share_replicas.create(share, args.availability_zone)
|
||||||
if args.share_network:
|
|
||||||
share_network = _find_share_network(cs, args.share_network)
|
|
||||||
|
|
||||||
replica = cs.share_replicas.create(share,
|
|
||||||
args.availability_zone,
|
|
||||||
share_network)
|
|
||||||
_print_share_replica(cs, replica)
|
_print_share_replica(cs, replica)
|
||||||
|
|
||||||
|
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Added CLI commands to get, add and delete share network subnets.
|
||||||
|
- Updated CLI command for managing share servers to accept
|
||||||
|
``share_network_subnet`` parameter.
|
||||||
|
- Deprecated ``neutron_subnet_id`` parameter from CLI command to update a
|
||||||
|
share network.
|
||||||
|
- Updated CLI command for listing share servers to show a new column
|
||||||
|
``Share Network Subnet Id``, and to accept a filter parameter
|
||||||
|
``share_network_subnet``.
|
||||||
|
fixes:
|
||||||
|
- Fixed share replica create API to make the replica inherit parent share's
|
||||||
|
share network.
|
Loading…
x
Reference in New Issue
Block a user