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
This commit is contained in:
Alexandr Notchenko 2014-04-14 21:18:28 +04:00
parent fc1e74185c
commit cf54bd27a0
8 changed files with 177 additions and 113 deletions

View File

@ -19,6 +19,9 @@ from fuelclient.objects.environment import Environment
class FactAction(Action): class FactAction(Action):
action_name = None
def __init__(self): def __init__(self):
super(FactAction, self).__init__() super(FactAction, self).__init__()
self.args = [ self.args = [
@ -61,10 +64,17 @@ class FactAction(Action):
fuel --env 1 {action_name} --default --node 1,2,3 fuel --env 1 {action_name} --default --node 1,2,3
""" """
env = Environment(params.env) env = Environment(params.env)
env.write_facts_to_dir( dir_name = env.write_facts_to_dir(
self.action_name, self.action_name,
env.get_default_facts(self.action_name, nodes=params.node), 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): def upload(self, params):
@ -72,15 +82,13 @@ class FactAction(Action):
fuel --env 1 {action_name} --upload fuel --env 1 {action_name} --upload
""" """
env = Environment(params.env) env = Environment(params.env)
facts = getattr(env, self.read_method_name)( facts = env.read_fact_info(
self.action_name, self.action_name,
directory=params.dir directory=params.dir,
serializer=self.serializer
) )
env.upload_facts(self.action_name, facts) env.upload_facts(self.action_name, facts)
self.serializer.print_to_output( print("{0} facts were uploaded.".format(self.action_name))
facts,
"{0} facts uploaded.".format(self.action_name)
)
def delete(self, params): def delete(self, params):
"""Also {action_name} information can be left or """Also {action_name} information can be left or
@ -90,25 +98,25 @@ class FactAction(Action):
""" """
env = Environment(params.env) env = Environment(params.env)
env.delete_facts(self.action_name) env.delete_facts(self.action_name)
self.serializer.print_to_output( print("{0} facts deleted.".format(self.action_name))
{},
"{0} facts deleted.".format(self.action_name)
)
def download(self, params): def download(self, params):
"""To download {action_name} information for some environment: """To download {action_name} information for some environment:
fuel --env 1 {action_name} --download fuel --env 1 {action_name} --download
""" """
env = Environment(params.env) env = Environment(params.env)
env.write_facts_to_dir( dir_name = env.write_facts_to_dir(
self.action_name, self.action_name,
env.get_facts(self.action_name, nodes=params.node), 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): class DeploymentAction(FactAction):

View File

@ -50,10 +50,12 @@ class NetworkAction(Action):
fuel --env 1 network --upload --dir path/to/derectory fuel --env 1 network --upload --dir path/to/derectory
""" """
env = Environment(params.env) env = Environment(params.env)
network_data = env.read_network_data(directory=params.dir) network_data = env.read_network_data(
response = env.set_network_data(network_data) directory=params.dir,
self.serializer.print_to_output( serializer=self.serializer
response, )
env.set_network_data(network_data)
print(
"Network configuration uploaded." "Network configuration uploaded."
) )
@ -64,8 +66,7 @@ class NetworkAction(Action):
""" """
env = Environment(params.env) env = Environment(params.env)
response = env.verify_network() response = env.verify_network()
self.serializer.print_to_output( print(
response,
"Verification status is '{status}'. message: {message}" "Verification status is '{status}'. message: {message}"
.format(**response) .format(**response)
) )
@ -79,9 +80,9 @@ class NetworkAction(Action):
network_data = env.get_network_data() network_data = env.get_network_data()
network_file_path = env.write_network_data( network_file_path = env.write_network_data(
network_data, network_data,
directory=params.dir) directory=params.dir,
self.serializer.print_to_output( serializer=self.serializer)
network_data, print(
"Network configuration for environment with id={0}" "Network configuration for environment with id={0}"
" downloaded to {1}" " downloaded to {1}"
.format(env.id, network_file_path) .format(env.id, network_file_path)

View File

@ -23,7 +23,6 @@ from fuelclient.cli.arguments import group
from fuelclient.cli.error import ActionException from fuelclient.cli.error import ActionException
from fuelclient.cli.error import ArgumentException from fuelclient.cli.error import ArgumentException
from fuelclient.cli.formatting import format_table from fuelclient.cli.formatting import format_table
from fuelclient.cli.formatting import quote_and_join
from fuelclient.objects.environment import Environment from fuelclient.objects.environment import Environment
from fuelclient.objects.node import Node from fuelclient.objects.node import Node
from fuelclient.objects.node import NodeCollection from fuelclient.objects.node import NodeCollection
@ -159,15 +158,20 @@ class NodeAction(Action):
file_path = node.write_attribute( file_path = node.write_attribute(
attribute_type, attribute_type,
default_attribute, default_attribute,
params.dir params.dir,
serializer=self.serializer
) )
files.append(file_path) files.append(file_path)
attributes.append(default_attribute) attributes.append(default_attribute)
message = "Default node attributes for {0} were written" \ 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: elif params.upload:
for node in nodes: 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( node.upload_node_attribute(
attribute_type, attribute_type,
attribute attribute
@ -181,16 +185,14 @@ class NodeAction(Action):
file_path = node.write_attribute( file_path = node.write_attribute(
attribute_type, attribute_type,
downloaded_attribute, downloaded_attribute,
params.dir params.dir,
serializer=self.serializer
) )
attributes.append(downloaded_attribute) attributes.append(downloaded_attribute)
files.append(file_path) files.append(file_path)
message = "Node attributes for {0} were written" \ message = "Node attributes for {0} were written" \
" to {1}".format(attribute_type, quote_and_join(files)) " to:\n{1}".format(attribute_type, "\n".join(files))
self.serializer.print_to_output( print(message)
attributes,
message
)
@check_all("env", "node") @check_all("env", "node")
def start(self, params): def start(self, params):

View File

@ -30,7 +30,8 @@ class SettingsAction(Action):
group( group(
Args.get_download_arg("Modify current configuration."), Args.get_download_arg("Modify current configuration."),
Args.get_default_arg("Open default 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.") Args.get_dir_arg("Directory with configuration data.")
) )
@ -45,12 +46,12 @@ class SettingsAction(Action):
fuel --env 1 settings --upload --dir path/to/derectory fuel --env 1 settings --upload --dir path/to/derectory
""" """
env = Environment(params.env) env = Environment(params.env)
network_data = env.read_settings_data(directory=params.dir) settings_data = env.read_settings_data(
response = env.set_settings_data(network_data) directory=params.dir,
self.serializer.print_to_output( serializer=self.serializer
response,
"Settings configuration uploaded."
) )
env.set_settings_data(settings_data)
print("Settings configuration uploaded.")
def default(self, params): def default(self, params):
"""To download default settings for some environment in some directory: """To download default settings for some environment in some directory:
@ -60,9 +61,9 @@ class SettingsAction(Action):
default_data = env.get_default_settings_data() default_data = env.get_default_settings_data()
settings_file_path = env.write_settings_data( settings_file_path = env.write_settings_data(
default_data, default_data,
directory=params.dir) directory=params.dir,
self.serializer.print_to_output( serializer=self.serializer)
default_data, print(
"Default settings configuration downloaded to {0}." "Default settings configuration downloaded to {0}."
.format(settings_file_path) .format(settings_file_path)
) )
@ -75,9 +76,9 @@ class SettingsAction(Action):
settings_data = env.get_settings_data() settings_data = env.get_settings_data()
settings_file_path = env.write_settings_data( settings_file_path = env.write_settings_data(
settings_data, settings_data,
directory=params.dir) directory=params.dir,
self.serializer.print_to_output( serializer=self.serializer)
settings_data, print(
"Settings configuration for environment with id={0}" "Settings configuration for environment with id={0}"
" downloaded to {1}" " downloaded to {1}"
.format(env.id, settings_file_path) .format(env.id, settings_file_path)

View File

@ -26,6 +26,10 @@ class FuelClientException(Exception):
pass pass
class ServerDataException(FuelClientException):
pass
class DeployProgressError(FuelClientException): class DeployProgressError(FuelClientException):
pass pass

View File

@ -18,21 +18,10 @@ import shutil
from fuelclient.cli.error import ActionException from fuelclient.cli.error import ActionException
from fuelclient.cli.error import ArgumentException from fuelclient.cli.error import ArgumentException
from fuelclient.cli.error import ServerDataException
from fuelclient.cli.serializers import listdir_without_extensions from fuelclient.cli.serializers import listdir_without_extensions
from fuelclient.objects.base import BaseObject from fuelclient.objects.base import BaseObject
from fuelclient.objects.task import DeployTask 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): class Environment(BaseObject):
@ -129,25 +118,30 @@ class Environment(BaseObject):
"settings_{0}".format(self.id) "settings_{0}".format(self.id)
) )
def write_network_data(self, network_data, directory=os.curdir): def write_network_data(self, network_data, directory=os.curdir,
return self.serializer.write_to_file( serializer=None):
return (serializer or self.serializer).write_to_file(
self.get_network_data_path(directory), self.get_network_data_path(directory),
network_data network_data
) )
def write_settings_data(self, settings_data, directory=os.curdir): def write_settings_data(self, settings_data, directory=os.curdir,
return self.serializer.write_to_file( serializer=None):
return (serializer or self.serializer).write_to_file(
self.get_settings_data_path(directory), self.get_settings_data_path(directory),
settings_data 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) 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) 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 @property
def settings_url(self): def settings_url(self):
@ -158,7 +152,6 @@ class Environment(BaseObject):
return self.settings_url + "/defaults" return self.settings_url + "/defaults"
@property @property
@memorize_one
def network_url(self): def network_url(self):
return "clusters/{id}/network_configuration/{net_provider}".format( return "clusters/{id}/network_configuration/{net_provider}".format(
**self.data **self.data
@ -213,12 +206,24 @@ class Environment(BaseObject):
return fact_url return fact_url
def get_default_facts(self, fact_type, nodes=None): 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)) 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): 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)) 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): def upload_facts(self, fact_type, facts):
self.connection.put_request(self._get_fact_url(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): def delete_facts(self, fact_type):
self.connection.delete_request(self._get_fact_url(fact_type)) self.connection.delete_request(self._get_fact_url(fact_type))
def read_fact_info(self, fact_type): def read_fact_info(self, fact_type, directory, serializer=None):
if fact_type == "deployment": return getattr(
return self.read_deployment_info(fact_type) self, "read_{0}_info".format(fact_type)
elif fact_type == "provisioning": )(fact_type, directory=directory, serializer=serializer)
return self.read_provisioning_info(fact_type)
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) dir_name = self._get_fact_dir_name(fact_type, directory=directory)
if os.path.exists(dir_name): if os.path.exists(dir_name):
shutil.rmtree(dir_name) shutil.rmtree(dir_name)
os.makedirs(dir_name) os.makedirs(dir_name)
if isinstance(facts, dict): if isinstance(facts, dict):
engine_file_path = os.path.join(dir_name, "engine") 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"] facts = facts["nodes"]
name_template = "{name}" name_template = "{name}"
else: else:
@ -249,25 +255,28 @@ class Environment(BaseObject):
dir_name, dir_name,
name_template.format(**_fact) 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) dir_name = self._get_fact_dir_name(fact_type, directory=directory)
return map( 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) [os.path.join(dir_name, json_file)
for json_file in listdir_without_extensions(dir_name)] 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) dir_name = self._get_fact_dir_name(fact_type, directory=directory)
node_facts = map( 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) [os.path.join(dir_name, fact_file)
for fact_file in listdir_without_extensions(dir_name) for fact_file in listdir_without_extensions(dir_name)
if "engine" != fact_file] if "engine" != fact_file]
) )
engine = self.serializer.read_from_file( engine = (serializer or self.serializer).read_from_file(
os.path.join(dir_name, "engine")) os.path.join(dir_name, "engine"))
return { return {
"engine": engine, "engine": engine,

View File

@ -87,7 +87,8 @@ class Node(BaseObject):
attributes 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) attributes_directory = self.get_attributes_path(directory)
if not os.path.exists(attributes_directory): if not os.path.exists(attributes_directory):
os.mkdir(attributes_directory) os.mkdir(attributes_directory)
@ -97,19 +98,19 @@ class Node(BaseObject):
) )
if os.path.exists(attribute_path): if os.path.exists(attribute_path):
os.remove(attribute_path) os.remove(attribute_path)
self.serializer.write_to_file( return (serializer or self.serializer).write_to_file(
attribute_path, attribute_path,
attributes attributes
) )
def read_attribute(self, attributes_type, directory): def read_attribute(self, attributes_type, directory, serializer=None):
attributes_directory = self.get_attributes_path(directory) attributes_directory = self.get_attributes_path(directory)
if not os.path.exists(attributes_directory): if not os.path.exists(attributes_directory):
exit_with_error( exit_with_error(
"Folder {0} doesn't contain node folder '{1}'" "Folder {0} doesn't contain node folder '{1}'"
.format(directory, "node_{0}".format(self.id)) .format(directory, "node_{0}".format(self.id))
) )
return self.serializer.read_from_file( return (serializer or self.serializer).read_from_file(
os.path.join( os.path.join(
attributes_directory, attributes_directory,
attributes_type attributes_type

View File

@ -118,38 +118,76 @@ class TestFiles(BaseTestCase):
"--env-id=1 node set --node 2,3 --role=compute" "--env-id=1 node set --node 2,3 --role=compute"
)) ))
for action in ("network", "settings"): for action in ("network", "settings"):
self.check_if_files_created( for format_ in ("yaml", "json"):
"--env 1 {0} --download".format(action), self.check_if_files_created(
("{0}_1.yaml".format(action),) "--env 1 {0} --download --{1}".format(action, format_),
) ("{0}_1.{1}".format(action, format_),)
deployment_provision_files = { )
"--env 1 deployment --default": ( command_to_files_map = (
"deployment_1", (
"deployment_1/primary-controller_1.yaml", "--env 1 deployment --default",
"deployment_1/compute_2.yaml", (
"deployment_1/compute_3.yaml" "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 --node 1 --disk --default",
("node_1", "node_1/disks.yaml") (
"node_1",
"node_1/disks.yaml"
)
), ),
( (
"node --node 1 --network --default", "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) self.check_if_files_created(command, files)
def check_if_files_created(self, command, paths): def check_if_files_created(self, command, paths):