Add support for info actions for task
fuel2 task deployment-info download 1 --file deployment-info.yaml
fuel2 task settings download 1 --file settings.yaml
fuel2 task network-configuration download 1 --file networks.yaml
Closes-Bug: #1566462
DocImpact
Change-Id: If6fdeaf68c5dd4d8b3330e63f02205d425ae5021
(cherry picked from commit 3b1e95e235)
This commit is contained in:
committed by
Vladimir Sharshov
parent
a2388bc910
commit
a4000b98db
@@ -48,10 +48,13 @@ def get_client(resource, version='v1'):
|
||||
|
||||
version_map = {
|
||||
'v1': {
|
||||
'cluster-settings': v1.cluster_settings,
|
||||
'deployment_history': v1.deployment_history,
|
||||
'deployment-info': v1.deployment_info,
|
||||
'environment': v1.environment,
|
||||
'fuel-version': v1.fuelversion,
|
||||
'graph': v1.graph,
|
||||
'network-configuration': v1.network_configuration,
|
||||
'network-group': v1.network_group,
|
||||
'node': v1.node,
|
||||
'openstack-config': v1.openstack_config,
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
|
||||
from fuelclient.cli.serializers import Serializer
|
||||
from fuelclient.commands import base
|
||||
from fuelclient.common import data_utils
|
||||
|
||||
@@ -19,6 +22,97 @@ from fuelclient.common import data_utils
|
||||
class TaskMixIn(object):
|
||||
entity_name = 'task'
|
||||
|
||||
@staticmethod
|
||||
def add_file_arg(parser):
|
||||
parser.add_argument(
|
||||
'-f',
|
||||
'--file',
|
||||
required=False,
|
||||
type=str,
|
||||
help='YAML file that contains network configuration.'
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def write_info_to_file(cls, info_type, data, transaction_id,
|
||||
serializer=None, file_path=None):
|
||||
"""Write additional info to the given path.
|
||||
|
||||
:param info_type: deployment_info | cluster_settings |
|
||||
network_configuration
|
||||
:type info_type: str
|
||||
:param data: data
|
||||
:type data: list of dict
|
||||
:param serializer: serializer
|
||||
:param transaction_id: Transaction ID
|
||||
:type transaction_id: str or int
|
||||
:param file_path: path
|
||||
:type file_path: str
|
||||
:return: path to resulting file
|
||||
:rtype: str
|
||||
"""
|
||||
return (serializer or Serializer()).write_to_path(
|
||||
(file_path or cls.get_default_info_path(info_type,
|
||||
transaction_id)),
|
||||
data)
|
||||
|
||||
@staticmethod
|
||||
def get_default_info_path(info_type, transaction_id):
|
||||
"""Generate default path for task additional info e.g. deployment info
|
||||
|
||||
:param info_type: deployment_info | cluster_settings |
|
||||
network_configuration
|
||||
:type info_type: str
|
||||
:param transaction_id: Transaction ID
|
||||
:type transaction_id: str or int
|
||||
:return: path
|
||||
:rtype: str
|
||||
"""
|
||||
return os.path.join(
|
||||
os.path.abspath(os.curdir),
|
||||
"{info_type}_{transaction_id}".format(
|
||||
info_type=info_type,
|
||||
transaction_id=transaction_id)
|
||||
)
|
||||
|
||||
def download_info_to_file(self, transaction_id, info_type, file_path):
|
||||
"""Get and save to path for task additional info e.g. deployment info
|
||||
|
||||
:param transaction_id: Transaction ID
|
||||
:type transaction_id: str or int
|
||||
:param info_type: deployment_info | cluster_settings |
|
||||
network_configuration
|
||||
:type info_type: str
|
||||
:param file_path: path
|
||||
:type file_path: str
|
||||
:return: path
|
||||
:rtype: str
|
||||
"""
|
||||
data = self.client.download(transaction_id=transaction_id)
|
||||
data_file_path = TaskMixIn.write_info_to_file(
|
||||
info_type,
|
||||
data,
|
||||
transaction_id,
|
||||
file_path)
|
||||
return data_file_path
|
||||
|
||||
|
||||
class TaskInfoFileMixIn(TaskMixIn):
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(TaskInfoFileMixIn, self).get_parser(
|
||||
prog_name)
|
||||
parser.add_argument('id', type=int, help='Id of the Task.')
|
||||
self.add_file_arg(parser)
|
||||
return parser
|
||||
|
||||
def download_info(self, parsed_args):
|
||||
data_file_path = self.download_info_to_file(
|
||||
transaction_id=parsed_args.id,
|
||||
info_type=self.info_type,
|
||||
file_path=parsed_args.file)
|
||||
|
||||
return data_file_path
|
||||
|
||||
|
||||
class TaskList(TaskMixIn, base.BaseListCommand):
|
||||
"""Show list of all available tasks."""
|
||||
@@ -85,3 +179,42 @@ class TaskHistoryShow(TaskMixIn, base.BaseListCommand):
|
||||
data = data_utils.get_display_data_multi(self.columns, data)
|
||||
|
||||
return (self.columns, data)
|
||||
|
||||
|
||||
class TaskNetworkConfigurationDownload(TaskInfoFileMixIn, base.BaseCommand):
|
||||
|
||||
entity_name = 'network-configuration'
|
||||
info_type = 'network_configuration'
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.app.stdout.write(
|
||||
"Network configuration for task with id={0}"
|
||||
" downloaded to {1}\n".format(parsed_args.id,
|
||||
self.download_info(parsed_args))
|
||||
)
|
||||
|
||||
|
||||
class TaskDeploymentInfoDownload(TaskInfoFileMixIn, base.BaseCommand):
|
||||
|
||||
entity_name = 'deployment-info'
|
||||
info_type = 'deployment_info'
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.app.stdout.write(
|
||||
"Deployment info for task with id={0}"
|
||||
" downloaded to {1}\n".format(parsed_args.id,
|
||||
self.download_info(parsed_args))
|
||||
)
|
||||
|
||||
|
||||
class TaskClusterSettingsDownload(TaskInfoFileMixIn, base.BaseCommand):
|
||||
|
||||
entity_name = 'cluster-settings'
|
||||
info_type = 'cluster_settings'
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.app.stdout.write(
|
||||
"Cluster settings for task with id={0}"
|
||||
" downloaded to {1}\n".format(parsed_args.id,
|
||||
self.download_info(parsed_args))
|
||||
)
|
||||
|
||||
@@ -23,6 +23,10 @@ class Task(BaseObject):
|
||||
|
||||
class_api_path = "transactions/"
|
||||
instance_api_path = "transactions/{0}/"
|
||||
info_types_url_map = {
|
||||
'deployment_info': 'deployment_info',
|
||||
'cluster_settings': 'settings',
|
||||
'network_configuration': 'network_configuration'}
|
||||
|
||||
def delete(self, force=False):
|
||||
return self.connection.delete_request(
|
||||
@@ -47,6 +51,31 @@ class Task(BaseObject):
|
||||
while not self.is_finished:
|
||||
sleep(0.5)
|
||||
|
||||
def deployment_info(self):
|
||||
return self.connection.get_request(
|
||||
self._get_additional_info_url('deployment_info'))
|
||||
|
||||
def network_configuration(self):
|
||||
return self.connection.get_request(
|
||||
self._get_additional_info_url('network_configuration'))
|
||||
|
||||
def cluster_settings(self):
|
||||
return self.connection.get_request(
|
||||
self._get_additional_info_url('cluster_settings'))
|
||||
|
||||
def _get_additional_info_url(self, info_type):
|
||||
"""Generate additional info url.
|
||||
|
||||
:param info_type: one of deployment_info, cluster_settings,
|
||||
network_configuration
|
||||
:type info_type: str
|
||||
:return: url
|
||||
:rtype: str
|
||||
"""
|
||||
|
||||
return self.instance_api_path.format(self.id) +\
|
||||
self.info_types_url_map[info_type]
|
||||
|
||||
|
||||
class DeployTask(Task):
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
# under the License.
|
||||
|
||||
import mock
|
||||
import yaml
|
||||
|
||||
from fuelclient.tests.unit.v2.cli import test_engine
|
||||
from fuelclient.tests import utils
|
||||
@@ -58,3 +59,41 @@ class TestTaskCommand(test_engine.BaseCLITest):
|
||||
self.m_client.get_all.assert_called_once_with(transaction_id=task_id,
|
||||
nodes=None,
|
||||
statuses=None)
|
||||
|
||||
def _test_cmd(self, cmd, method, cmd_line, client,
|
||||
return_data, expected_kwargs):
|
||||
self.m_get_client.reset_mock()
|
||||
self.m_client.get_filtered.reset_mock()
|
||||
self.m_client.__getattr__(method).return_value =\
|
||||
yaml.safe_load(return_data)
|
||||
m_open = mock.mock_open()
|
||||
with mock.patch('fuelclient.cli.serializers.open',
|
||||
m_open, create=True):
|
||||
self.exec_command('task {0} {1} {2}'.format(cmd, method,
|
||||
cmd_line))
|
||||
|
||||
written_yaml = yaml.safe_load(m_open().write.mock_calls[0][1][0])
|
||||
expected_yaml = yaml.safe_load(return_data)
|
||||
self.assertEqual(written_yaml, expected_yaml)
|
||||
|
||||
self.m_get_client.assert_called_once_with(client, mock.ANY)
|
||||
self.m_client.__getattr__(method).assert_called_once_with(
|
||||
**expected_kwargs)
|
||||
|
||||
def test_task_deployment_info_download(self):
|
||||
self._test_cmd('deployment-info', 'download', '1',
|
||||
'deployment-info',
|
||||
utils.get_fake_yaml_deployment_info(),
|
||||
dict(transaction_id=1))
|
||||
|
||||
def test_task_cluster_settings_download(self):
|
||||
self._test_cmd('settings', 'download', '1',
|
||||
'cluster-settings',
|
||||
utils.get_fake_yaml_cluster_settings(),
|
||||
dict(transaction_id=1))
|
||||
|
||||
def test_task_network_configuration_download(self):
|
||||
self._test_cmd('network-configuration', 'download', '1',
|
||||
'network-configuration',
|
||||
utils.get_fake_yaml_network_conf(),
|
||||
dict(transaction_id=1))
|
||||
|
||||
58
fuelclient/tests/unit/v2/lib/test_task_additional_info.py
Normal file
58
fuelclient/tests/unit/v2/lib/test_task_additional_info.py
Normal file
@@ -0,0 +1,58 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2016 Mirantis, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import yaml
|
||||
|
||||
import fuelclient
|
||||
from fuelclient.tests.unit.v2.lib import test_api
|
||||
from fuelclient.tests import utils
|
||||
|
||||
|
||||
class TestTaskAdditionalInfoFacade(test_api.BaseLibTest):
|
||||
|
||||
def setUp(self):
|
||||
super(TestTaskAdditionalInfoFacade, self).setUp()
|
||||
|
||||
self.version = 'v1'
|
||||
self.task_id = 42
|
||||
self.res_uri = (
|
||||
'/api/{version}/transactions/{task_id}/'.format(
|
||||
version=self.version, task_id=self.task_id))
|
||||
|
||||
def _test_info_download(self, client_name, yaml_data, uri):
|
||||
client = fuelclient.get_client(client_name, self.version)
|
||||
expected_body = yaml.load(yaml_data)
|
||||
matcher = self.m_request.get("{0}{1}".format(self.res_uri, uri),
|
||||
json=expected_body)
|
||||
result = client.download(self.task_id)
|
||||
|
||||
self.assertTrue(matcher.called)
|
||||
self.assertEqual(expected_body, result)
|
||||
|
||||
def test_network_configuration_download(self):
|
||||
self._test_info_download('network-configuration',
|
||||
utils.get_fake_yaml_network_conf(),
|
||||
'network_configuration')
|
||||
|
||||
def test_cluster_settings_download(self):
|
||||
self._test_info_download('cluster-settings',
|
||||
utils.get_fake_yaml_cluster_settings(),
|
||||
'settings')
|
||||
|
||||
def test_deployment_info_download(self):
|
||||
self._test_info_download('deployment-info',
|
||||
utils.get_fake_yaml_deployment_info(),
|
||||
'deployment_info')
|
||||
@@ -15,6 +15,12 @@
|
||||
# under the License.
|
||||
|
||||
from fuelclient.tests.utils.random_data import random_string
|
||||
from fuelclient.tests.utils.fake_additional_info \
|
||||
import get_fake_yaml_cluster_settings
|
||||
from fuelclient.tests.utils.fake_additional_info \
|
||||
import get_fake_yaml_deployment_info
|
||||
from fuelclient.tests.utils.fake_additional_info \
|
||||
import get_fake_yaml_network_conf
|
||||
from fuelclient.tests.utils.fake_deployment_history \
|
||||
import get_fake_deployment_history
|
||||
from fuelclient.tests.utils.fake_net_conf import get_fake_interface_config
|
||||
@@ -31,6 +37,9 @@ from fuelclient.tests.utils.fake_openstack_config \
|
||||
|
||||
|
||||
__all__ = (get_fake_deployment_history,
|
||||
get_fake_yaml_cluster_settings,
|
||||
get_fake_yaml_deployment_info,
|
||||
get_fake_yaml_network_conf,
|
||||
get_fake_env,
|
||||
get_fake_fuel_version,
|
||||
get_fake_interface_config,
|
||||
|
||||
90
fuelclient/tests/utils/fake_additional_info.py
Normal file
90
fuelclient/tests/utils/fake_additional_info.py
Normal file
@@ -0,0 +1,90 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2016 Mirantis, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
CLUSTER_SETTINGS = '''---
|
||||
editable:
|
||||
service_user:
|
||||
name:
|
||||
type: "hidden"
|
||||
value: "fuel"
|
||||
sudo:
|
||||
type: "hidden"
|
||||
value: "ALL=(ALL) NOPASSWD: ALL"
|
||||
homedir:
|
||||
type: "hidden"
|
||||
value: "/var/lib/fuel"
|
||||
'''
|
||||
|
||||
DEPLOYMENT_INFO = '''---
|
||||
glance_glare:
|
||||
user_password: yBw0bY60owLC1C0AplHpEiEX
|
||||
user_node_name: Untitled (5e:89)
|
||||
uid: '5'
|
||||
aodh:
|
||||
db_password: JnEjYacrjxU2TLdTUQE9LdKq
|
||||
user_password: 8MhyQgtWjWkl0Dv1r1worTjK
|
||||
mysql:
|
||||
root_password: bQhzpWjWIOTHOwEA4qNI8X4K
|
||||
wsrep_password: 01QSoq3bYHgA7oS0OPYQurgX
|
||||
murano-cfapi:
|
||||
db_password: hGrAhxUjv3kAPEjiV7uYNwgZ
|
||||
user_password: 43x0pvQMXugwd8JBaRSQXX4l
|
||||
enabled: false
|
||||
rabbit_password: ZqTnnw7lsGQNOFJRN6pTaI8t
|
||||
'''
|
||||
|
||||
NETWORK_CONF = '''---
|
||||
vips:
|
||||
vrouter_pub:
|
||||
network_role: "public/vip"
|
||||
ipaddr: "10.109.3.2"
|
||||
namespace: "vrouter"
|
||||
is_user_defined: false
|
||||
vendor_specific:
|
||||
iptables_rules:
|
||||
ns_start:
|
||||
- "iptables -t nat -A POSTROUTING -o <%INT%> -j MASQUERADE"
|
||||
'''
|
||||
|
||||
|
||||
def get_fake_yaml_cluster_settings():
|
||||
"""Create a fake cluster settings
|
||||
|
||||
Returns the serialized and parametrized representation of a dumped Fuel
|
||||
Cluster Settings. Represents the average amount of data.
|
||||
|
||||
"""
|
||||
return CLUSTER_SETTINGS
|
||||
|
||||
|
||||
def get_fake_yaml_deployment_info():
|
||||
"""Create a fake cluster settings
|
||||
|
||||
Returns the serialized and parametrized representation of a dumped Fuel
|
||||
Deployment Info. Represents the average amount of data.
|
||||
|
||||
"""
|
||||
return DEPLOYMENT_INFO
|
||||
|
||||
|
||||
def get_fake_yaml_network_conf():
|
||||
"""Create a fake cluster settings
|
||||
|
||||
Returns the serialized and parametrized representation of a dumped Fuel
|
||||
Network Conf. Represents the average amount of data.
|
||||
|
||||
"""
|
||||
return NETWORK_CONF
|
||||
@@ -12,10 +12,13 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from fuelclient.v1 import cluster_settings
|
||||
from fuelclient.v1 import deployment_history
|
||||
from fuelclient.v1 import deployment_info
|
||||
from fuelclient.v1 import environment
|
||||
from fuelclient.v1 import fuelversion
|
||||
from fuelclient.v1 import graph
|
||||
from fuelclient.v1 import network_configuration
|
||||
from fuelclient.v1 import network_group
|
||||
from fuelclient.v1 import node
|
||||
from fuelclient.v1 import openstack_config
|
||||
@@ -24,10 +27,13 @@ from fuelclient.v1 import task
|
||||
from fuelclient.v1 import vip
|
||||
|
||||
# Please keeps the list in alphabetical order
|
||||
__all__ = ('deployment_history',
|
||||
__all__ = ('cluster_settings',
|
||||
'deployment_history',
|
||||
'deployment_info',
|
||||
'environment',
|
||||
'fuelversion',
|
||||
'graph',
|
||||
'network_configuration',
|
||||
'network_group',
|
||||
'node',
|
||||
'openstack_config',
|
||||
|
||||
31
fuelclient/v1/cluster_settings.py
Normal file
31
fuelclient/v1/cluster_settings.py
Normal file
@@ -0,0 +1,31 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2016 Mirantis, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from fuelclient import objects
|
||||
from fuelclient.v1 import base_v1
|
||||
|
||||
|
||||
class ClusterSettingsClient(base_v1.BaseV1Client):
|
||||
|
||||
_entity_wrapper = objects.Task
|
||||
|
||||
def download(self, transaction_id):
|
||||
task = self._entity_wrapper(transaction_id)
|
||||
return task.cluster_settings()
|
||||
|
||||
|
||||
def get_client():
|
||||
return ClusterSettingsClient()
|
||||
31
fuelclient/v1/deployment_info.py
Normal file
31
fuelclient/v1/deployment_info.py
Normal file
@@ -0,0 +1,31 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2016 Mirantis, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from fuelclient import objects
|
||||
from fuelclient.v1 import base_v1
|
||||
|
||||
|
||||
class DeploymentInfoClient(base_v1.BaseV1Client):
|
||||
|
||||
_entity_wrapper = objects.Task
|
||||
|
||||
def download(self, transaction_id):
|
||||
task = self._entity_wrapper(transaction_id)
|
||||
return task.deployment_info()
|
||||
|
||||
|
||||
def get_client():
|
||||
return DeploymentInfoClient()
|
||||
31
fuelclient/v1/network_configuration.py
Normal file
31
fuelclient/v1/network_configuration.py
Normal file
@@ -0,0 +1,31 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2016 Mirantis, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from fuelclient import objects
|
||||
from fuelclient.v1 import base_v1
|
||||
|
||||
|
||||
class NetworkConfigurationClient(base_v1.BaseV1Client):
|
||||
|
||||
_entity_wrapper = objects.Task
|
||||
|
||||
def download(self, transaction_id):
|
||||
task = self._entity_wrapper(transaction_id)
|
||||
return task.network_configuration()
|
||||
|
||||
|
||||
def get_client():
|
||||
return NetworkConfigurationClient()
|
||||
@@ -66,6 +66,9 @@ fuelclient =
|
||||
task_list=fuelclient.commands.task:TaskList
|
||||
task_show=fuelclient.commands.task:TaskShow
|
||||
task_history_show=fuelclient.commands.task:TaskHistoryShow
|
||||
task_settings_download=fuelclient.commands.task:TaskClusterSettingsDownload
|
||||
task_deployment-info_download=fuelclient.commands.task:TaskDeploymentInfoDownload
|
||||
task_network-configuration_download=fuelclient.commands.task:TaskNetworkConfigurationDownload
|
||||
openstack-config_list=fuelclient.commands.openstack_config:OpenstackConfigList
|
||||
openstack-config_upload=fuelclient.commands.openstack_config:OpenstackConfigUpload
|
||||
openstack-config_download=fuelclient.commands.openstack_config:OpenstackConfigDownload
|
||||
|
||||
Reference in New Issue
Block a user