Add CLI for client v2
* Added CLI for workbooks, executions, workflows and tasks. * v2 commands are set by default TODO: * Unit tests for CLI v2 * Add ActionManager and Actions CLI Change-Id: Ie564cd77d816ab7ff939f4bec9fa14ae04130435
This commit is contained in:
parent
413019b6d8
commit
37606f99ac
@ -22,12 +22,11 @@ class Workbook(base.Resource):
|
||||
class WorkbookManager(base.ResourceManager):
|
||||
resource_class = Workbook
|
||||
|
||||
def create(self, name, definition=None, description=None, tags=None):
|
||||
def create(self, name, tags=None, definition=None):
|
||||
self._ensure_not_empty(name=name)
|
||||
|
||||
data = {
|
||||
'name': name,
|
||||
'description': description,
|
||||
'tags': tags,
|
||||
}
|
||||
|
||||
@ -36,12 +35,11 @@ class WorkbookManager(base.ResourceManager):
|
||||
|
||||
return self._create('/workbooks', data)
|
||||
|
||||
def update(self, name, definition=None, description=None, tags=None):
|
||||
def update(self, name, tags=None, definition=None):
|
||||
self._ensure_not_empty(name=name)
|
||||
|
||||
data = {
|
||||
'name': name,
|
||||
'description': description,
|
||||
'tags': tags,
|
||||
}
|
||||
|
||||
|
@ -22,24 +22,22 @@ class Workflow(base.Resource):
|
||||
class WorkflowManager(base.ResourceManager):
|
||||
resource_class = Workflow
|
||||
|
||||
def create(self, name, definition, description=None, tags=None):
|
||||
def create(self, name, definition, tags=None):
|
||||
self._ensure_not_empty(name=name, definition=definition)
|
||||
|
||||
data = {
|
||||
'name': name,
|
||||
'definition': definition,
|
||||
'description': description,
|
||||
'tags': tags,
|
||||
}
|
||||
|
||||
return self._create('/workflows', data)
|
||||
|
||||
def update(self, name, definition=None, description=None, tags=None):
|
||||
def update(self, name, definition=None, tags=None):
|
||||
self._ensure_not_empty(name=name)
|
||||
|
||||
data = {
|
||||
'name': name,
|
||||
'description': description,
|
||||
'tags': tags,
|
||||
}
|
||||
|
||||
|
0
mistralclient/commands/v1/__init__.py
Normal file
0
mistralclient/commands/v1/__init__.py
Normal file
0
mistralclient/commands/v2/__init__.py
Normal file
0
mistralclient/commands/v2/__init__.py
Normal file
214
mistralclient/commands/v2/executions.py
Normal file
214
mistralclient/commands/v2/executions.py
Normal file
@ -0,0 +1,214 @@
|
||||
# Copyright 2014 - Mirantis, Inc.
|
||||
# All Rights Reserved
|
||||
#
|
||||
# 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 logging
|
||||
|
||||
from cliff import command
|
||||
from cliff import lister
|
||||
from cliff import show
|
||||
|
||||
from mistralclient.api.v2 import executions
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def format(execution=None):
|
||||
columns = (
|
||||
'ID',
|
||||
'Workflow',
|
||||
'State',
|
||||
'Created at',
|
||||
'Updated at'
|
||||
)
|
||||
# TODO(nmakhotkin) Add parent task id when it's implemented in API.
|
||||
|
||||
if execution:
|
||||
data = (
|
||||
execution.id,
|
||||
execution.workflow_name,
|
||||
execution.state,
|
||||
execution.created_at,
|
||||
execution.updated_at or '<none>'
|
||||
)
|
||||
else:
|
||||
data = (tuple('<none>' for _ in range(len(columns))),)
|
||||
|
||||
return columns, data
|
||||
|
||||
|
||||
class List(lister.Lister):
|
||||
"""List all executions."""
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
data = [format(execution)[1] for execution
|
||||
in executions.ExecutionManager(self.app.client).list()]
|
||||
|
||||
if data:
|
||||
return format()[0], data
|
||||
else:
|
||||
return format()
|
||||
|
||||
|
||||
class Get(show.ShowOne):
|
||||
"""Show specific execution."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(Get, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'id',
|
||||
help='Execution identifier')
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
execution = executions.ExecutionManager(self.app.client)\
|
||||
.get(parsed_args.id)
|
||||
|
||||
return format(execution)
|
||||
|
||||
|
||||
class Create(show.ShowOne):
|
||||
"""Create new execution."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(Create, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'workflow_name',
|
||||
help='Execution workflow')
|
||||
parser.add_argument(
|
||||
'workflow_input',
|
||||
nargs='?',
|
||||
help='Workflow input')
|
||||
parser.add_argument(
|
||||
'params',
|
||||
nargs='?',
|
||||
help='Workflow additional parameters')
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
if parsed_args.workflow_input:
|
||||
try:
|
||||
wf_input = json.loads(parsed_args.workflow_input)
|
||||
except:
|
||||
wf_input = json.load(open(parsed_args.workflow_input))
|
||||
else:
|
||||
wf_input = {}
|
||||
|
||||
if parsed_args.params:
|
||||
try:
|
||||
params = json.loads(parsed_args.params)
|
||||
except:
|
||||
params = json.load(open(parsed_args.params))
|
||||
else:
|
||||
params = {}
|
||||
|
||||
execution = executions.ExecutionManager(self.app.client)\
|
||||
.create(parsed_args.workflow_name,
|
||||
wf_input,
|
||||
**params)
|
||||
|
||||
return format(execution)
|
||||
|
||||
|
||||
class Delete(command.Command):
|
||||
"""Delete execution."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(Delete, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'id',
|
||||
help='Execution identifier')
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
executions.ExecutionManager(self.app.client).delete(parsed_args.id)
|
||||
|
||||
|
||||
class Update(show.ShowOne):
|
||||
"""Update execution."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(Update, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'id',
|
||||
help='Execution identifier')
|
||||
parser.add_argument(
|
||||
'state',
|
||||
choices=['RUNNING', 'SUSPENDED', 'STOPPED', 'SUCCESS', 'ERROR'],
|
||||
help='Execution state')
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
execution = executions.ExecutionManager(self.app.client)\
|
||||
.update(parsed_args.id,
|
||||
parsed_args.state)
|
||||
|
||||
return format(execution)
|
||||
|
||||
|
||||
class GetInput(command.Command):
|
||||
"""Show execution input data."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(GetInput, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'id',
|
||||
help='Execution ID')
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
ex_input = executions.ExecutionManager(self.app.client)\
|
||||
.get(parsed_args.id).input
|
||||
|
||||
try:
|
||||
ex_input = json.loads(ex_input)
|
||||
ex_input = json.dumps(ex_input, indent=4) + "\n"
|
||||
except:
|
||||
LOG.debug("Execution input is not JSON.")
|
||||
|
||||
self.app.stdout.write(ex_input or "\n")
|
||||
|
||||
|
||||
class GetOutput(command.Command):
|
||||
"""Show execution output data."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(GetOutput, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'id',
|
||||
help='Execution ID')
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
output = executions.ExecutionManager(self.app.client)\
|
||||
.get(parsed_args.id).output
|
||||
|
||||
try:
|
||||
output = json.loads(output)
|
||||
output = json.dumps(output, indent=4) + "\n"
|
||||
except:
|
||||
LOG.debug("Execution output is not JSON.")
|
||||
|
||||
self.app.stdout.write(output or "\n")
|
154
mistralclient/commands/v2/tasks.py
Normal file
154
mistralclient/commands/v2/tasks.py
Normal file
@ -0,0 +1,154 @@
|
||||
# Copyright 2014 - Mirantis, Inc.
|
||||
# All Rights Reserved
|
||||
#
|
||||
# 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 logging
|
||||
|
||||
from cliff import command
|
||||
from cliff import lister
|
||||
from cliff import show
|
||||
|
||||
from mistralclient.api.v2 import tasks
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def format(task=None):
|
||||
columns = (
|
||||
'ID',
|
||||
'Name',
|
||||
'Workflow name',
|
||||
'Execution ID',
|
||||
'State',
|
||||
'Parameters',
|
||||
)
|
||||
|
||||
if task:
|
||||
data = (
|
||||
task.id,
|
||||
task.name,
|
||||
task.wf_name,
|
||||
task.execution_id,
|
||||
task.state,
|
||||
task.parameters,
|
||||
)
|
||||
else:
|
||||
data = (tuple('<none>' for _ in range(len(columns))),)
|
||||
|
||||
return columns, data
|
||||
|
||||
|
||||
class List(lister.Lister):
|
||||
"""List all tasks."""
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
data = [format(task)[1] for task
|
||||
in tasks.TaskManager(self.app.client).list()]
|
||||
|
||||
if data:
|
||||
return format()[0], data
|
||||
else:
|
||||
return format()
|
||||
|
||||
|
||||
class Get(show.ShowOne):
|
||||
"""Show specific task."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(Get, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'id',
|
||||
help='Task identifier')
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
execution = tasks.TaskManager(self.app.client)\
|
||||
.get(parsed_args.id)
|
||||
|
||||
return format(execution)
|
||||
|
||||
|
||||
class Update(show.ShowOne):
|
||||
"""Update task."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(Update, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'id',
|
||||
help='Task identifier')
|
||||
parser.add_argument(
|
||||
'state',
|
||||
choices=['IDLE', 'RUNNING', 'SUCCESS', 'ERROR'],
|
||||
help='Task state')
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
execution = tasks.TaskManager(self.app.client).update(
|
||||
parsed_args.id,
|
||||
parsed_args.state)
|
||||
|
||||
return format(execution)
|
||||
|
||||
|
||||
class GetOutput(command.Command):
|
||||
"""Show task output data."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(GetOutput, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'id',
|
||||
help='Task ID')
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
output = tasks.TaskManager(self.app.client)\
|
||||
.get(parsed_args.id).output
|
||||
|
||||
try:
|
||||
output = json.loads(output)
|
||||
output = json.dumps(output, indent=4) + "\n"
|
||||
except:
|
||||
LOG.debug("Task output is not JSON.")
|
||||
|
||||
self.app.stdout.write(output or "\n")
|
||||
|
||||
|
||||
class GetResult(command.Command):
|
||||
"""Show task output data."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(GetResult, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'id',
|
||||
help='Task ID')
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
result = tasks.TaskManager(self.app.client)\
|
||||
.get(parsed_args.id).result
|
||||
|
||||
try:
|
||||
result = json.loads(result)
|
||||
result = json.dumps(result, indent=4) + "\n"
|
||||
except:
|
||||
LOG.debug("Task result is not JSON.")
|
||||
|
||||
self.app.stdout.write(result or "\n")
|
208
mistralclient/commands/v2/workbooks.py
Normal file
208
mistralclient/commands/v2/workbooks.py
Normal file
@ -0,0 +1,208 @@
|
||||
# Copyright 2014 - Mirantis, Inc.
|
||||
# All Rights Reserved
|
||||
#
|
||||
# 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 argparse
|
||||
import logging
|
||||
|
||||
from cliff import command
|
||||
from cliff import lister
|
||||
from cliff import show
|
||||
|
||||
from mistralclient.api.v2 import workbooks
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def format(workbook=None):
|
||||
columns = (
|
||||
'Name',
|
||||
'Tags',
|
||||
'Created at',
|
||||
'Updated at'
|
||||
)
|
||||
|
||||
if workbook:
|
||||
data = (
|
||||
workbook.name,
|
||||
', '.join(workbook.tags or '') or '<none>',
|
||||
workbook.created_at,
|
||||
)
|
||||
|
||||
if hasattr(workbook, 'updated_at'):
|
||||
data += (workbook.updated_at or '<none>',)
|
||||
else:
|
||||
data += (None,)
|
||||
|
||||
else:
|
||||
data = (tuple('<none>' for _ in range(len(columns))),)
|
||||
|
||||
return columns, data
|
||||
|
||||
|
||||
class List(lister.Lister):
|
||||
"""List all workbooks."""
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
data = [format(workbook)[1] for workbook
|
||||
in workbooks.WorkbookManager(self.app.client).list()]
|
||||
|
||||
if data:
|
||||
return format()[0], data
|
||||
else:
|
||||
return format()
|
||||
|
||||
|
||||
class Get(show.ShowOne):
|
||||
"""Show specific workbook."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(Get, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'name',
|
||||
help='Workbook name')
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
workbook = workbooks.WorkbookManager(self.app.client).get(
|
||||
parsed_args.name)
|
||||
|
||||
return format(workbook)
|
||||
|
||||
|
||||
class Create(show.ShowOne):
|
||||
"""Create new workbook."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(Create, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'name',
|
||||
help='Workbook name')
|
||||
parser.add_argument(
|
||||
'tags',
|
||||
nargs='?',
|
||||
help='Workbook tags separated by ","')
|
||||
parser.add_argument(
|
||||
'definition',
|
||||
nargs='?',
|
||||
type=argparse.FileType('r'),
|
||||
help='Workbook definition file'
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
if parsed_args.definition:
|
||||
workbook = workbooks.WorkbookManager(self.app.client)\
|
||||
.create(parsed_args.name,
|
||||
str(parsed_args.tags).split(','),
|
||||
parsed_args.definition.read())
|
||||
else:
|
||||
workbook = workbooks.WorkbookManager(self.app.client)\
|
||||
.create(parsed_args.name,
|
||||
str(parsed_args.tags).split(','), None)
|
||||
|
||||
return format(workbook)
|
||||
|
||||
|
||||
class Delete(command.Command):
|
||||
"""Delete workbook."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(Delete, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'name',
|
||||
help='Workbook name')
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
workbooks.WorkbookManager(self.app.client).delete(parsed_args.name)
|
||||
|
||||
|
||||
class Update(show.ShowOne):
|
||||
"""Update workbook."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(Update, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'name',
|
||||
help='Workbook name')
|
||||
parser.add_argument(
|
||||
'tags',
|
||||
nargs='?',
|
||||
help='Workbook tags separated by ","')
|
||||
parser.add_argument(
|
||||
'definition',
|
||||
nargs='?',
|
||||
type=argparse.FileType('r'),
|
||||
help='Workbook definition file'
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
if parsed_args.definition:
|
||||
workbook = workbooks.WorkbookManager(self.app.client)\
|
||||
.update(parsed_args.name,
|
||||
str(parsed_args.tags).split(','),
|
||||
parsed_args.definition.read())
|
||||
return format(workbook)
|
||||
else:
|
||||
workbook = workbooks.WorkbookManager(self.app.client)\
|
||||
.update(parsed_args.name,
|
||||
tags=str(parsed_args.tags).split(','))
|
||||
return format(workbook)
|
||||
|
||||
|
||||
class UploadDefinition(command.Command):
|
||||
"""Upload workbook definition."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(UploadDefinition, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'name',
|
||||
help='Workbook name')
|
||||
parser.add_argument(
|
||||
'path',
|
||||
type=argparse.FileType('r'),
|
||||
help='Workbook definition file')
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
workbook = workbooks.WorkbookManager(self.app.client)\
|
||||
.update(parsed_args.name,
|
||||
definition=parsed_args.path.read())
|
||||
|
||||
self.app.stdout.write(workbook.definition or "\n")
|
||||
|
||||
|
||||
class GetDefinition(command.Command):
|
||||
"""Show workbook definition."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(GetDefinition, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'name',
|
||||
help='Workbook name')
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
definition = workbooks.WorkbookManager(self.app.client)\
|
||||
.get(parsed_args.name).definition
|
||||
|
||||
self.app.stdout.write(definition or "\n")
|
206
mistralclient/commands/v2/workflows.py
Normal file
206
mistralclient/commands/v2/workflows.py
Normal file
@ -0,0 +1,206 @@
|
||||
# Copyright 2014 - Mirantis, Inc.
|
||||
# All Rights Reserved
|
||||
#
|
||||
# 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 argparse
|
||||
import logging
|
||||
|
||||
from cliff import command
|
||||
from cliff import lister
|
||||
from cliff import show
|
||||
|
||||
from mistralclient.api.v2 import workflows
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def format(workflow=None):
|
||||
columns = (
|
||||
'Name',
|
||||
'Tags',
|
||||
'Created at',
|
||||
'Updated at'
|
||||
)
|
||||
|
||||
if workflow:
|
||||
data = (
|
||||
workflow.name,
|
||||
', '.join(workflow.tags or '') or '<none>',
|
||||
workflow.created_at,
|
||||
)
|
||||
if hasattr(workflow, 'updated_at'):
|
||||
data += (workflow.updated_at,)
|
||||
else:
|
||||
data += (None,)
|
||||
else:
|
||||
data = (tuple('<none>' for _ in range(len(columns))),)
|
||||
|
||||
return columns, data
|
||||
|
||||
|
||||
class List(lister.Lister):
|
||||
"""List all workflows."""
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
data = [format(workflow)[1] for workflow
|
||||
in workflows.WorkflowManager(self.app.client).list()]
|
||||
|
||||
if data:
|
||||
return format()[0], data
|
||||
else:
|
||||
return format()
|
||||
|
||||
|
||||
class Get(show.ShowOne):
|
||||
"""Show specific workflow."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(Get, self).get_parser(prog_name)
|
||||
|
||||
parser.add_argument(
|
||||
'name',
|
||||
help='Workflow name')
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
workflow = workflows.WorkflowManager(self.app.client).get(
|
||||
parsed_args.name)
|
||||
|
||||
return format(workflow)
|
||||
|
||||
|
||||
class Create(show.ShowOne):
|
||||
"""Create new workflow."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(Create, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'name',
|
||||
help='Workflow name')
|
||||
parser.add_argument(
|
||||
'tags',
|
||||
nargs='?',
|
||||
help='Workflow tags separated by ","')
|
||||
parser.add_argument(
|
||||
'definition',
|
||||
nargs='?',
|
||||
type=argparse.FileType('r'),
|
||||
help='Workflow definition file'
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
if not parsed_args.definition:
|
||||
raise RuntimeError("You must provide path to workflow "
|
||||
"definition file.")
|
||||
|
||||
workflow = workflows.WorkflowManager(self.app.client)\
|
||||
.create(parsed_args.name,
|
||||
parsed_args.definition.read(),
|
||||
str(parsed_args.tags).split(','))
|
||||
|
||||
return format(workflow)
|
||||
|
||||
|
||||
class Delete(command.Command):
|
||||
"""Delete workflow."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(Delete, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'name',
|
||||
help='Workflow name')
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
workflows.WorkflowManager(self.app.client).delete(parsed_args.name)
|
||||
|
||||
|
||||
class Update(show.ShowOne):
|
||||
"""Update workflow."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(Update, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'name',
|
||||
help='Workflow name')
|
||||
parser.add_argument(
|
||||
'tags',
|
||||
nargs='?',
|
||||
help='Workflow tags separated by ","')
|
||||
parser.add_argument(
|
||||
'definition',
|
||||
nargs='?',
|
||||
help='Workflow definition')
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
if parsed_args.definition:
|
||||
workflow = workflows.WorkflowManager(self.app.client)\
|
||||
.update(parsed_args.name,
|
||||
parsed_args.definition.read(),
|
||||
str(parsed_args.tags).split(','))
|
||||
else:
|
||||
workflow = workflows.WorkflowManager(self.app.client)\
|
||||
.update(parsed_args.name,
|
||||
None,
|
||||
str(parsed_args.tags).split(','))
|
||||
|
||||
return format(workflow)
|
||||
|
||||
|
||||
class UploadDefinition(command.Command):
|
||||
"""Upload workflow definition."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(UploadDefinition, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'name',
|
||||
help='Workflow name')
|
||||
parser.add_argument(
|
||||
'path',
|
||||
type=argparse.FileType('r'),
|
||||
help='Workflow definition file')
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
workflow = workflows.WorkflowManager(self.app.client)\
|
||||
.update(parsed_args.name,
|
||||
definition=parsed_args.path.read())
|
||||
|
||||
self.app.stdout.write(workflow.definition or "\n")
|
||||
|
||||
|
||||
class GetDefinition(command.Command):
|
||||
"""Show workflow definition."""
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(GetDefinition, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'name',
|
||||
help='Workflow name')
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
definition = workflows.WorkflowManager(self.app.client)\
|
||||
.get(parsed_args.name).definition
|
||||
|
||||
self.app.stdout.write(definition or "\n")
|
@ -25,50 +25,34 @@ from mistralclient.openstack.common.cliutils import env
|
||||
|
||||
from mistralclient.api import client
|
||||
|
||||
import mistralclient.commands.workbooks
|
||||
import mistralclient.commands.executions
|
||||
import mistralclient.commands.tasks
|
||||
import mistralclient.commands.v1.workbooks
|
||||
import mistralclient.commands.v1.executions
|
||||
import mistralclient.commands.v1.tasks
|
||||
import mistralclient.commands.v2.workbooks
|
||||
import mistralclient.commands.v2.workflows
|
||||
import mistralclient.commands.v2.executions
|
||||
import mistralclient.commands.v2.tasks
|
||||
|
||||
from cliff.app import App
|
||||
from cliff.help import HelpAction
|
||||
from cliff.commandmanager import CommandManager
|
||||
from cliff import app
|
||||
from cliff import help
|
||||
from cliff import commandmanager
|
||||
|
||||
import argparse
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MistralShell(App):
|
||||
class MistralShell(app.App):
|
||||
|
||||
def __init__(self):
|
||||
super(MistralShell, self).__init__(
|
||||
description=__doc__.strip(),
|
||||
version='0.1',
|
||||
command_manager=CommandManager('mistral.cli'),
|
||||
command_manager=commandmanager.CommandManager('mistral.cli'),
|
||||
)
|
||||
|
||||
self.commands = {
|
||||
'workbook-list': mistralclient.commands.workbooks.List,
|
||||
'workbook-get': mistralclient.commands.workbooks.Get,
|
||||
'workbook-create': mistralclient.commands.workbooks.Create,
|
||||
'workbook-delete': mistralclient.commands.workbooks.Delete,
|
||||
'workbook-update': mistralclient.commands.workbooks.Update,
|
||||
'workbook-upload-definition':
|
||||
mistralclient.commands.workbooks.UploadDefinition,
|
||||
'workbook-get-definition':
|
||||
mistralclient.commands.workbooks.GetDefinition,
|
||||
'execution-list': mistralclient.commands.executions.List,
|
||||
'execution-get': mistralclient.commands.executions.Get,
|
||||
'execution-create': mistralclient.commands.executions.Create,
|
||||
'execution-delete': mistralclient.commands.executions.Delete,
|
||||
'execution-update': mistralclient.commands.executions.Update,
|
||||
'task-list': mistralclient.commands.tasks.List,
|
||||
'task-get': mistralclient.commands.tasks.Get,
|
||||
'task-update': mistralclient.commands.tasks.Update,
|
||||
}
|
||||
|
||||
for k, v in self.commands.items():
|
||||
self.command_manager.add_command(k, v)
|
||||
# Set v2 commands by default
|
||||
self._set_shell_commands(self._get_commands_v2())
|
||||
|
||||
def configure_logging(self):
|
||||
super(MistralShell, self).configure_logging()
|
||||
@ -125,7 +109,7 @@ class MistralShell(App):
|
||||
)
|
||||
parser.add_argument(
|
||||
'-h', '--help',
|
||||
action=HelpAction,
|
||||
action=help.HelpAction,
|
||||
nargs=0,
|
||||
default=self, # tricky
|
||||
help="Show this help message and exit.",
|
||||
@ -140,7 +124,7 @@ class MistralShell(App):
|
||||
'--os-mistral-url',
|
||||
action='store',
|
||||
dest='mistral_url',
|
||||
default=env('OS_MISTRAL_URL', default='http://localhost:8989/v1'),
|
||||
default=env('OS_MISTRAL_URL', default='http://localhost:8989/v2'),
|
||||
help='Mistral API host (Env: OS_MISTRAL_URL)'
|
||||
)
|
||||
parser.add_argument(
|
||||
@ -188,6 +172,10 @@ class MistralShell(App):
|
||||
return parser
|
||||
|
||||
def initialize_app(self, argv):
|
||||
self._clear_shell_commands()
|
||||
self._set_shell_commands(self._get_commands(
|
||||
client.determine_client_version(self.options.mistral_url)))
|
||||
|
||||
self.client = client.client(mistral_url=self.options.mistral_url,
|
||||
username=self.options.username,
|
||||
api_key=self.options.password,
|
||||
@ -198,6 +186,81 @@ class MistralShell(App):
|
||||
service_type='workflow',
|
||||
auth_token=self.options.token)
|
||||
|
||||
def _set_shell_commands(self, cmds_dict):
|
||||
for k, v in cmds_dict.items():
|
||||
self.command_manager.add_command(k, v)
|
||||
|
||||
def _clear_shell_commands(self):
|
||||
exclude_cmds = ['help', 'complete']
|
||||
|
||||
cmds = self.command_manager.commands.copy()
|
||||
for k, v in cmds.items():
|
||||
if k not in exclude_cmds:
|
||||
self.command_manager.commands.pop(k)
|
||||
|
||||
def _get_commands(self, version):
|
||||
if version == 1:
|
||||
return self._get_commands_v1()
|
||||
else:
|
||||
return self._get_commands_v2()
|
||||
|
||||
def _get_commands_v1(self):
|
||||
return {
|
||||
'workbook-list': mistralclient.commands.v1.workbooks.List,
|
||||
'workbook-get': mistralclient.commands.v1.workbooks.Get,
|
||||
'workbook-create': mistralclient.commands.v1.workbooks.Create,
|
||||
'workbook-delete': mistralclient.commands.v1.workbooks.Delete,
|
||||
'workbook-update': mistralclient.commands.v1.workbooks.Update,
|
||||
'workbook-upload-definition':
|
||||
mistralclient.commands.v1.workbooks.UploadDefinition,
|
||||
'workbook-get-definition':
|
||||
mistralclient.commands.v1.workbooks.GetDefinition,
|
||||
'execution-list': mistralclient.commands.v1.executions.List,
|
||||
'execution-get': mistralclient.commands.v1.executions.Get,
|
||||
'execution-create': mistralclient.commands.v1.executions.Create,
|
||||
'execution-delete': mistralclient.commands.v1.executions.Delete,
|
||||
'execution-update': mistralclient.commands.v1.executions.Update,
|
||||
'task-list': mistralclient.commands.v1.tasks.List,
|
||||
'task-get': mistralclient.commands.v1.tasks.Get,
|
||||
'task-update': mistralclient.commands.v1.tasks.Update,
|
||||
}
|
||||
|
||||
def _get_commands_v2(self):
|
||||
return {
|
||||
'workbook-list': mistralclient.commands.v2.workbooks.List,
|
||||
'workbook-get': mistralclient.commands.v2.workbooks.Get,
|
||||
'workbook-create': mistralclient.commands.v2.workbooks.Create,
|
||||
'workbook-delete': mistralclient.commands.v2.workbooks.Delete,
|
||||
'workbook-update': mistralclient.commands.v2.workbooks.Update,
|
||||
'workbook-upload-definition':
|
||||
mistralclient.commands.v2.workbooks.UploadDefinition,
|
||||
'workbook-get-definition':
|
||||
mistralclient.commands.v2.workbooks.GetDefinition,
|
||||
'execution-list': mistralclient.commands.v2.executions.List,
|
||||
'execution-get': mistralclient.commands.v2.executions.Get,
|
||||
'execution-get-input':
|
||||
mistralclient.commands.v2.executions.GetInput,
|
||||
'execution-get-output':
|
||||
mistralclient.commands.v2.executions.GetOutput,
|
||||
'execution-create': mistralclient.commands.v2.executions.Create,
|
||||
'execution-delete': mistralclient.commands.v2.executions.Delete,
|
||||
'execution-update': mistralclient.commands.v2.executions.Update,
|
||||
'task-list': mistralclient.commands.v2.tasks.List,
|
||||
'task-get': mistralclient.commands.v2.tasks.Get,
|
||||
'task-get-output': mistralclient.commands.v2.tasks.GetOutput,
|
||||
'task-get-result': mistralclient.commands.v2.tasks.GetResult,
|
||||
'task-update': mistralclient.commands.v2.tasks.Update,
|
||||
'workflow-list': mistralclient.commands.v2.workflows.List,
|
||||
'workflow-get': mistralclient.commands.v2.workflows.Get,
|
||||
'workflow-create': mistralclient.commands.v2.workflows.Create,
|
||||
'workflow-delete': mistralclient.commands.v2.workflows.Delete,
|
||||
'workflow-update': mistralclient.commands.v2.workflows.Update,
|
||||
'workflow-upload-definition':
|
||||
mistralclient.commands.v2.workflows.UploadDefinition,
|
||||
'workflow-get-definition':
|
||||
mistralclient.commands.v2.workflows.GetDefinition
|
||||
}
|
||||
|
||||
|
||||
def main(argv=sys.argv[1:]):
|
||||
return MistralShell().run(argv)
|
||||
|
@ -18,13 +18,18 @@ from tempest import cli
|
||||
from tempest import exceptions
|
||||
|
||||
|
||||
MISTRAL_URL = "http://localhost:8989/v1"
|
||||
|
||||
|
||||
class MistralCLIAuth(cli.ClientTestBase):
|
||||
|
||||
def mistral(self, action, flags='', params='', admin=True, fail_ok=False,
|
||||
keystone_version=3):
|
||||
"""Executes Mistral command."""
|
||||
mistral_url_op = "--os-mistral-url %s" % MISTRAL_URL
|
||||
return self.cmd_with_auth(
|
||||
'mistral', action, flags, params, admin, fail_ok, keystone_version)
|
||||
'mistral %s' % mistral_url_op, action, flags, params, admin,
|
||||
fail_ok, keystone_version)
|
||||
|
||||
|
||||
class SimpleMistralCLITests(MistralCLIAuth):
|
||||
@ -34,24 +39,6 @@ class SimpleMistralCLITests(MistralCLIAuth):
|
||||
def setUpClass(cls):
|
||||
super(SimpleMistralCLITests, cls).setUpClass()
|
||||
|
||||
def test_command_help(self):
|
||||
mistral_help = self.mistral('--help')
|
||||
|
||||
self.assertIn('Command-line interface to the Mistral APIs',
|
||||
mistral_help)
|
||||
self.assertIn('Commands:', mistral_help)
|
||||
|
||||
expected_commands = ('complete', 'execution-create',
|
||||
'execution-delete', 'execution-get',
|
||||
'execution-list', 'execution-update',
|
||||
'help', 'task-get', 'task-list',
|
||||
'task-update', 'workbook-create',
|
||||
'workbook-delete', 'workbook-get',
|
||||
'workbook-get-definition', 'workbook-list',
|
||||
'workbook-update', 'workbook-upload-definition')
|
||||
for command in expected_commands:
|
||||
self.assertIn(command, mistral_help)
|
||||
|
||||
def test_workbooks_list(self):
|
||||
workbooks = self.parser.listing(self.mistral('workbook-list'))
|
||||
self.assertTableStruct(workbooks,
|
||||
|
@ -13,7 +13,8 @@ class ClientAuth(rest_client.RestClient):
|
||||
super(ClientAuth, self).__init__(auth_provider)
|
||||
|
||||
self.mistral_client = mclient.Client(
|
||||
auth_token=self.auth_provider.get_token())
|
||||
auth_token=self.auth_provider.get_token(),
|
||||
mistral_url="http://localhost:8989/v1")
|
||||
|
||||
|
||||
class MistralBase(testtools.TestCase):
|
||||
|
@ -19,7 +19,7 @@ import pkg_resources as pkg
|
||||
import mock
|
||||
|
||||
from mistralclient.tests.unit import base
|
||||
from mistralclient.commands import executions
|
||||
from mistralclient.commands.v1 import executions
|
||||
from mistralclient.api.v1.executions import Execution
|
||||
|
||||
EXECUTION = Execution(mock, {
|
||||
|
@ -18,7 +18,7 @@ import mock
|
||||
|
||||
from mistralclient.tests.unit import base
|
||||
|
||||
from mistralclient.commands import tasks
|
||||
from mistralclient.commands.v1 import tasks
|
||||
from mistralclient.api.v1.tasks import Task
|
||||
|
||||
TASK = Task(mock, {
|
||||
|
@ -18,7 +18,7 @@ import mock
|
||||
|
||||
from mistralclient.tests.unit import base
|
||||
|
||||
from mistralclient.commands import workbooks
|
||||
from mistralclient.commands.v1 import workbooks
|
||||
from mistralclient.api.v1.workbooks import Workbook
|
||||
|
||||
WORKBOOK = Workbook(mock, {
|
||||
|
@ -45,7 +45,6 @@ Workflows:
|
||||
|
||||
WORKBOOK = {
|
||||
'name': "my_workbook",
|
||||
'description': "My cool Mistral workbook",
|
||||
'tags': ['deployment', 'demo'],
|
||||
'definition': WB_DEF
|
||||
}
|
||||
@ -61,9 +60,8 @@ class TestWorkbooksV2(base.BaseClientV2Test):
|
||||
mock = self.mock_http_post(content=WORKBOOK)
|
||||
|
||||
wb = self.workbooks.create(WORKBOOK['name'],
|
||||
WORKBOOK['definition'],
|
||||
WORKBOOK['description'],
|
||||
WORKBOOK['tags'])
|
||||
WORKBOOK['tags'],
|
||||
WORKBOOK['definition'])
|
||||
|
||||
self.assertIsNotNone(wb)
|
||||
self.assertEqual(workbooks.Workbook(self.workbooks,
|
||||
@ -74,9 +72,8 @@ class TestWorkbooksV2(base.BaseClientV2Test):
|
||||
mock = self.mock_http_put(content=WORKBOOK)
|
||||
|
||||
wb = self.workbooks.update(WORKBOOK['name'],
|
||||
WORKBOOK['definition'],
|
||||
description=WORKBOOK['description'],
|
||||
tags=WORKBOOK['tags'])
|
||||
WORKBOOK['tags'],
|
||||
WORKBOOK['definition'])
|
||||
|
||||
self.assertIsNotNone(wb)
|
||||
self.assertEqual(workbooks.Workbook(self.workbooks,
|
||||
|
Loading…
Reference in New Issue
Block a user