Add namespace support for actions to client
When creating an action-definition user can use the option --namespace to create the action in that specific namespace, if it was not provided the action will be created in the default namespace. default namespace is ''. *Added --namespace to action commands, *Added --namespace option to run-action Depends-On: I07862e30adf28404ec70a473571a9213e53d8a08 Implements: blueprint create-and-run-workflows-within-a-namespace Change-Id: I18dbd9faee06c3cd2209f7e579eeb2e1a24c88d9
This commit is contained in:
parent
165a3b3455
commit
e1e75d61eb
@ -1,4 +1,5 @@
|
|||||||
# Copyright 2014 - Mirantis, Inc.
|
# Copyright 2014 - Mirantis, Inc.
|
||||||
|
# Copyright 2020 Nokia Software.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@ -24,7 +25,7 @@ class ActionExecution(base.Resource):
|
|||||||
class ActionExecutionManager(base.ResourceManager):
|
class ActionExecutionManager(base.ResourceManager):
|
||||||
resource_class = ActionExecution
|
resource_class = ActionExecution
|
||||||
|
|
||||||
def create(self, name, input=None, **params):
|
def create(self, name, input=None, namespace='', **params):
|
||||||
self._ensure_not_empty(name=name)
|
self._ensure_not_empty(name=name)
|
||||||
|
|
||||||
data = {'name': name}
|
data = {'name': name}
|
||||||
@ -35,6 +36,9 @@ class ActionExecutionManager(base.ResourceManager):
|
|||||||
if params:
|
if params:
|
||||||
data['params'] = jsonutils.dumps(params)
|
data['params'] = jsonutils.dumps(params)
|
||||||
|
|
||||||
|
if namespace:
|
||||||
|
data['workflow_namespace'] = namespace
|
||||||
|
|
||||||
return self._create(
|
return self._create(
|
||||||
'/action_executions',
|
'/action_executions',
|
||||||
data,
|
data,
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
# Copyright 2014 - Mirantis, Inc.
|
# Copyright 2014 - Mirantis, Inc.
|
||||||
|
# Copyright 2020 Nokia Software.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@ -23,7 +24,7 @@ class Action(base.Resource):
|
|||||||
class ActionManager(base.ResourceManager):
|
class ActionManager(base.ResourceManager):
|
||||||
resource_class = Action
|
resource_class = Action
|
||||||
|
|
||||||
def create(self, definition, scope='private'):
|
def create(self, definition, scope='private', namespace=''):
|
||||||
self._ensure_not_empty(definition=definition)
|
self._ensure_not_empty(definition=definition)
|
||||||
|
|
||||||
# If the specified definition is actually a file, read in the
|
# If the specified definition is actually a file, read in the
|
||||||
@ -31,7 +32,7 @@ class ActionManager(base.ResourceManager):
|
|||||||
definition = utils.get_contents_if_file(definition)
|
definition = utils.get_contents_if_file(definition)
|
||||||
|
|
||||||
return self._create(
|
return self._create(
|
||||||
'/actions?scope=%s' % scope,
|
'/actions?scope=%s&namespace=%s' % (scope, namespace),
|
||||||
definition,
|
definition,
|
||||||
response_key='actions',
|
response_key='actions',
|
||||||
dump_json=False,
|
dump_json=False,
|
||||||
@ -39,17 +40,15 @@ class ActionManager(base.ResourceManager):
|
|||||||
is_iter_resp=True
|
is_iter_resp=True
|
||||||
)
|
)
|
||||||
|
|
||||||
def update(self, definition, scope='private', id=None):
|
def update(self, definition, scope='private', id=None, namespace=''):
|
||||||
self._ensure_not_empty(definition=definition)
|
self._ensure_not_empty(definition=definition)
|
||||||
|
params = '?scope=%s&namespace=%s' % (scope, namespace)
|
||||||
url_pre = ('/actions/%s' % id) if id else '/actions'
|
url = ('/actions/%s' % id if id else '/actions') + params
|
||||||
|
|
||||||
# If the specified definition is actually a file, read in the
|
# If the specified definition is actually a file, read in the
|
||||||
# definition file
|
# definition file
|
||||||
definition = utils.get_contents_if_file(definition)
|
definition = utils.get_contents_if_file(definition)
|
||||||
|
|
||||||
return self._update(
|
return self._update(
|
||||||
'%s?scope=%s' % (url_pre, scope),
|
url,
|
||||||
definition,
|
definition,
|
||||||
response_key='actions',
|
response_key='actions',
|
||||||
dump_json=False,
|
dump_json=False,
|
||||||
@ -59,7 +58,6 @@ class ActionManager(base.ResourceManager):
|
|||||||
|
|
||||||
def list(self, marker='', limit=None, sort_keys='', sort_dirs='',
|
def list(self, marker='', limit=None, sort_keys='', sort_dirs='',
|
||||||
fields='', **filters):
|
fields='', **filters):
|
||||||
|
|
||||||
query_string = self._build_query_params(
|
query_string = self._build_query_params(
|
||||||
marker=marker,
|
marker=marker,
|
||||||
limit=limit,
|
limit=limit,
|
||||||
@ -74,15 +72,15 @@ class ActionManager(base.ResourceManager):
|
|||||||
response_key='actions',
|
response_key='actions',
|
||||||
)
|
)
|
||||||
|
|
||||||
def get(self, identifier):
|
def get(self, identifier, namespace=''):
|
||||||
self._ensure_not_empty(identifier=identifier)
|
self._ensure_not_empty(identifier=identifier)
|
||||||
|
|
||||||
return self._get('/actions/%s' % identifier)
|
return self._get('/actions/%s/%s' % (identifier, namespace))
|
||||||
|
|
||||||
def delete(self, identifier):
|
def delete(self, identifier, namespace=''):
|
||||||
self._ensure_not_empty(identifier=identifier)
|
self._ensure_not_empty(identifier=identifier)
|
||||||
|
|
||||||
self._delete('/actions/%s' % identifier)
|
self._delete('/actions/%s/%s' % (identifier, namespace))
|
||||||
|
|
||||||
def validate(self, definition):
|
def validate(self, definition):
|
||||||
self._ensure_not_empty(definition=definition)
|
self._ensure_not_empty(definition=definition)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
# Copyright 2014 - Mirantis, Inc.
|
# Copyright 2014 - Mirantis, Inc.
|
||||||
# Copyright 2016 - Brocade Communications Systems, Inc.
|
# Copyright 2016 - Brocade Communications Systems, Inc.
|
||||||
|
# Copyright 2020 Nokia Software.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# 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
|
# not use this file except in compliance with the License. You may obtain
|
||||||
@ -120,6 +121,12 @@ class Create(command.ShowOne):
|
|||||||
dest='target',
|
dest='target',
|
||||||
help='Action will be executed on <target> executor.'
|
help='Action will be executed on <target> executor.'
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--namespace',
|
||||||
|
nargs='?',
|
||||||
|
default='',
|
||||||
|
help="Namespace of the action(s).",
|
||||||
|
)
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -145,6 +152,7 @@ class Create(command.ShowOne):
|
|||||||
action_ex = mistral_client.action_executions.create(
|
action_ex = mistral_client.action_executions.create(
|
||||||
parsed_args.name,
|
parsed_args.name,
|
||||||
action_input,
|
action_input,
|
||||||
|
namespace=parsed_args.namespace,
|
||||||
**params
|
**params
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
# Copyright 2014 - Mirantis, Inc.
|
# Copyright 2014 - Mirantis, Inc.
|
||||||
|
# Copyright 2020 Nokia Software.
|
||||||
# All Rights Reserved
|
# All Rights Reserved
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
@ -26,12 +27,13 @@ class ActionFormatter(base.MistralFormatter):
|
|||||||
COLUMNS = [
|
COLUMNS = [
|
||||||
('id', 'ID'),
|
('id', 'ID'),
|
||||||
('name', 'Name'),
|
('name', 'Name'),
|
||||||
|
('namespace', 'Namespace'),
|
||||||
('is_system', 'Is system'),
|
('is_system', 'Is system'),
|
||||||
('input', 'Input'),
|
('input', 'Input'),
|
||||||
('description', 'Description'),
|
('description', 'Description'),
|
||||||
('tags', 'Tags'),
|
('tags', 'Tags'),
|
||||||
('created_at', 'Created at'),
|
('created_at', 'Created at'),
|
||||||
('updated_at', 'Updated at')
|
('updated_at', 'Updated at'),
|
||||||
]
|
]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -45,6 +47,7 @@ class ActionFormatter(base.MistralFormatter):
|
|||||||
data = (
|
data = (
|
||||||
action.id,
|
action.id,
|
||||||
action.name,
|
action.name,
|
||||||
|
action.namespace,
|
||||||
action.is_system,
|
action.is_system,
|
||||||
input_,
|
input_,
|
||||||
desc,
|
desc,
|
||||||
@ -93,12 +96,20 @@ class Get(command.ShowOne):
|
|||||||
parser = super(Get, self).get_parser(prog_name)
|
parser = super(Get, self).get_parser(prog_name)
|
||||||
|
|
||||||
parser.add_argument('action', help='Action (name or ID)')
|
parser.add_argument('action', help='Action (name or ID)')
|
||||||
|
parser.add_argument(
|
||||||
|
'--namespace',
|
||||||
|
nargs='?',
|
||||||
|
default='',
|
||||||
|
help="Namespace to create the action within.",
|
||||||
|
)
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
mistral_client = self.app.client_manager.workflow_engine
|
mistral_client = self.app.client_manager.workflow_engine
|
||||||
action = mistral_client.actions.get(parsed_args.action)
|
action = mistral_client.actions.get(
|
||||||
|
parsed_args.action,
|
||||||
|
parsed_args.namespace)
|
||||||
|
|
||||||
return ActionFormatter.format(action)
|
return ActionFormatter.format(action)
|
||||||
|
|
||||||
@ -119,6 +130,12 @@ class Create(base.MistralLister):
|
|||||||
action='store_true',
|
action='store_true',
|
||||||
help='With this flag action will be marked as "public".'
|
help='With this flag action will be marked as "public".'
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--namespace',
|
||||||
|
nargs='?',
|
||||||
|
default='',
|
||||||
|
help="Namespace to create the action within.",
|
||||||
|
)
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -136,6 +153,7 @@ class Create(base.MistralLister):
|
|||||||
|
|
||||||
return mistral_client.actions.create(
|
return mistral_client.actions.create(
|
||||||
parsed_args.definition.read(),
|
parsed_args.definition.read(),
|
||||||
|
namespace=parsed_args.namespace,
|
||||||
scope=scope
|
scope=scope
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -151,6 +169,12 @@ class Delete(command.Command):
|
|||||||
nargs='+',
|
nargs='+',
|
||||||
help='Name or ID of action(s).'
|
help='Name or ID of action(s).'
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--namespace',
|
||||||
|
nargs='?',
|
||||||
|
default='',
|
||||||
|
help="Namespace of the action(s).",
|
||||||
|
)
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -158,7 +182,9 @@ class Delete(command.Command):
|
|||||||
mistral_client = self.app.client_manager.workflow_engine
|
mistral_client = self.app.client_manager.workflow_engine
|
||||||
|
|
||||||
utils.do_action_on_many(
|
utils.do_action_on_many(
|
||||||
lambda s: mistral_client.actions.delete(s),
|
lambda s: mistral_client.actions.delete(
|
||||||
|
s,
|
||||||
|
namespace=parsed_args.namespace),
|
||||||
parsed_args.action,
|
parsed_args.action,
|
||||||
"Request to delete action %s has been accepted.",
|
"Request to delete action %s has been accepted.",
|
||||||
"Unable to delete the specified action(s)."
|
"Unable to delete the specified action(s)."
|
||||||
@ -182,6 +208,12 @@ class Update(base.MistralLister):
|
|||||||
action='store_true',
|
action='store_true',
|
||||||
help='With this flag action will be marked as "public".'
|
help='With this flag action will be marked as "public".'
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--namespace',
|
||||||
|
nargs='?',
|
||||||
|
default='',
|
||||||
|
help="Namespace of the action.",
|
||||||
|
)
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -207,18 +239,27 @@ class GetDefinition(command.Command):
|
|||||||
parser = super(GetDefinition, self).get_parser(prog_name)
|
parser = super(GetDefinition, self).get_parser(prog_name)
|
||||||
|
|
||||||
parser.add_argument('name', help='Action name')
|
parser.add_argument('name', help='Action name')
|
||||||
|
parser.add_argument(
|
||||||
|
'--namespace',
|
||||||
|
nargs='?',
|
||||||
|
default='',
|
||||||
|
help="Namespace of the action.",
|
||||||
|
)
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
mistral_client = self.app.client_manager.workflow_engine
|
mistral_client = self.app.client_manager.workflow_engine
|
||||||
definition = mistral_client.actions.get(parsed_args.name).definition
|
definition = mistral_client.actions.get(
|
||||||
|
parsed_args.name,
|
||||||
|
namespace=parsed_args.namespace).definition
|
||||||
|
|
||||||
self.app.stdout.write(definition or "\n")
|
self.app.stdout.write(definition or "\n")
|
||||||
|
|
||||||
|
|
||||||
class Validate(command.ShowOne):
|
class Validate(command.ShowOne):
|
||||||
"""Validate action."""
|
"""Validate action."""
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _format(result=None):
|
def _format(result=None):
|
||||||
columns = ('Valid', 'Error')
|
columns = ('Valid', 'Error')
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
# Copyright (c) 2014 Mirantis, Inc.
|
# Copyright (c) 2014 Mirantis, Inc.
|
||||||
|
# Copyright 2020 Nokia Software.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# 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
|
# not use this file except in compliance with the License. You may obtain
|
||||||
@ -192,12 +193,16 @@ class MistralClientTestBase(base.MistralCLIAuth, base.MistralCLIAltAuth):
|
|||||||
|
|
||||||
return member
|
return member
|
||||||
|
|
||||||
def action_create(self, act_def, admin=True, scope='private'):
|
def action_create(self, act_def, admin=True,
|
||||||
|
scope='private', namespace=''):
|
||||||
params = '{0}'.format(act_def)
|
params = '{0}'.format(act_def)
|
||||||
|
|
||||||
if scope == 'public':
|
if scope == 'public':
|
||||||
params += ' --public'
|
params += ' --public'
|
||||||
|
|
||||||
|
if namespace:
|
||||||
|
params += " --namespace " + namespace
|
||||||
|
|
||||||
acts = self.mistral_cli(
|
acts = self.mistral_cli(
|
||||||
admin,
|
admin,
|
||||||
'action-create',
|
'action-create',
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
# Copyright (c) 2014 Mirantis, Inc.
|
# Copyright (c) 2014 Mirantis, Inc.
|
||||||
|
# Copyright 2020 Nokia Software.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# 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
|
# not use this file except in compliance with the License. You may obtain
|
||||||
@ -1381,6 +1382,16 @@ class ActionCLITests(base_v2.MistralClientTestBase):
|
|||||||
|
|
||||||
self.assertNotIn('404 Not Found', definition)
|
self.assertNotIn('404 Not Found', definition)
|
||||||
|
|
||||||
|
def test_action_get_definition_with_namespace(self):
|
||||||
|
self.action_create(self.act_def)
|
||||||
|
|
||||||
|
definition = self.mistral_admin(
|
||||||
|
'action-get-definition',
|
||||||
|
params='greeting --namespace test_namespace'
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertNotIn('404 Not Found', definition)
|
||||||
|
|
||||||
def test_action_get_with_id(self):
|
def test_action_get_with_id(self):
|
||||||
created = self.action_create(self.act_def)
|
created = self.action_create(self.act_def)
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
# Copyright 2015 Huawei Technologies Co., Ltd.
|
# Copyright 2015 Huawei Technologies Co., Ltd.
|
||||||
|
# Copyright 2020 Nokia Software.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@ -75,6 +76,20 @@ class TestActionsV2(base.BaseClientV2Test):
|
|||||||
self.assertEqual('text/plain', last_request.headers['content-type'])
|
self.assertEqual('text/plain', last_request.headers['content-type'])
|
||||||
self.assertEqual(ACTION_DEF, last_request.text)
|
self.assertEqual(ACTION_DEF, last_request.text)
|
||||||
|
|
||||||
|
def test_create_with_namespace(self):
|
||||||
|
self.requests_mock.post(self.TEST_URL + URL_TEMPLATE,
|
||||||
|
json={'actions': [ACTION]},
|
||||||
|
status_code=201)
|
||||||
|
|
||||||
|
actions = self.actions.create(ACTION_DEF, namespace='test_namespace')
|
||||||
|
|
||||||
|
self.assertIsNotNone(actions)
|
||||||
|
self.assertEqual(ACTION_DEF, actions[0].definition)
|
||||||
|
|
||||||
|
last_request = self.requests_mock.last_request
|
||||||
|
self.assertEqual('text/plain', last_request.headers['content-type'])
|
||||||
|
self.assertEqual(ACTION_DEF, last_request.text)
|
||||||
|
|
||||||
def test_create_with_file(self):
|
def test_create_with_file(self):
|
||||||
self.requests_mock.post(self.TEST_URL + URL_TEMPLATE,
|
self.requests_mock.post(self.TEST_URL + URL_TEMPLATE,
|
||||||
json={'actions': [ACTION]},
|
json={'actions': [ACTION]},
|
||||||
@ -106,7 +121,7 @@ class TestActionsV2(base.BaseClientV2Test):
|
|||||||
|
|
||||||
last_request = self.requests_mock.last_request
|
last_request = self.requests_mock.last_request
|
||||||
|
|
||||||
self.assertEqual('scope=private', last_request.query)
|
self.assertEqual('scope=private&namespace=', last_request.query)
|
||||||
self.assertEqual('text/plain', last_request.headers['content-type'])
|
self.assertEqual('text/plain', last_request.headers['content-type'])
|
||||||
self.assertEqual(ACTION_DEF, last_request.text)
|
self.assertEqual(ACTION_DEF, last_request.text)
|
||||||
|
|
||||||
@ -121,7 +136,22 @@ class TestActionsV2(base.BaseClientV2Test):
|
|||||||
|
|
||||||
last_request = self.requests_mock.last_request
|
last_request = self.requests_mock.last_request
|
||||||
|
|
||||||
self.assertEqual('scope=private', last_request.query)
|
self.assertEqual('scope=private&namespace=', last_request.query)
|
||||||
|
self.assertEqual('text/plain', last_request.headers['content-type'])
|
||||||
|
self.assertEqual(ACTION_DEF, last_request.text)
|
||||||
|
|
||||||
|
def test_update_with_namespace(self):
|
||||||
|
self.requests_mock.put(self.TEST_URL + URL_TEMPLATE,
|
||||||
|
json={'actions': [ACTION]})
|
||||||
|
actions = self.actions.update(ACTION_DEF, namespace='test_namespace')
|
||||||
|
|
||||||
|
self.assertIsNotNone(actions)
|
||||||
|
self.assertEqual(ACTION_DEF, actions[0].definition)
|
||||||
|
|
||||||
|
last_request = self.requests_mock.last_request
|
||||||
|
|
||||||
|
self.assertEqual('scope=private&namespace=test_namespace',
|
||||||
|
last_request.query)
|
||||||
self.assertEqual('text/plain', last_request.headers['content-type'])
|
self.assertEqual('text/plain', last_request.headers['content-type'])
|
||||||
self.assertEqual(ACTION_DEF, last_request.text)
|
self.assertEqual(ACTION_DEF, last_request.text)
|
||||||
|
|
||||||
@ -145,7 +175,7 @@ class TestActionsV2(base.BaseClientV2Test):
|
|||||||
self.assertEqual(ACTION_DEF, actions[0].definition)
|
self.assertEqual(ACTION_DEF, actions[0].definition)
|
||||||
|
|
||||||
last_request = self.requests_mock.last_request
|
last_request = self.requests_mock.last_request
|
||||||
self.assertEqual('scope=private', last_request.query)
|
self.assertEqual('scope=private&namespace=', last_request.query)
|
||||||
self.assertEqual('text/plain', last_request.headers['content-type'])
|
self.assertEqual('text/plain', last_request.headers['content-type'])
|
||||||
self.assertEqual(ACTION_DEF, last_request.text)
|
self.assertEqual(ACTION_DEF, last_request.text)
|
||||||
|
|
||||||
@ -197,7 +227,7 @@ class TestActionsV2(base.BaseClientV2Test):
|
|||||||
self.assertNotIn('limit', last_request.qs)
|
self.assertNotIn('limit', last_request.qs)
|
||||||
|
|
||||||
def test_get(self):
|
def test_get(self):
|
||||||
self.requests_mock.get(self.TEST_URL + URL_TEMPLATE_NAME % 'action',
|
self.requests_mock.get(self.TEST_URL + URL_TEMPLATE_NAME % 'action/',
|
||||||
json=ACTION)
|
json=ACTION)
|
||||||
|
|
||||||
action = self.actions.get('action')
|
action = self.actions.get('action')
|
||||||
@ -208,14 +238,35 @@ class TestActionsV2(base.BaseClientV2Test):
|
|||||||
action.to_dict()
|
action.to_dict()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_get_with_namespace(self):
|
||||||
|
self.requests_mock.get(self.TEST_URL + URL_TEMPLATE_NAME
|
||||||
|
% 'action/namespace',
|
||||||
|
json=ACTION)
|
||||||
|
|
||||||
|
action = self.actions.get('action', 'namespace')
|
||||||
|
|
||||||
|
self.assertIsNotNone(action)
|
||||||
|
self.assertEqual(
|
||||||
|
actions.Action(self.actions, ACTION).to_dict(),
|
||||||
|
action.to_dict()
|
||||||
|
)
|
||||||
|
|
||||||
def test_delete(self):
|
def test_delete(self):
|
||||||
url = self.TEST_URL + URL_TEMPLATE_NAME % 'action'
|
url = self.TEST_URL + URL_TEMPLATE_NAME % 'action/'
|
||||||
m = self.requests_mock.delete(url, status_code=204)
|
m = self.requests_mock.delete(url, status_code=204)
|
||||||
|
|
||||||
self.actions.delete('action')
|
self.actions.delete('action')
|
||||||
|
|
||||||
self.assertEqual(1, m.call_count)
|
self.assertEqual(1, m.call_count)
|
||||||
|
|
||||||
|
def test_delete_with_namespace(self):
|
||||||
|
url = self.TEST_URL + URL_TEMPLATE_NAME % 'action/namespace'
|
||||||
|
m = self.requests_mock.delete(url, status_code=204)
|
||||||
|
|
||||||
|
self.actions.delete('action', 'namespace')
|
||||||
|
|
||||||
|
self.assertEqual(1, m.call_count)
|
||||||
|
|
||||||
def test_validate(self):
|
def test_validate(self):
|
||||||
self.requests_mock.post(self.TEST_URL + URL_TEMPLATE_VALIDATE,
|
self.requests_mock.post(self.TEST_URL + URL_TEMPLATE_VALIDATE,
|
||||||
json={'valid': True})
|
json={'valid': True})
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
# Copyright 2014 Mirantis, Inc.
|
# Copyright 2014 Mirantis, Inc.
|
||||||
|
# Copyright 2020 Nokia Software.
|
||||||
# All Rights Reserved
|
# All Rights Reserved
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
@ -31,7 +32,8 @@ ACTION_DICT = {
|
|||||||
'description': 'My cool action',
|
'description': 'My cool action',
|
||||||
'tags': ['test'],
|
'tags': ['test'],
|
||||||
'created_at': '1',
|
'created_at': '1',
|
||||||
'updated_at': '1'
|
'updated_at': '1',
|
||||||
|
'namespace': 'test_namespace'
|
||||||
}
|
}
|
||||||
|
|
||||||
ACTION_DEF = """
|
ACTION_DEF = """
|
||||||
@ -58,7 +60,7 @@ class TestCLIActionsV2(base.BaseCommandTest):
|
|||||||
result = self.call(action_cmd.Create, app_args=['1.txt'])
|
result = self.call(action_cmd.Create, app_args=['1.txt'])
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
[('1234-4567-7894-7895', 'a', True, "param1",
|
[('1234-4567-7894-7895', 'a', 'test_namespace', True, "param1",
|
||||||
'My cool action', 'test', '1', '1')],
|
'My cool action', 'test', '1', '1')],
|
||||||
result[1]
|
result[1]
|
||||||
)
|
)
|
||||||
@ -73,7 +75,7 @@ class TestCLIActionsV2(base.BaseCommandTest):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
[('1234-4567-7894-7895', 'a', True, "param1",
|
[('1234-4567-7894-7895', 'a', 'test_namespace', True, "param1",
|
||||||
'My cool action', 'test', '1', '1')],
|
'My cool action', 'test', '1', '1')],
|
||||||
result[1]
|
result[1]
|
||||||
)
|
)
|
||||||
@ -99,8 +101,9 @@ class TestCLIActionsV2(base.BaseCommandTest):
|
|||||||
result = self.call(action_cmd.Create, app_args=['1.txt'])
|
result = self.call(action_cmd.Create, app_args=['1.txt'])
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
[('1234-4567-7894-7895', 'a', True, cmd_base.cut(long_input),
|
[('1234-4567-7894-7895', 'a', 'test_namespace',
|
||||||
'My cool action', 'test', '1', '1')],
|
True, cmd_base.cut(long_input), 'My cool action',
|
||||||
|
'test', '1', '1')],
|
||||||
result[1]
|
result[1]
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -111,7 +114,7 @@ class TestCLIActionsV2(base.BaseCommandTest):
|
|||||||
result = self.call(action_cmd.Update, app_args=['my_action.yaml'])
|
result = self.call(action_cmd.Update, app_args=['my_action.yaml'])
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
[('1234-4567-7894-7895', 'a', True, "param1",
|
[('1234-4567-7894-7895', 'a', 'test_namespace', True, "param1",
|
||||||
'My cool action', 'test', '1', '1')],
|
'My cool action', 'test', '1', '1')],
|
||||||
result[1]
|
result[1]
|
||||||
)
|
)
|
||||||
@ -126,7 +129,7 @@ class TestCLIActionsV2(base.BaseCommandTest):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
[('1234-4567-7894-7895', 'a', True, "param1",
|
[('1234-4567-7894-7895', 'a', 'test_namespace', True, "param1",
|
||||||
'My cool action', 'test', '1', '1')],
|
'My cool action', 'test', '1', '1')],
|
||||||
result[1]
|
result[1]
|
||||||
)
|
)
|
||||||
@ -142,7 +145,7 @@ class TestCLIActionsV2(base.BaseCommandTest):
|
|||||||
result = self.call(action_cmd.List)
|
result = self.call(action_cmd.List)
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
[('1234-4567-7894-7895', 'a', True, "param1",
|
[('1234-4567-7894-7895', 'a', 'test_namespace', True, "param1",
|
||||||
'My cool action', 'test', '1', '1')],
|
'My cool action', 'test', '1', '1')],
|
||||||
result[1]
|
result[1]
|
||||||
)
|
)
|
||||||
@ -153,7 +156,7 @@ class TestCLIActionsV2(base.BaseCommandTest):
|
|||||||
result = self.call(action_cmd.Get, app_args=['name'])
|
result = self.call(action_cmd.Get, app_args=['name'])
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
('1234-4567-7894-7895', 'a', True, "param1",
|
('1234-4567-7894-7895', 'a', 'test_namespace', True, "param1",
|
||||||
'My cool action', 'test', '1', '1'),
|
'My cool action', 'test', '1', '1'),
|
||||||
result[1]
|
result[1]
|
||||||
)
|
)
|
||||||
@ -161,14 +164,39 @@ class TestCLIActionsV2(base.BaseCommandTest):
|
|||||||
def test_delete(self):
|
def test_delete(self):
|
||||||
self.call(action_cmd.Delete, app_args=['name'])
|
self.call(action_cmd.Delete, app_args=['name'])
|
||||||
|
|
||||||
self.client.actions.delete.assert_called_once_with('name')
|
self.client.actions.delete.assert_called_once_with('name',
|
||||||
|
namespace='')
|
||||||
|
|
||||||
|
def test_delete_with_namespace(self):
|
||||||
|
self.call(action_cmd.Delete, app_args=['name',
|
||||||
|
'--namespace',
|
||||||
|
'test_namespace']
|
||||||
|
)
|
||||||
|
|
||||||
|
self.client.actions.delete.assert_called_once_with(
|
||||||
|
'name',
|
||||||
|
namespace='test_namespace')
|
||||||
|
|
||||||
|
def test_delete_with_multi_names_and_namespace(self):
|
||||||
|
self.call(action_cmd.Delete, app_args=['name1',
|
||||||
|
'name2',
|
||||||
|
'--namespace',
|
||||||
|
'test_namespace'])
|
||||||
|
|
||||||
|
self.assertEqual(2, self.client.actions.delete.call_count)
|
||||||
|
self.assertEqual(
|
||||||
|
[mock.call('name1', namespace='test_namespace'),
|
||||||
|
mock.call('name2', namespace='test_namespace')],
|
||||||
|
self.client.actions.delete.call_args_list
|
||||||
|
)
|
||||||
|
|
||||||
def test_delete_with_multi_names(self):
|
def test_delete_with_multi_names(self):
|
||||||
self.call(action_cmd.Delete, app_args=['name1', 'name2'])
|
self.call(action_cmd.Delete, app_args=['name1', 'name2'])
|
||||||
|
|
||||||
self.assertEqual(2, self.client.actions.delete.call_count)
|
self.assertEqual(2, self.client.actions.delete.call_count)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
[mock.call('name1'), mock.call('name2')],
|
[mock.call('name1', namespace=''),
|
||||||
|
mock.call('name2', namespace='')],
|
||||||
self.client.actions.delete.call_args_list
|
self.client.actions.delete.call_args_list
|
||||||
)
|
)
|
||||||
|
|
||||||
|
5
releasenotes/notes/add_namespace_option_to_actions.yaml
Normal file
5
releasenotes/notes/add_namespace_option_to_actions.yaml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Add namespace parameter to action commands. Namespace parameter allows
|
||||||
|
to create multiple actions with same name under different namespaces.
|
Loading…
Reference in New Issue
Block a user