Support of Scale command in openstackclient
Supported Scale command in Openstack Tacker Client. Implements: blueprint support-etsi-nfv-specs Change-Id: I27b670c0aaa0c9b9cbce6ae44e03e5ba6234beb5
This commit is contained in:

committed by
Koichi Edagawa

parent
60c268f04d
commit
d7f7ea35d2
@@ -92,3 +92,4 @@ openstack.tackerclient.v1 =
|
||||
vnflcm_delete = tackerclient.osc.v1.vnflcm.vnflcm:DeleteVnfLcm
|
||||
vnflcm_heal = tackerclient.osc.v1.vnflcm.vnflcm:HealVnfLcm
|
||||
vnflcm_update = tackerclient.osc.v1.vnflcm.vnflcm:UpdateVnfLcm
|
||||
vnflcm_scale = tackerclient.osc.v1.vnflcm.vnflcm:ScaleVnfLcm
|
||||
|
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"additionalParams": {"key1":"value1", "key2":"value2"}
|
||||
}
|
@@ -465,3 +465,71 @@ class UpdateVnfLcm(command.Command):
|
||||
if not result:
|
||||
print((_('Update vnf:%(id)s ') %
|
||||
{'id': parsed_args.vnf_instance}))
|
||||
|
||||
|
||||
class ScaleVnfLcm(command.Command):
|
||||
_description = _("Scale a VNF Instance")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ScaleVnfLcm, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
_VNF_INSTANCE,
|
||||
metavar="<vnf-instance>",
|
||||
help=_('VNF instance ID to scale'))
|
||||
parser.add_argument(
|
||||
'--I',
|
||||
metavar="<param-file>",
|
||||
help=_("Specify scale request parameters in a json file."))
|
||||
parser.add_argument(
|
||||
'--type',
|
||||
metavar="<type>",
|
||||
choices=['SCALE_OUT', 'SCALE_IN'],
|
||||
help=_("Indicates the type of the scale operation requested"))
|
||||
parser.add_argument(
|
||||
'--aspect-id',
|
||||
metavar="<aspect-id>",
|
||||
help=_("Identifier of the scaling aspect."))
|
||||
parser.add_argument(
|
||||
'--number-of-steps',
|
||||
metavar="<number-of-steps>",
|
||||
type=int,
|
||||
help=_("Number of scaling steps to be executed as part of"
|
||||
"this Scale VNF operation."))
|
||||
parser.add_argument(
|
||||
'--additional-param-file',
|
||||
metavar="<additional-param-file>",
|
||||
help=_("Additional parameters passed by the NFVO as input"
|
||||
"to the scaling process."))
|
||||
return parser
|
||||
|
||||
def args2body(self, file_path=None):
|
||||
"""To store request body, call jsonfile2body.
|
||||
|
||||
Args:
|
||||
file_path ([string], optional): file path of param file(json).
|
||||
Defaults to None.
|
||||
|
||||
Returns:
|
||||
body[dict]: [description]
|
||||
"""
|
||||
body = {}
|
||||
|
||||
if file_path:
|
||||
return jsonfile2body(file_path)
|
||||
|
||||
return body
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
"""Execute scale_vnf_instance and output result comment.
|
||||
|
||||
Args:
|
||||
parsed_args ([Namespace]): [description]
|
||||
"""
|
||||
client = self.app.client_manager.tackerclient
|
||||
if parsed_args.additional_param_file:
|
||||
result = client.scale_vnf_instance(
|
||||
parsed_args.vnf_instance,
|
||||
self.args2body(file_path=parsed_args.additional_param_file))
|
||||
if not result:
|
||||
print((_('Scale request for VNF Instance %(id)s has been'
|
||||
' accepted.') % {'id': parsed_args.vnf_instance}))
|
||||
|
@@ -602,53 +602,109 @@ class TestUpdateVnfLcm(TestVnfLcm):
|
||||
parsed_args = self.check_parser(self.update_vnf_lcm, arglist,
|
||||
verifylist)
|
||||
|
||||
self.assertRaises(exceptions.InvalidInput,
|
||||
self.update_vnf_lcm.take_action, parsed_args)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class TestScaleVnfLcm(TestVnfLcm):
|
||||
def setUp(self):
|
||||
super(TestScaleVnfLcm, self).setUp()
|
||||
self.scale_vnf_lcm = vnflcm.ScaleVnfLcm(
|
||||
self.app, self.app_args, cmd_name='vnflcm scale')
|
||||
|
||||
@ddt.data('SCALE_IN', 'SCALE_OUT')
|
||||
def test_take_action(self, scale_type):
|
||||
vnf_instance = vnflcm_fakes.vnf_instance_response()
|
||||
sample_param_file = ("./tackerclient/osc/v1/vnflcm/samples/"
|
||||
"scale_vnf_instance_param_sample.json")
|
||||
|
||||
arglist = [vnf_instance['id'],
|
||||
'--aspect-id', uuidsentinel.aspect_id,
|
||||
'--number-of-steps', '1',
|
||||
'--type', scale_type,
|
||||
'--additional-param-file', sample_param_file]
|
||||
verifylist = [('vnf_instance', vnf_instance['id']),
|
||||
('aspect_id', uuidsentinel.aspect_id),
|
||||
('number_of_steps', 1),
|
||||
('type', scale_type),
|
||||
('additional_param_file', sample_param_file)]
|
||||
|
||||
# command param
|
||||
parsed_args = self.check_parser(self.scale_vnf_lcm, arglist,
|
||||
verifylist)
|
||||
url = os.path.join(
|
||||
self.url,
|
||||
'vnflcm/v1/vnf_instances',
|
||||
vnf_instance['id'],
|
||||
'scale')
|
||||
|
||||
self.requests_mock.register_uri(
|
||||
'POST', url, headers=self.header, json={})
|
||||
|
||||
sys.stdout = buffer = StringIO()
|
||||
self.scale_vnf_lcm.take_action(parsed_args)
|
||||
|
||||
actual_message = buffer.getvalue().strip()
|
||||
|
||||
expected_message = ("Scale request for VNF Instance %s has been "
|
||||
"accepted.") % vnf_instance['id']
|
||||
|
||||
self.assertEqual(expected_message, actual_message)
|
||||
|
||||
@ddt.data('SCALE_IN', 'SCALE_OUT')
|
||||
def test_take_action_param_file_not_exists(self, scale_type):
|
||||
vnf_instance = vnflcm_fakes.vnf_instance_response()
|
||||
sample_param_file = "./not_exists.json"
|
||||
arglist = [vnf_instance['id'],
|
||||
'--aspect-id', uuidsentinel.aspect_id,
|
||||
'--number-of-steps', '2',
|
||||
'--type', scale_type,
|
||||
'--additional-param-file', sample_param_file]
|
||||
verifylist = [('vnf_instance', vnf_instance['id']),
|
||||
('aspect_id', uuidsentinel.aspect_id),
|
||||
('number_of_steps', 2),
|
||||
('type', scale_type),
|
||||
('additional_param_file', sample_param_file)]
|
||||
|
||||
# command param
|
||||
parsed_args = self.check_parser(self.scale_vnf_lcm, arglist,
|
||||
verifylist)
|
||||
|
||||
ex = self.assertRaises(exceptions.InvalidInput,
|
||||
self.update_vnf_lcm.take_action, parsed_args)
|
||||
self.scale_vnf_lcm.take_action, parsed_args)
|
||||
|
||||
expected_msg = ("Invalid input: File %s does not exist "
|
||||
"or user does not have read privileges to it")
|
||||
self.assertEqual(expected_msg % sample_param_file, str(ex))
|
||||
|
||||
def test_take_action_vnf_instance_not_found(self):
|
||||
@ddt.data('SCALE_IN', 'SCALE_OUT')
|
||||
def test_take_action_vnf_instance_not_found(self, scale_type):
|
||||
vnf_instance = vnflcm_fakes.vnf_instance_response()
|
||||
sample_param_file = ("./tackerclient/osc/v1/vnflcm/samples/"
|
||||
"update_vnf_instance_param_sample.json")
|
||||
arglist = [vnf_instance['id'], '--I', sample_param_file]
|
||||
arglist = [vnf_instance['id'],
|
||||
'--aspect-id', uuidsentinel.aspect_id,
|
||||
'--number-of-steps', '3',
|
||||
'--type', scale_type,
|
||||
'--additional-param-file', sample_param_file]
|
||||
verifylist = [('vnf_instance', vnf_instance['id']),
|
||||
('I', sample_param_file)]
|
||||
('aspect_id', uuidsentinel.aspect_id),
|
||||
('number_of_steps', 3),
|
||||
('type', scale_type),
|
||||
('additional_param_file', sample_param_file)]
|
||||
|
||||
# command param
|
||||
parsed_args = self.check_parser(
|
||||
self.update_vnf_lcm, arglist, verifylist)
|
||||
parsed_args = self.check_parser(self.scale_vnf_lcm, arglist,
|
||||
verifylist)
|
||||
|
||||
url = os.path.join(
|
||||
self.url,
|
||||
'vnflcm/v1/vnf_instances',
|
||||
vnf_instance['id'])
|
||||
self.requests_mock.register_uri(
|
||||
'PATCH', url, headers=self.header, status_code=404, json={})
|
||||
'POST', url, headers=self.header, status_code=404, json={})
|
||||
|
||||
self.assertRaises(exceptions.TackerClientException,
|
||||
self.update_vnf_lcm.take_action,
|
||||
self.scale_vnf_lcm.take_action,
|
||||
parsed_args)
|
||||
|
||||
@mock.patch("os.open")
|
||||
@mock.patch("os.access")
|
||||
def test_take_action_invalid_format_param_file(self, mock_open,
|
||||
mock_access):
|
||||
vnf_instance = vnflcm_fakes.vnf_instance_response()
|
||||
sample_param_file = "./invalid_param_file.json"
|
||||
arglist = [vnf_instance['id'], '--I', sample_param_file]
|
||||
verifylist = [('vnf_instance', vnf_instance['id']),
|
||||
('I', sample_param_file)]
|
||||
|
||||
mock_open.return_value = "invalid_json_data"
|
||||
# command param
|
||||
parsed_args = self.check_parser(self.update_vnf_lcm, arglist,
|
||||
verifylist)
|
||||
|
||||
ex = self.assertRaises(exceptions.InvalidInput,
|
||||
self.update_vnf_lcm.take_action,
|
||||
parsed_args)
|
||||
expected_msg = "Failed to load parameter file."
|
||||
self.assertIn(expected_msg, str(ex))
|
||||
|
@@ -900,6 +900,11 @@ class VnfLCMClient(ClientBase):
|
||||
def update_vnf_instance(self, vnf_id, body):
|
||||
return self.patch(self.vnf_instance_path % vnf_id, body=body)
|
||||
|
||||
@APIParamsCall
|
||||
def scale_vnf_instance(self, vnf_id, body):
|
||||
return self.post((self.vnf_instance_path + "/scale") % vnf_id,
|
||||
body=body)
|
||||
|
||||
|
||||
class Client(object):
|
||||
"""Unified interface to interact with multiple applications of tacker service.
|
||||
@@ -1170,6 +1175,9 @@ class Client(object):
|
||||
def terminate_vnf_instance(self, vnf_id, body):
|
||||
return self.vnf_lcm_client.terminate_vnf_instance(vnf_id, body)
|
||||
|
||||
def scale_vnf_instance(self, vnf_id, body):
|
||||
return self.vnf_lcm_client.scale_vnf_instance(vnf_id, body)
|
||||
|
||||
def delete_vnf_instance(self, vnf_id):
|
||||
return self.vnf_lcm_client.delete_vnf_instance(vnf_id)
|
||||
|
||||
|
Reference in New Issue
Block a user