added selective node deployment/provisioning

Detailed description
* added node selection on deployment/provisioning actions
  e.g. downloading/uploading of facts for specific nodes
  rather than downloading facts for all nodes
* fixed spelling

Implements: blueprint cli-separate-rpovisioning-and-deployment

Change-Id: I5eb3fca4cd3e0cd7db8bf573c321d4b3db93524a
This commit is contained in:
Alexandr Notchenko 2013-12-09 13:51:09 +04:00
parent a6b77e0cbe
commit 910442bf62
3 changed files with 97 additions and 29 deletions

View File

@ -76,13 +76,13 @@ class SetAction(argparse.Action):
setattr(namespace, self.dest, set(values))
def handle_api_exceptions(e):
if isinstance(e, urllib2.HTTPError):
print_error(str(e))
elif isinstance(e, urllib2.URLError):
def handle_exceptions(exc):
if isinstance(exc, urllib2.HTTPError):
print_error(str(exc))
elif isinstance(exc, urllib2.URLError):
print_error("Can't connect to Nailgun server!")
else:
raise e
raise exc
def recur_get(multi_level_dict, key_chain):
@ -531,6 +531,24 @@ def node(params):
elif any((params.default, params.download, params.upload)):
print('"--default", "--download" or "--upload" '
'must appear after "--disk" or "--network" flags.')
elif params.deploy or params.provision:
check_for_attributes(params, ["node", "env"])
node_ids = [str(n) for n in chain(*params.node)]
mode = "deploy" if params.deploy else "provision"
deploy_nodes_url = "clusters/{0}/{1}/?nodes={2}".format(
params.env,
mode,
','.join(node_ids)
)
data = json_api_put_request(
deploy_nodes_url,
{}
)
print_to_output(
data,
"Started {0}ing nodes [{1}]."
.format(mode, ", ".join(node_ids))
)
else:
acceptable_keys = ["id", "status", "name", "cluster",
"mac", "roles", "pending_roles", "online"]
@ -765,7 +783,8 @@ def task(params):
.format(','.join(map(str, task_ids)))
)
else:
acceptable_keys = ["id", "status", "name", "cluster", "progress"]
acceptable_keys = ["id", "status", "name",
"cluster", "progress", "uuid"]
tasks = json_api_get_request("tasks/")
print_to_output(
tasks,
@ -822,7 +841,7 @@ def download_snapshot_with_progress_bar(url, directory):
print()
def deploy(params):
def deploy_changes(params):
"""Deploy changes to environments
"""
check_for_attributes(params, ["env"])
@ -987,6 +1006,10 @@ def fact(params, info_type):
params.env,
info_type
)
if params.node:
facts_default_url += "/?nodes=" + ",".join(
str(n) for n in chain(*params.node)
)
facts_url = "clusters/{0}/orchestrator/{1}/".format(
params.env,
info_type
@ -1017,7 +1040,7 @@ def fact(params, info_type):
write_facts_to_dir(facts, dir_name)
def healthcheck(params):
def health_check(params):
"""Run health check on environment
"""
check_for_attributes(params, ["env"])
@ -1350,6 +1373,20 @@ def get_release_arg(help_msg):
}
def get_node_arg(help_msg):
return {
"args": ["--node", "--node-id"],
"params": {
"dest": "node",
"action": "store",
"nargs": '+',
"type": parse_ids,
"help": help_msg,
"default": None
}
}
actions = {
"release": {
"action": release,
@ -1473,17 +1510,8 @@ actions = {
get_download_arg("Download configuration of specific node"),
get_upload_arg("Upload configuration to specific node"),
get_dir_arg("Select directory to which download node attributes"),
get_node_arg("Node id."),
{
"args": ["--node", "--node-id"],
"params": {
"dest": "node",
"action": "store",
"nargs": '+',
"type": parse_ids,
"help": "Node id.",
"default": None
}
}, {
"args": ["-r", "--role"],
"params": {
"dest": "role",
@ -1516,6 +1544,22 @@ actions = {
"help": "Bypassing parameter validation.",
"default": False
}
}, {
"args": ["--deploy"],
"params": {
"dest": "deploy",
"action": "store_true",
"help": "Deploy specific nodes.",
"default": False
}
}, {
"args": ["--provision"],
"params": {
"dest": "provision",
"action": "store_true",
"help": "Provision specific nodes.",
"default": False
}
}]
},
"network": {
@ -1558,12 +1602,12 @@ actions = {
get_dir_arg("Directory to which download snapshot.")
]
},
"deploy": {
"action": deploy,
"deploy-changes": {
"action": deploy_changes,
"args": []
},
"health": {
"action": healthcheck,
"action": health_check,
"args": [
get_list_arg("List all available checks"),
{
@ -1587,7 +1631,8 @@ def get_args_for_facts(fact_type):
get_download_arg("Download current {0} data.".format(fact_type)),
get_upload_arg("Upload current {0} data.".format(fact_type)),
get_default_arg("Download default {0} data.".format(fact_type)),
get_dir_arg("Directory with {0} data.".format(fact_type))
get_dir_arg("Directory with {0} data.".format(fact_type)),
get_node_arg("Node ids."),
]
@ -1715,4 +1760,4 @@ if __name__ == '__main__':
try:
actions[current_action]["action"](parsed_params)
except Exception as e:
handle_api_exceptions(e)
handle_exceptions(e)

View File

@ -87,7 +87,7 @@ class BaseTestCase(TestCase):
print("Running " + " ".join(args))
handle.wait()
def run_cli_command(self, command_line=None, with_erros=False):
def run_cli_command(self, command_line, with_erros=False):
modified_env = os.environ.copy()
modified_env["LISTEN_PORT"] = "8003"
command_args = [" ".join((self.fuel_path, command_line))]
@ -108,22 +108,26 @@ class BaseTestCase(TestCase):
self.fail()
return result
def run_cli_commands(self, command_lines, with_erros=False):
for command in command_lines:
self.run_cli_command(command, with_erros=with_erros)
def check_if_required(self, command):
call = self.run_cli_command(command_line=command, with_erros=True)
call = self.run_cli_command(command, with_erros=True)
#should not work without env id
self.assertIn("required", call.stderr)
def check_for_stdout(self, command, msg):
call = self.run_cli_command(command_line=command)
call = self.run_cli_command(command)
self.assertEqual(call.stdout, msg)
def check_all_in_msg(self, command, substrs):
output = self.run_cli_command(command_line=command)
output = self.run_cli_command(command)
for substr in substrs:
self.assertIn(substr, output.stdout)
def check_for_rows_in_table(self, command):
output = self.run_cli_command(command_line=command)
output = self.run_cli_command(command)
message = output.stdout.split("\n")
#no env
self.assertEqual(message[2], '')

View File

@ -59,10 +59,29 @@ class TestHandlers(BaseTestCase):
"--list", "-s", "--set", "--delete", "--default", "-d",
"--download", "-u", "--upload", "--dir", "--node",
"--node-id", "-r", "--role", "--net", "--network",
"--disk", "-f", "--force"]
"--disk", "-f", "--force", "--deploy", "--provision"]
self.check_all_in_msg("node --help", help_msg)
self.check_for_rows_in_table("node")
for action in ("set", "remove", "--network", "--disk"):
self.check_if_required("node {0}".format(action))
def test_selected_node_deploy_or_provision(self):
self.load_data_to_nailgun_server()
self.run_cli_commands((
"env create --name=NewEnv --release=1",
"--env-id=1 node set --node 1 --role=controller"
))
commands = ("--provision", "--deploy")
for action in commands:
self.check_if_required("--env-id=1 node {0}".format(action))
messages = (
"Started provisioning nodes [1].\n",
"Started deploying nodes [1].\n"
)
for cmd, msg in zip(commands, messages):
self.check_for_stdout(
"--env-id=1 node {0} --node=1".format(cmd),
msg
)