solar/solar/cli/resource.py

203 lines
5.7 KiB
Python

# Copyright 2015 Mirantis, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import json
import os
import click
import yaml
from solar.cli.base import BaseGroup
from solar.cli import executors
from solar.core import actions
from solar.core import resource as sresource
from solar.core.resource import composer as cr
class ResourceGroup(BaseGroup):
pass
@click.group(cls=ResourceGroup)
def resource():
pass
@resource.command()
@click.argument('action')
@click.argument('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)
)
r = sresource.load(resource)
actions.resource_action(r, 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)
))
@resource.command()
def clear_all():
from solar.dblayer.model import ModelMeta
click.echo('Clearing all resources and connections')
ModelMeta.remove_all()
@resource.command()
@click.argument('name')
@click.argument('base_path')
@click.argument('args', nargs=-1)
def create(args, base_path, name):
if base_path.startswith('./'):
base_path = os.path.abspath(base_path)
elif base_path.endswith('.yaml'):
base_path = os.path.abspath(base_path)
args_parsed = {}
click.echo('create {} {} {}'.format(name, base_path, args))
for arg in args:
try:
args_parsed.update(json.loads(arg))
except ValueError:
k, v = arg.split('=')
args_parsed.update({k: yaml.safe_load(v)})
resources = cr.create(name, base_path, inputs=args_parsed)
for res in resources:
click.echo(res.color_repr())
@resource.command()
@click.option('--name', '-n', default=None)
@click.option('--tag', '-t', multiple=True)
@click.option('--as_json', default=False, is_flag=True)
@click.option('--color', default=True, is_flag=True)
def show(name, tag, as_json, color):
echo = click.echo_via_pager
if name:
resources = [sresource.load(name)]
echo = click.echo
elif tag:
resources = sresource.load_by_tags(set(tag))
else:
resources = sresource.load_all()
if as_json:
output = json.dumps([r.to_dict(inputs=True)
for r in resources], indent=2)
echo = click.echo
else:
if color:
formatter = lambda r: r.color_repr(inputs=True)
else:
formatter = lambda r: unicode(r)
output = '\n'.join(formatter(r) for r in resources)
if output:
echo(output)
@resource.command()
@click.argument('resource_name')
@click.argument('tags', nargs=-1)
@click.option('--add/--delete', default=True)
def tag(add, tags, resource_name):
r = sresource.load(resource_name)
if add:
r.add_tags(*tags)
click.echo('Tag(s) {} added to {}'.format(tags, resource_name))
else:
r.remove_tags(*tags)
click.echo('Tag(s) {} removed from {}'.format(tags, resource_name))
@resource.command()
@click.argument('name')
@click.argument('args', nargs=-1)
def update(name, args):
args_parsed = {}
for arg in args:
try:
args_parsed.update(json.loads(arg))
except ValueError:
k, v = arg.split('=')
args_parsed.update({k: yaml.safe_load(v)})
click.echo('Updating resource {} with args {}'.format(name, args_parsed))
res = sresource.load(name)
res.update(args_parsed)
@resource.command()
def validate():
errors = sresource.validate_resources()
for r, error in errors:
click.echo('ERROR: %s: %s' % (r.name, error))
@resource.command()
@click.argument('path', type=click.Path(exists=True, dir_okay=False))
def get_inputs(path):
with open(path) as f:
content = f.read()
click.echo(cr.get_inputs(content))
@resource.command()
@click.option('--name', '-n', default=None)
@click.option('--tag', '-t', multiple=True)
@click.option('-f', default=False, is_flag=True,
help='force removal from database')
def remove(name, tag, f):
if name:
resources = [sresource.load(name)]
elif tag:
resources = sresource.load_by_tags(set(tag))
else:
resources = sresource.load_all()
for res in resources:
res.remove(force=f)
if f:
msg = 'Resource %s removed from database' % res.name
else:
msg = 'Resource %s will be removed after committing changes.' % res.name # NOQA
click.echo(msg)
@resource.command()
@click.option('--name', '-n')
@click.option('--tag', '-t', multiple=True)
def prefetch(name, tag):
if name:
resources = [sresource.load(name)]
elif tag:
resources = sresource.load_by_tags(set(tag))
else:
raise click.ClickException("No resource defined, use --tag or --name")
for res in resources:
res.prefetch()
click.echo(res.color_repr())