Files
deb-python-fuelclient/fuelclient/commands/graph.py
Ilya Kutukov 85311221ca Add custom graph download and list support to the Fuel V2 CLI
Following commands are added:

* fuel2 graph download --env env_id --all [--type graph_type] [--file cluster_graph.yaml]

* fuel2 graph download --env env_id --cluster [--type graph_type] [--file cluster_graph.yaml]

* fuel2 graph download --env env_id --plugins [--type graph_type] [--file plugins_graph.yaml]

* fuel2 graph download --env env_id --release [--type graph_type] [--file release_graph.yaml]

--type is optional and ‘default’ graph will be downloaded in no type is
defined.

* fuel2 graph list --env env_id

Change-Id: Iba9255f2b201ffc54e81e0f15ba7b9e415ef63ba
Closes-Bug: #1563851
DocImpact
2016-04-07 13:41:37 +00:00

283 lines
10 KiB
Python

# -*- 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 os
from fuelclient.cli import error
from fuelclient.cli.serializers import Serializer
from fuelclient.commands import base
from fuelclient.common import data_utils
class FileMethodsMixin(object):
@classmethod
def check_file_path(cls, file_path):
if not os.path.exists(file_path):
raise error.InvalidFileException(
"File '{0}' doesn't exist.".format(file_path))
@classmethod
def check_dir(cls, directory):
if not os.path.exists(directory):
raise error.InvalidDirectoryException(
"Directory '{0}' doesn't exist.".format(directory))
if not os.path.isdir(directory):
raise error.InvalidDirectoryException(
"Error: '{0}' is not a directory.".format(directory))
class GraphUpload(base.BaseCommand, FileMethodsMixin):
"""Upload deployment graph configuration."""
entity_name = 'graph'
@classmethod
def read_tasks_data_from_file(cls, file_path=None, serializer=None):
"""Read Tasks data from given path.
:param file_path: path
:type file_path: str
:param serializer: serializer object
:type serializer: object
:return: data
:rtype: list|object
"""
cls.check_file_path(file_path)
return (serializer or Serializer()).read_from_full_path(file_path)
def get_parser(self, prog_name):
parser = super(GraphUpload, self).get_parser(prog_name)
graph_class = parser.add_mutually_exclusive_group()
graph_class.add_argument('-e',
'--env',
type=int,
required=False,
help='Id of the environment')
graph_class.add_argument('-r',
'--release',
type=int,
required=False,
help='Id of the release')
graph_class.add_argument('-p',
'--plugin',
type=int,
required=False,
help='Id of the plugin')
parser.add_argument('-t',
'--type',
type=str,
default=None,
required=False,
help='Type of the deployment graph')
parser.add_argument('-f',
'--file',
type=str,
required=True,
default=None,
help='YAML file that contains '
'deployment graph data.')
return parser
def take_action(self, args):
parameters_to_graph_class = (
('env', 'clusters'),
('release', 'releases'),
('plugin', 'plugins'),
)
for parameter, graph_class in parameters_to_graph_class:
model_id = getattr(args, parameter)
if model_id:
self.client.upload(
data=self.read_tasks_data_from_file(args.file),
related_model=graph_class,
related_id=model_id,
graph_type=args.type
)
break
self.app.stdout.write(
"Deployment graph was uploaded from {0}\n".format(args.file)
)
class GraphExecute(base.BaseCommand):
"""Start deployment with given graph type."""
entity_name = 'graph'
def get_parser(self, prog_name):
parser = super(GraphExecute, self).get_parser(prog_name)
parser.add_argument('-e',
'--env',
type=int,
required=True,
help='Id of the environment')
parser.add_argument('-t',
'--type',
type=str,
default=None,
required=False,
help='Type of the deployment graph')
parser.add_argument('-n',
'--nodes',
type=int,
nargs='+',
required=False,
help='Ids of the nodes to use for deployment.')
return parser
def take_action(self, args):
self.client.execute(
env_id=args.env,
graph_type=args.type,
nodes=args.nodes
)
self.app.stdout.write(
"Deployment was executed\n"
)
class GraphDownload(base.BaseCommand):
"""Download deployment graph configuration."""
entity_name = 'graph'
def get_parser(self, prog_name):
parser = super(GraphDownload, self).get_parser(prog_name)
tasks_level = parser.add_mutually_exclusive_group()
parser.add_argument('-e',
'--env',
type=int,
required=True,
help='Id of the environment')
tasks_level.add_argument('-a',
'--all',
action="store_true",
required=False,
default=False,
help='Download merged graph for the '
'environment')
tasks_level.add_argument('-c',
'--cluster',
action="store_true",
required=False,
default=False,
help='Download cluster-specific tasks')
tasks_level.add_argument('-p',
'--plugins',
action="store_true",
required=False,
default=False,
help='Download plugins-specific tasks')
tasks_level.add_argument('-r',
'--release',
action="store_true",
required=False,
default=False,
help='Download release-specific tasks')
parser.add_argument('-t',
'--type',
type=str,
default=None,
required=False,
help='Graph type string')
parser.add_argument('-f',
'--file',
type=str,
required=False,
default=None,
help='YAML file that contains tasks data.')
return parser
@classmethod
def get_default_tasks_data_path(cls):
return os.path.join(
os.path.abspath(os.curdir),
"cluster_graph"
)
@classmethod
def write_tasks_to_file(cls, tasks_data, serializer=None, file_path=None):
serializer = serializer or Serializer()
if file_path:
return serializer.write_to_full_path(
file_path,
tasks_data
)
else:
return serializer.write_to_path(
cls.get_default_tasks_data_path(),
tasks_data
)
def take_action(self, args):
tasks_data = []
for tasks_level_name in ('all', 'cluster', 'release', 'plugins'):
if getattr(args, tasks_level_name):
tasks_data = self.client.download(
env_id=args.env,
level=tasks_level_name,
graph_type=args.type
)
break
# write to file
graph_data_file_path = self.write_tasks_to_file(
tasks_data=tasks_data,
serializer=Serializer(),
file_path=args.file)
self.app.stdout.write(
"Tasks were downloaded to {0}\n".format(graph_data_file_path)
)
class GraphList(base.BaseListCommand):
"""Upload deployment graph configuration."""
entity_name = 'graph'
columns = ("id",
"name",
"tasks",
"relations")
def get_parser(self, prog_name):
parser = super(GraphList, self).get_parser(prog_name)
parser.add_argument('-e',
'--env',
type=int,
required=True,
help='Id of the environment')
return parser
def take_action(self, parsed_args):
data = self.client.list(
env_id=parsed_args.env
)
# format fields
for d in data:
d['relations'] = "\n".join(
'as "{type}" to {model}(ID={model_id})'
.format(**r) for r in d['relations']
)
d['tasks'] = ', '.join(sorted(t['id'] for t in d['tasks']))
data = data_utils.get_display_data_multi(self.columns, data)
scolumn_ids = [self.columns.index(col)
for col in parsed_args.sort_columns]
data.sort(key=lambda x: [x[scolumn_id] for scolumn_id in scolumn_ids])
return self.columns, data