Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revamp the argument passing #175

Merged
merged 11 commits into from
Nov 19, 2018
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,14 @@ interactive: True
# Runs the command in reporting mode. The standard output of the remote command will
# be dumped to the screen instead of the exit code.
report: True

# The following list form the arguments to the command line. They are set as bash shell
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this line could do with some clearing up - either 'The following list forms the arguments sent to the command line' or 'The following list forms the arguments for the command line'

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

# variables when running the command. This allows them to be used within the command
# NOTE: this key is optional
arguments:
- arg1
- arg2
...
```

# Configuring Run Parameters
Expand Down
2 changes: 1 addition & 1 deletion src/appliance_cli/command_generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ def add_argument(name):
is_required = False
for n in arg_n: add_argument(n)
else:
add_argument(arg_name)
add_argument(arg_n)
return args_map


Expand Down
64 changes: 41 additions & 23 deletions src/commands/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ def run():

runner_cmd = {
'help': Config.help,
**run_options
**run_options,
'arguments': Config.args
}
runner_group = {
'help': (lambda names: "Run tools in {}".format(' '.join(names))),
Expand All @@ -44,7 +45,7 @@ def run():
@command_creator.tools(run, command = runner_cmd, group = runner_group)
@cli_utils.with__node__group
@cli_utils.ignore_parent_commands
def runner(_ctx, configs, _a, options, nodes):
def runner(_ctx, configs, argv, options, nodes):
def error_if_invalid_interactive_batch():
matches = [c for c in configs if c.interactive()]
if matches and (len(configs) > 1 or len(nodes) > 1):
Expand All @@ -66,13 +67,43 @@ def is_quiet():
if first.interactive() or first.report: return True
else: return False

def argument_hash(config):
keys = config.args()
arg_hash = {}
for index, value in enumerate(argv):
arg_hash[keys[index]] = value
return arg_hash

def build_batches():
def build(config):
batch = Batch(config = config.path)
batch.build_jobs(*nodes)
batch.build_shell_variables(**argument_hash(config))
return batch
return list(map(lambda c: build(c), configs))

def get_confirmation(batches, nodes):
tool_names = '\n '.join([b.config_model.name() for b in batches])
node_names = groups_util.compress_nodes(nodes).replace('],', ']\n ')
node_tag = 'node' if len(nodes) == 1 else 'nodes'
click.echo("""
You are about to run:
{}
Over {}:
{}
""".strip().format(tool_names, node_tag, node_names))
question = "Please enter [y/n] to confirm"
affirmatives = ['y', 'ye', 'yes']
reply = click.prompt(question).lower()
if reply in affirmatives: return True

error_if_no_nodes()
batches = list(map(lambda c: Batch(config = c.path), configs))
error_if_invalid_interactive_batch()
if not (options['yes'].value or get_confirmation(batches, nodes)):
return
for batch in batches: batch.build_jobs(*nodes)
execute_batches(batches, quiet = is_quiet())

batches = build_batches()

if (options['yes'].value or get_confirmation(batches, nodes)):
execute_batches(batches, quiet = is_quiet())

def execute_batches(batches, quiet = False):
def run_print(string):
Expand Down Expand Up @@ -116,6 +147,9 @@ def remove_done_tasks():
for batch in batches:
session.add(batch)
session.commit()
# Ensure the models are loaded from the db
batch.jobs
batch.shell_variables
run_print('Executing: {}'.format(batch.name()))
tasks = map(lambda j: j.task(thread_pool = pool), batch.jobs)
loop.run_until_complete(start_tasks(tasks))
Expand All @@ -127,19 +161,3 @@ def remove_done_tasks():
session.commit()
Session.remove()
run_print('Done')

def get_confirmation(batches, nodes):
tool_names = '\n '.join([b.config_model.name() for b in batches])
node_names = groups_util.compress_nodes(nodes).replace('],', ']\n ')
node_tag = 'node' if len(nodes) == 1 else 'nodes'
click.echo("""
You are about to run:
{}
Over {}:
{}
""".strip().format(tool_names, node_tag, node_names))
question = "Please enter [y/n] to confirm"
affirmatives = ['y', 'ye', 'yes']
reply = click.prompt(question).lower()
if reply in affirmatives:
return True
15 changes: 14 additions & 1 deletion src/models/batch.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from database import Base
from models.config import Config
from models.job import Job
from models.shell_variable import ShellVariable

class Batch(Base):

Expand All @@ -21,7 +22,12 @@ def help(self):
return self.config_model.help()

def command(self):
return self.config_model.command()
var_models = self.shell_variables
var_map = map(lambda v: '='.join([v.key, v.value]), var_models)
var_str = ' && '.join(var_map)
cmd = self.config_model.command()
if var_str: cmd = ' && '.join([var_str, cmd])
return cmd

def command_exists(self):
return self.config_model.command_exists()
Expand All @@ -31,3 +37,10 @@ def is_interactive(self):

def build_jobs(self, *nodes):
return list(map(lambda n: Job(node = n, batch = self), nodes))

def build_shell_variables(self, **variables):
def build(key):
args = { 'key': key, 'value': variables[key], 'batch': self }
return ShellVariable(**args)

return list(map(lambda k: build(k), variables.keys()))
3 changes: 3 additions & 0 deletions src/models/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ def help(self):
if not self.data['help']: self.data['help'] = default
return self.data['help']

def args(self):
return self.arguments or []

# TODO: Deprecated, avoid usage
def interactive_only(self):
return self.interactive()
Expand Down
24 changes: 24 additions & 0 deletions src/models/shell_variable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

from sqlalchemy import Column, String, Integer, ForeignKey
from sqlalchemy.orm import relationship, validates

from database import Base

import click

class ShellVariable(Base):


key = Column(String)
value = Column(String)
batch_id = Column(Integer, ForeignKey('batches.id'))
batch = relationship("Batch", backref="shell_variables")


@validates('value')
def validate_value(self, _, value):
try:
assert value.isalnum()
return value
except AssertionError:
raise click.ClickException('The arguments must be alphanumeric')