From eee0ff4aed05865f8ba399dcad0ca4deea6a3e96 Mon Sep 17 00:00:00 2001 From: Alexandr Notchenko Date: Mon, 14 Apr 2014 21:18:28 +0400 Subject: [PATCH] File Serialization problem * Fixed serialization with flags * Fixed several command stdout messages * Fixed empty facts exception Closes-bug: #1307577 Closes-bug: #1307516 Change-Id: Iecbd12959c4f8e707249c6a58df0cc5e432fd1df --- fuelclient/cli/actions/fact.py | 44 ++++++++------- fuelclient/cli/actions/network.py | 19 +++---- fuelclient/cli/actions/node.py | 22 ++++---- fuelclient/cli/actions/settings.py | 25 ++++----- fuelclient/cli/error.py | 4 ++ fuelclient/objects/environment.py | 81 +++++++++++++++------------- fuelclient/objects/node.py | 9 ++-- tests/test_client.py | 86 +++++++++++++++++++++--------- 8 files changed, 177 insertions(+), 113 deletions(-) diff --git a/fuelclient/cli/actions/fact.py b/fuelclient/cli/actions/fact.py index f28d8ab..022ece7 100644 --- a/fuelclient/cli/actions/fact.py +++ b/fuelclient/cli/actions/fact.py @@ -19,6 +19,9 @@ from fuelclient.objects.environment import Environment class FactAction(Action): + + action_name = None + def __init__(self): super(FactAction, self).__init__() self.args = [ @@ -61,10 +64,17 @@ class FactAction(Action): fuel --env 1 {action_name} --default --node 1,2,3 """ env = Environment(params.env) - env.write_facts_to_dir( + dir_name = env.write_facts_to_dir( self.action_name, env.get_default_facts(self.action_name, nodes=params.node), - directory=params.dir + directory=params.dir, + serializer=self.serializer + ) + print( + "Default {0} info was downloaded to {1}".format( + self.action_name, + dir_name + ) ) def upload(self, params): @@ -72,15 +82,13 @@ class FactAction(Action): fuel --env 1 {action_name} --upload """ env = Environment(params.env) - facts = getattr(env, self.read_method_name)( + facts = env.read_fact_info( self.action_name, - directory=params.dir + directory=params.dir, + serializer=self.serializer ) env.upload_facts(self.action_name, facts) - self.serializer.print_to_output( - facts, - "{0} facts uploaded.".format(self.action_name) - ) + print("{0} facts were uploaded.".format(self.action_name)) def delete(self, params): """Also {action_name} information can be left or @@ -90,25 +98,25 @@ class FactAction(Action): """ env = Environment(params.env) env.delete_facts(self.action_name) - self.serializer.print_to_output( - {}, - "{0} facts deleted.".format(self.action_name) - ) + print("{0} facts deleted.".format(self.action_name)) def download(self, params): """To download {action_name} information for some environment: fuel --env 1 {action_name} --download """ env = Environment(params.env) - env.write_facts_to_dir( + dir_name = env.write_facts_to_dir( self.action_name, env.get_facts(self.action_name, nodes=params.node), - directory=params.dir + directory=params.dir, + serializer=self.serializer + ) + print( + "Current {0} info was downloaded to {1}".format( + self.action_name, + dir_name + ) ) - - @property - def read_method_name(self): - return "read_{0}_info".format(self.action_name) class DeploymentAction(FactAction): diff --git a/fuelclient/cli/actions/network.py b/fuelclient/cli/actions/network.py index 5e56e23..31f4c25 100644 --- a/fuelclient/cli/actions/network.py +++ b/fuelclient/cli/actions/network.py @@ -50,10 +50,12 @@ class NetworkAction(Action): fuel --env 1 network --upload --dir path/to/derectory """ env = Environment(params.env) - network_data = env.read_network_data(directory=params.dir) - response = env.set_network_data(network_data) - self.serializer.print_to_output( - response, + network_data = env.read_network_data( + directory=params.dir, + serializer=self.serializer + ) + env.set_network_data(network_data) + print( "Network configuration uploaded." ) @@ -64,8 +66,7 @@ class NetworkAction(Action): """ env = Environment(params.env) response = env.verify_network() - self.serializer.print_to_output( - response, + print( "Verification status is '{status}'. message: {message}" .format(**response) ) @@ -79,9 +80,9 @@ class NetworkAction(Action): network_data = env.get_network_data() network_file_path = env.write_network_data( network_data, - directory=params.dir) - self.serializer.print_to_output( - network_data, + directory=params.dir, + serializer=self.serializer) + print( "Network configuration for environment with id={0}" " downloaded to {1}" .format(env.id, network_file_path) diff --git a/fuelclient/cli/actions/node.py b/fuelclient/cli/actions/node.py index 32aac36..f947cf8 100644 --- a/fuelclient/cli/actions/node.py +++ b/fuelclient/cli/actions/node.py @@ -23,7 +23,6 @@ from fuelclient.cli.arguments import group from fuelclient.cli.error import ActionException from fuelclient.cli.error import ArgumentException from fuelclient.cli.formatting import format_table -from fuelclient.cli.formatting import quote_and_join from fuelclient.objects.environment import Environment from fuelclient.objects.node import Node from fuelclient.objects.node import NodeCollection @@ -159,15 +158,20 @@ class NodeAction(Action): file_path = node.write_attribute( attribute_type, default_attribute, - params.dir + params.dir, + serializer=self.serializer ) files.append(file_path) attributes.append(default_attribute) message = "Default node attributes for {0} were written" \ - " to {1}".format(attribute_type, quote_and_join(files)) + " to:\n{1}".format(attribute_type, "\n".join(files)) elif params.upload: for node in nodes: - attribute = node.read_attribute(attribute_type, params.dir) + attribute = node.read_attribute( + attribute_type, + params.dir, + serializer=self.serializer + ) node.upload_node_attribute( attribute_type, attribute @@ -181,16 +185,14 @@ class NodeAction(Action): file_path = node.write_attribute( attribute_type, downloaded_attribute, - params.dir + params.dir, + serializer=self.serializer ) attributes.append(downloaded_attribute) files.append(file_path) message = "Node attributes for {0} were written" \ - " to {1}".format(attribute_type, quote_and_join(files)) - self.serializer.print_to_output( - attributes, - message - ) + " to:\n{1}".format(attribute_type, "\n".join(files)) + print(message) @check_all("env", "node") def start(self, params): diff --git a/fuelclient/cli/actions/settings.py b/fuelclient/cli/actions/settings.py index 7c26db9..ed4f88b 100644 --- a/fuelclient/cli/actions/settings.py +++ b/fuelclient/cli/actions/settings.py @@ -30,7 +30,8 @@ class SettingsAction(Action): group( Args.get_download_arg("Modify current configuration."), Args.get_default_arg("Open default configuration."), - Args.get_upload_arg("Save current changes in configuration.") + Args.get_upload_arg("Save current changes in configuration."), + required=True ), Args.get_dir_arg("Directory with configuration data.") ) @@ -45,12 +46,12 @@ class SettingsAction(Action): fuel --env 1 settings --upload --dir path/to/derectory """ env = Environment(params.env) - network_data = env.read_settings_data(directory=params.dir) - response = env.set_settings_data(network_data) - self.serializer.print_to_output( - response, - "Settings configuration uploaded." + settings_data = env.read_settings_data( + directory=params.dir, + serializer=self.serializer ) + env.set_settings_data(settings_data) + print("Settings configuration uploaded.") def default(self, params): """To download default settings for some environment in some directory: @@ -60,9 +61,9 @@ class SettingsAction(Action): default_data = env.get_default_settings_data() settings_file_path = env.write_settings_data( default_data, - directory=params.dir) - self.serializer.print_to_output( - default_data, + directory=params.dir, + serializer=self.serializer) + print( "Default settings configuration downloaded to {0}." .format(settings_file_path) ) @@ -75,9 +76,9 @@ class SettingsAction(Action): settings_data = env.get_settings_data() settings_file_path = env.write_settings_data( settings_data, - directory=params.dir) - self.serializer.print_to_output( - settings_data, + directory=params.dir, + serializer=self.serializer) + print( "Settings configuration for environment with id={0}" " downloaded to {1}" .format(env.id, settings_file_path) diff --git a/fuelclient/cli/error.py b/fuelclient/cli/error.py index bb9da1a..6c2c489 100644 --- a/fuelclient/cli/error.py +++ b/fuelclient/cli/error.py @@ -26,6 +26,10 @@ class FuelClientException(Exception): pass +class ServerDataException(FuelClientException): + pass + + class DeployProgressError(FuelClientException): pass diff --git a/fuelclient/objects/environment.py b/fuelclient/objects/environment.py index 9f4513b..f500fc9 100644 --- a/fuelclient/objects/environment.py +++ b/fuelclient/objects/environment.py @@ -18,21 +18,10 @@ import shutil from fuelclient.cli.error import ActionException from fuelclient.cli.error import ArgumentException +from fuelclient.cli.error import ServerDataException from fuelclient.cli.serializers import listdir_without_extensions from fuelclient.objects.base import BaseObject from fuelclient.objects.task import DeployTask -from functools import wraps - - -def memorize_one(func): - func.cache = None - - @wraps(func) - def nested(*args, **kwargs): - if func.cache is None: - func.cache = func(*args, **kwargs) - return func.cache - return nested class Environment(BaseObject): @@ -129,25 +118,30 @@ class Environment(BaseObject): "settings_{0}".format(self.id) ) - def write_network_data(self, network_data, directory=os.curdir): - return self.serializer.write_to_file( + def write_network_data(self, network_data, directory=os.curdir, + serializer=None): + return (serializer or self.serializer).write_to_file( self.get_network_data_path(directory), network_data ) - def write_settings_data(self, settings_data, directory=os.curdir): - return self.serializer.write_to_file( + def write_settings_data(self, settings_data, directory=os.curdir, + serializer=None): + return (serializer or self.serializer).write_to_file( self.get_settings_data_path(directory), settings_data ) - def read_network_data(self, directory=os.curdir): + def read_network_data(self, directory=os.curdir, + serializer=None): network_file_path = self.get_network_data_path(directory) - return self.serializer.read_from_file(network_file_path) + return (serializer or self.serializer).read_from_file( + network_file_path) - def read_settings_data(self, directory=os.curdir): + def read_settings_data(self, directory=os.curdir, serializer=None): settings_file_path = self.get_settings_data_path(directory) - return self.serializer.read_from_file(settings_file_path) + return (serializer or self.serializer).read_from_file( + settings_file_path) @property def settings_url(self): @@ -158,7 +152,6 @@ class Environment(BaseObject): return self.settings_url + "/defaults" @property - @memorize_one def network_url(self): return "clusters/{id}/network_configuration/{net_provider}".format( **self.data @@ -213,12 +206,24 @@ class Environment(BaseObject): return fact_url def get_default_facts(self, fact_type, nodes=None): - return self.connection.get_request( + facts = self.connection.get_request( self._get_fact_default_url(fact_type, nodes=nodes)) + if not facts: + raise ServerDataException( + "There is no {0} info for this " + "environment!".format(fact_type) + ) + return facts def get_facts(self, fact_type, nodes=None): - return self.connection.get_request( + facts = self.connection.get_request( self._get_fact_url(fact_type, nodes=nodes)) + if not facts: + raise ServerDataException( + "There is no {0} info for this " + "environment!".format(fact_type) + ) + return facts def upload_facts(self, fact_type, facts): self.connection.put_request(self._get_fact_url(fact_type), facts) @@ -226,20 +231,21 @@ class Environment(BaseObject): def delete_facts(self, fact_type): self.connection.delete_request(self._get_fact_url(fact_type)) - def read_fact_info(self, fact_type): - if fact_type == "deployment": - return self.read_deployment_info(fact_type) - elif fact_type == "provisioning": - return self.read_provisioning_info(fact_type) + def read_fact_info(self, fact_type, directory, serializer=None): + return getattr( + self, "read_{0}_info".format(fact_type) + )(fact_type, directory=directory, serializer=serializer) - def write_facts_to_dir(self, fact_type, facts, directory=os.path.curdir): + def write_facts_to_dir(self, fact_type, facts, + directory=os.path.curdir, serializer=None): dir_name = self._get_fact_dir_name(fact_type, directory=directory) if os.path.exists(dir_name): shutil.rmtree(dir_name) os.makedirs(dir_name) if isinstance(facts, dict): engine_file_path = os.path.join(dir_name, "engine") - self.serializer.write_to_file(engine_file_path, facts["engine"]) + (serializer or self.serializer).write_to_file( + engine_file_path, facts["engine"]) facts = facts["nodes"] name_template = "{name}" else: @@ -249,25 +255,28 @@ class Environment(BaseObject): dir_name, name_template.format(**_fact) ) - self.serializer.write_to_file(fact_path, _fact) + (serializer or self.serializer).write_to_file(fact_path, _fact) + return dir_name - def read_deployment_info(self, fact_type, directory=os.path.curdir): + def read_deployment_info(self, fact_type, + directory=os.path.curdir, serializer=None): dir_name = self._get_fact_dir_name(fact_type, directory=directory) return map( - lambda f: self.serializer.read_from_file(f), + lambda f: (serializer or self.serializer).read_from_file(f), [os.path.join(dir_name, json_file) for json_file in listdir_without_extensions(dir_name)] ) - def read_provisioning_info(self, fact_type, directory=os.path.curdir): + def read_provisioning_info(self, fact_type, + directory=os.path.curdir, serializer=None): dir_name = self._get_fact_dir_name(fact_type, directory=directory) node_facts = map( - lambda f: self.serializer.read_from_file(f), + lambda f: (serializer or self.serializer).read_from_file(f), [os.path.join(dir_name, fact_file) for fact_file in listdir_without_extensions(dir_name) if "engine" != fact_file] ) - engine = self.serializer.read_from_file( + engine = (serializer or self.serializer).read_from_file( os.path.join(dir_name, "engine")) return { "engine": engine, diff --git a/fuelclient/objects/node.py b/fuelclient/objects/node.py index 2169fcf..c8917a1 100644 --- a/fuelclient/objects/node.py +++ b/fuelclient/objects/node.py @@ -87,7 +87,8 @@ class Node(BaseObject): attributes ) - def write_attribute(self, attribute_type, attributes, directory): + def write_attribute(self, attribute_type, attributes, + directory, serializer=None): attributes_directory = self.get_attributes_path(directory) if not os.path.exists(attributes_directory): os.mkdir(attributes_directory) @@ -97,19 +98,19 @@ class Node(BaseObject): ) if os.path.exists(attribute_path): os.remove(attribute_path) - self.serializer.write_to_file( + return (serializer or self.serializer).write_to_file( attribute_path, attributes ) - def read_attribute(self, attributes_type, directory): + def read_attribute(self, attributes_type, directory, serializer=None): attributes_directory = self.get_attributes_path(directory) if not os.path.exists(attributes_directory): exit_with_error( "Folder {0} doesn't contain node folder '{1}'" .format(directory, "node_{0}".format(self.id)) ) - return self.serializer.read_from_file( + return (serializer or self.serializer).read_from_file( os.path.join( attributes_directory, attributes_type diff --git a/tests/test_client.py b/tests/test_client.py index c62bd2c..9ec3fae 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -118,38 +118,76 @@ class TestFiles(BaseTestCase): "--env-id=1 node set --node 2,3 --role=compute" )) for action in ("network", "settings"): - self.check_if_files_created( - "--env 1 {0} --download".format(action), - ("{0}_1.yaml".format(action),) - ) - deployment_provision_files = { - "--env 1 deployment --default": ( - "deployment_1", - "deployment_1/primary-controller_1.yaml", - "deployment_1/compute_2.yaml", - "deployment_1/compute_3.yaml" + for format_ in ("yaml", "json"): + self.check_if_files_created( + "--env 1 {0} --download --{1}".format(action, format_), + ("{0}_1.{1}".format(action, format_),) + ) + command_to_files_map = ( + ( + "--env 1 deployment --default", + ( + "deployment_1", + "deployment_1/primary-controller_1.yaml", + "deployment_1/compute_2.yaml", + "deployment_1/compute_3.yaml" + ) + ), + ( + "--env 1 provisioning --default", + ( + "provisioning_1", + "provisioning_1/engine.yaml", + "provisioning_1/node-1.yaml", + "provisioning_1/node-2.yaml", + "provisioning_1/node-3.yaml" + ) + ), + ( + "--env 1 deployment --default --json", + ( + "deployment_1/primary-controller_1.json", + "deployment_1/compute_2.json", + "deployment_1/compute_3.json" + ) + ), + ( + "--env 1 provisioning --default --json", + ( + "provisioning_1/engine.json", + "provisioning_1/node-1.json", + "provisioning_1/node-2.json", + "provisioning_1/node-3.json" + ) ), - "--env 1 provisioning --default": ( - "provisioning_1", - "provisioning_1/engine.yaml", - "provisioning_1/node-1.yaml", - "provisioning_1/node-2.yaml", - "provisioning_1/node-3.yaml" - ) - } - for command, files in deployment_provision_files.iteritems(): - self.check_if_files_created(command, files) - node_configs = ( ( "node --node 1 --disk --default", - ("node_1", "node_1/disks.yaml") + ( + "node_1", + "node_1/disks.yaml" + ) ), ( "node --node 1 --network --default", - ("node_1", "node_1/interfaces.yaml") + ( + "node_1", + "node_1/interfaces.yaml" + ) + ), + ( + "node --node 1 --disk --default --json", + ( + "node_1/disks.json", + ) + ), + ( + "node --node 1 --network --default --json", + ( + "node_1/interfaces.json", + ) ) ) - for command, files in node_configs: + for command, files in command_to_files_map: self.check_if_files_created(command, files) def check_if_files_created(self, command, paths):