197 lines
5.6 KiB
Python
Executable File
197 lines
5.6 KiB
Python
Executable File
#!/usr/bin/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 sys
|
|
import time
|
|
|
|
import click
|
|
|
|
from solar.cli.base import BaseGroup
|
|
from solar.cli.uids_history import remember_uid
|
|
from solar.cli.uids_history import SOLARUID
|
|
from solar.dblayer.locking import DBLock
|
|
from solar import errors
|
|
from solar.orchestration import filters
|
|
from solar.orchestration import graph
|
|
from solar.orchestration import SCHEDULER_CLIENT
|
|
from solar.orchestration.traversal import states
|
|
from solar.orchestration import utils
|
|
|
|
|
|
class OrchGroup(BaseGroup):
|
|
pass
|
|
|
|
|
|
@click.group(name='orch', cls=OrchGroup)
|
|
def orchestration():
|
|
pass
|
|
|
|
|
|
@orchestration.command()
|
|
@click.argument('plan')
|
|
def create(plan):
|
|
uid = graph.create_plan(plan).graph['uid']
|
|
remember_uid(uid)
|
|
click.echo(uid)
|
|
|
|
|
|
def wait_report(uid, timeout, interval=3):
|
|
try:
|
|
if timeout:
|
|
for summary in graph.wait_finish(uid, timeout=timeout):
|
|
stringified_summary = '\r' + ' '.join(
|
|
['{}: {}'.format(state, count)
|
|
for state, count in summary.items()])
|
|
click.echo(stringified_summary, nl=False)
|
|
sys.stdout.flush()
|
|
pending = states.PENDING.name
|
|
in_progress = states.INPROGRESS.name
|
|
if summary[pending] + summary[in_progress] != 0:
|
|
time.sleep(interval)
|
|
except errors.SolarError:
|
|
click.echo('')
|
|
click_report(uid)
|
|
raise
|
|
else:
|
|
click.echo('')
|
|
click_report(uid)
|
|
|
|
|
|
def click_report(uid):
|
|
report = graph.report_progress(uid)
|
|
if len(report['tasks']) == 0:
|
|
click.echo('Nothing to report')
|
|
else:
|
|
colors = {
|
|
'PENDING': 'cyan',
|
|
'ERROR': 'red',
|
|
'SUCCESS': 'green',
|
|
'INPROGRESS': 'yellow',
|
|
'SKIPPED': 'blue',
|
|
'NOOP': 'black'}
|
|
|
|
for item in report['tasks']:
|
|
msg = '{} -> {}'.format(item[0], item[1])
|
|
if item[2]:
|
|
msg += ' :: {}'.format(item[2])
|
|
click.echo(click.style(msg, fg=colors[item[1]]))
|
|
click.echo('Total Delta: {}'.format(report['total_delta']))
|
|
click.echo('Total Time: {}'.format(report['total_time']))
|
|
|
|
|
|
@orchestration.command()
|
|
@click.argument('uid', type=SOLARUID, default='last')
|
|
@click.option('-w', 'wait', default=0)
|
|
def report(uid, wait):
|
|
wait_report(uid, wait)
|
|
|
|
|
|
@orchestration.command()
|
|
@click.argument('uid', type=SOLARUID)
|
|
@click.option('--start', '-s', multiple=True)
|
|
@click.option('--end', '-e', multiple=True)
|
|
def filter(uid, start, end):
|
|
graph.reset_filtered(uid)
|
|
plan = graph.get_graph(uid)
|
|
errors = filters.filter(plan, start=start, end=end)
|
|
if errors:
|
|
raise click.ClickException('\n'.join(errors))
|
|
graph.update_graph(plan)
|
|
utils.write_graph(plan)
|
|
click.echo('Created {name}.png'.format(name=plan.graph['name']))
|
|
|
|
|
|
@orchestration.command(help='Used to mark task as executed')
|
|
@click.argument('uid', type=SOLARUID)
|
|
@click.option('--task', '-t', multiple=True)
|
|
def noop(uid, task):
|
|
graph.set_states(uid, task)
|
|
|
|
|
|
@orchestration.command(name='run-once')
|
|
@click.argument('uid', type=SOLARUID, default='last')
|
|
@click.option('-w', 'wait', default=0)
|
|
def run_once(uid, wait):
|
|
SCHEDULER_CLIENT.next({}, uid)
|
|
wait_report(uid, wait)
|
|
|
|
|
|
@orchestration.command()
|
|
@click.argument('uid', type=SOLARUID)
|
|
@click.option('-w', 'wait', default=0)
|
|
def restart(uid, wait):
|
|
graph.reset_by_uid(uid)
|
|
SCHEDULER_CLIENT.next({}, uid)
|
|
wait_report(uid, wait)
|
|
|
|
|
|
@orchestration.command()
|
|
@click.argument('uid', type=SOLARUID)
|
|
def stop(uid):
|
|
# TODO(dshulyak) how to do "hard" stop?
|
|
# using revoke(terminate=True) will lead to inability to restart execution
|
|
# research possibility of customizations
|
|
# app.control and Panel.register in celery
|
|
SCHEDULER_CLIENT.soft_stop({}, uid)
|
|
|
|
|
|
@orchestration.command()
|
|
@click.argument('uid', type=SOLARUID)
|
|
def reset(uid):
|
|
graph.reset_by_uid(uid)
|
|
|
|
|
|
@orchestration.command()
|
|
@click.argument('uid', type=SOLARUID)
|
|
def resume(uid):
|
|
graph.reset_by_uid(uid, state_list=['SKIPPED'])
|
|
SCHEDULER_CLIENT.next({}, uid)
|
|
|
|
|
|
@orchestration.command()
|
|
@click.argument('uid', type=SOLARUID)
|
|
def retry(uid):
|
|
graph.reset_by_uid(uid, state_list=['ERROR'])
|
|
SCHEDULER_CLIENT.next({}, uid)
|
|
|
|
|
|
@orchestration.command()
|
|
@click.argument('uid', type=SOLARUID)
|
|
@click.option('--start', '-s', multiple=True)
|
|
@click.option('--end', '-e', multiple=True)
|
|
def dg(uid, start, end):
|
|
plan = graph.get_graph(uid)
|
|
if start or end:
|
|
errors = filters.filter(plan, start=start, end=end)
|
|
if errors:
|
|
raise click.ClickException('\n'.join(errors))
|
|
utils.write_graph(plan)
|
|
click.echo('Created {name}.svg'.format(name=plan.graph['name']))
|
|
|
|
|
|
@orchestration.command()
|
|
@click.argument('uid', type=SOLARUID)
|
|
def show(uid):
|
|
click.echo(graph.show(uid))
|
|
|
|
|
|
@orchestration.command(name='release-lock')
|
|
@click.argument('uid', type=SOLARUID)
|
|
def release_lock(uid):
|
|
"""Use if worker was killed, and lock wasnt released properly. """
|
|
lock = DBLock.get(uid)
|
|
lock.delete()
|
|
return True
|