Merge branch 'master' into cgenie/solar-bootstrap

This commit is contained in:
Przemyslaw Kaminski 2015-08-06 14:05:09 +02:00
commit 0c3f3208b6
6 changed files with 124 additions and 4 deletions

View File

@ -157,6 +157,43 @@ from x import resource
all_resources = resource.load_all('rs')
```
## Dry run
Solar CLI has possibility to show dry run of actions to be performed.
To see what will happen when you run Puppet action, for example, try this:
```
solar resource action keystone_puppet run -d
```
This should print out something like this:
```
EXECUTED:
73c6cb1cf7f6cdd38d04dd2d0a0729f8: (0, 'SSH RUN', ('sudo cat /tmp/puppet-modules/Puppetfile',), {})
3dd4d7773ce74187d5108ace0717ef29: (1, 'SSH SUDO', ('mv "1038cb062449340bdc4832138dca18cba75caaf8" "/tmp/puppet-modules/Puppetfile"',), {})
ae5ad2455fe2b02ba46b4b7727eff01a: (2, 'SSH RUN', ('sudo librarian-puppet install',), {})
208764fa257ed3159d1788f73c755f44: (3, 'SSH SUDO', ('puppet apply -vd /tmp/action.pp',), {})
```
By default every mocked command returns an empty string. If you want it to return
something else (to check how would dry run behave in different situation) you provide
a mapping (in JSON format), something along the lines of:
```
solar resource action keystone_puppet run -d -m "{\"73c\": \"mod 'openstack-keystone'\n\"}"
```
The above means the return string of first command (with hash `73c6c...`) will be
as specified in the mapping. Notice that in mapping you don't have to specify the
whole hash, just it's unique beginning. Also, you don't have to specify the whole
return string in mapping. Dry run executor can read file and return it's contents
instead, just use the `>` operator when specifying hash:
```
solar resource action keystone_puppet run -d -m "{\"73c>\": \"./Puppetlabs-file\"}"
```
## Resource compiling
You can compile all `meta.yaml` definitions into Python code with classes that

View File

@ -9,6 +9,7 @@
# PIP
- apt: name=python-pip state=absent
- apt: name=python-six state=absent
- shell: easy_install pip
- shell: pip install -U pip
- shell: pip install -U setuptools

View File

@ -17,7 +17,7 @@ input:
value: false
glance_request_timeout:
schema: str
value: ''
value:
git:
schema: {repository: str!, branch: str!}

View File

@ -0,0 +1,55 @@
from hashlib import md5
class DryRunExecutor(object):
def __init__(self, mapping=None):
from fabric import api as fabric_api
from fabric.contrib import project as fabric_project
import mock
from solar.core.handlers import puppet
self.executed = []
self.mapping = mapping or {}
def dry_run_executor(command_name):
def wrapper(*args, **kwargs):
key = (len(self.executed), command_name, args, kwargs)
self.executed.append(key)
return self.find_hash(self.compute_hash(key))
return wrapper
# Add your own mocks here, IO, whatever
fabric_api.local = mock.Mock(side_effect=dry_run_executor('LOCAL RUN'))
fabric_api.put = mock.Mock(side_effect=dry_run_executor('PUT'))
fabric_api.run = mock.Mock(side_effect=dry_run_executor('SSH RUN'))
fabric_api.sudo = mock.Mock(side_effect=dry_run_executor('SSH SUDO'))
fabric_project.rsync_project = mock.Mock(side_effect=dry_run_executor('RSYNC PROJECT'))
def compute_hash(self, key):
return md5(str(key)).hexdigest()
def find_hash(self, hash):
stripped_hashes = {k.replace('>', ''): k for k in self.mapping}
hashes = [k for k in stripped_hashes if hash.startswith(k)]
if len(hashes) == 0:
#raise Exception('Hash {} not found'.format(hash))
return ''
elif len(hashes) > 1:
raise Exception('Hash {} not unique in {}'.format(
hash, hashes
))
hash = stripped_hashes[hashes[0]]
if hash.endswith('>'):
with open(self.mapping[hash]) as f:
return f.read()
return self.mapping[hash]

View File

@ -33,12 +33,12 @@ from solar.core import resource as sresource
from solar.core.resource import assign_resources_to_nodes
from solar.core import signals
from solar.core.tags_set_parser import Expression
from solar.core import testing
from solar.core.resource import virtual_resource as vr
from solar.interfaces.db import get_db
from solar import errors
from solar.core.log import log
from solar.cli import executors
from solar.cli.orch import orchestration
from solar.cli.system_log import changes
@ -134,10 +134,15 @@ def init_actions():
@main.command()
@click.option('-t', '--tags')
@click.option('-a', '--action')
def run(action, tags):
@click.option('-d', '--dry-run', default=False, is_flag=True)
@click.option('-m', '--dry-run-mapping', default='{}')
def run(dry_run_mapping, dry_run, action, tags):
from solar.core import actions
from solar.core import resource
if dry_run:
dry_run_executor = executors.DryRunExecutor(mapping=json.loads(dry_run_mapping))
resources = filter(
lambda r: Expression(tags, r.get('tags', [])).evaluate(),
db.get_list('resource'))
@ -146,6 +151,14 @@ def init_actions():
resource_obj = sresource.load(resource['id'])
actions.resource_action(resource_obj, action)
if dry_run:
click.echo('EXECUTED:')
for key in dry_run_executor.executed:
click.echo('{}: {}'.format(
click.style(dry_run_executor.compute_hash(key), fg='green'),
str(key)
))
def init_cli_connect():
@main.command()
@ -238,7 +251,12 @@ def init_cli_resource():
@resource.command()
@click.argument('action')
@click.argument('resource')
def action(action, resource):
@click.option('-d', '--dry-run', default=False, is_flag=True)
@click.option('-m', '--dry-run-mapping', default='{}')
def action(dry_run_mapping, dry_run, action, resource):
if dry_run:
dry_run_executor = executors.DryRunExecutor(mapping=json.loads(dry_run_mapping))
click.echo(
'action {} for resource {}'.format(action, resource)
)
@ -250,6 +268,14 @@ def init_cli_resource():
log.debug(e)
sys.exit(1)
if dry_run:
click.echo('EXECUTED:')
for key in dry_run_executor.executed:
click.echo('{}: {}'.format(
click.style(dry_run_executor.compute_hash(key), fg='green'),
str(key)
))
@resource.command()
def compile_all():
from solar.core.resource import compiler

View File

@ -91,6 +91,7 @@ class LibrarianPuppet(ResourceSSHMixin):
self.resource,
'sudo', 'cat', '/var/tmp/puppet/Puppetfile'
)
log.debug('Puppetlabs file is: \n%s\n', puppetlabs)
git = self.resource.args['git'].value