Move mistral demo-app to mistral-extra

Change-Id: I1790309fddb66a6c1fc91b479399a6eb88f189fa
This commit is contained in:
Nikolay Mahotkin 2014-01-20 19:25:31 +04:00
parent 709ee551ea
commit 5e749d114d
15 changed files with 526 additions and 0 deletions

View File

@ -1,3 +1,4 @@
git+https://github.com/stackforge/python-mistralclient.git
pbr>=0.5.21,<1.0
eventlet>=0.13.0
pyyaml

42
simple_app/api/app.py Normal file
View File

@ -0,0 +1,42 @@
# -*- coding: utf-8 -*-
#
# Copyright 2013 - 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 pecan
app = {
'root': 'demo_app.api.controllers.root.RootController',
'modules': ['demo_app.api'],
'debug': True,
}
def get_pecan_config():
# Set up the pecan configuration
return pecan.configuration.conf_from_dict(app)
def setup_app(config=None):
if not config:
config = get_pecan_config()
app_conf = dict(config)
return pecan.make_app(
app_conf.pop('root'),
logging=getattr(config, 'logging', {}),
**app_conf
)

60
simple_app/api/client.py Normal file
View File

@ -0,0 +1,60 @@
# -*- coding: utf-8 -*-
#
# Copyright 2013 - 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 mock
import pkg_resources as pkg
from mistralclient.api import client
from simple_app import version
MISTRAL_URL = "http://localhost:8989/v1"
client.Client.authenticate = mock.MagicMock(return_value=(MISTRAL_URL,
"", "", ""))
CLIENT = client.Client(mistral_url=MISTRAL_URL,
project_name="mistral_demo")
WB_NAME = "myWorkbook"
TARGET_TASK = "task4"
def upload_workbook():
try:
CLIENT.workbooks.get(WB_NAME)
except:
CLIENT.workbooks.create(WB_NAME,
description="My test workbook",
tags=["test"])
print("Uploading workbook definition...\n")
definition = get_workbook_definition()
CLIENT.workbooks.upload_definition(WB_NAME, definition)
print definition
print("\nUploaded.")
def get_workbook_definition():
return open(pkg.resource_filename(version.version_info.package,
"demo.yaml")).read()
def start_execution():
import threading
t = threading.Thread(target=CLIENT.executions.create,
kwargs={'workbook_name': WB_NAME,
'target_task': TARGET_TASK})
t.start()
return "accepted"

View File

View File

@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
#
# Copyright 2013 - 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 logging
from wsme import types as wtypes
LOG = logging.getLogger(__name__)
API_STATUS = wtypes.Enum(str, 'SUPPORTED', 'CURRENT', 'DEPRECATED')
class Resource(wtypes.Base):
"""REST API Resource."""
@classmethod
def from_dict(cls, d):
# TODO: take care of nested resources
obj = cls()
for key, val in d.items():
if hasattr(obj, key):
setattr(obj, key, val)
return obj
def __str__(self):
"""WSME based implementation of __str__."""
res = "%s [" % type(self).__name__
first = True
for attr in self._wsme_attributes:
if not first:
res += ', '
else:
first = False
res += "%s='%s'" % (attr.name, getattr(self, attr.name))
return res + "]"

View File

@ -0,0 +1,69 @@
# -*- coding: utf-8 -*-
#
# Copyright 2013 - 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 logging
import pecan
from pecan import rest
from wsme import types as wtypes
import wsmeext.pecan as wsme_pecan
from simple_app.api.controllers import resource
from simple_app.api.controllers import tasks
from simple_app.api import client
LOG = logging.getLogger(__name__)
API_STATUS = wtypes.Enum(str, 'SUPPORTED', 'CURRENT', 'DEPRECATED')
class Link(resource.Resource):
"""Web link."""
href = wtypes.text
target = wtypes.text
class APIVersion(resource.Resource):
"""API Version."""
id = wtypes.text
status = API_STATUS
link = Link
class StartController(rest.RestController):
@wsme_pecan.wsexpose(wtypes.text)
def get(self):
print("Start execution for: %s" % client.TARGET_TASK)
return client.start_execution()
class RootController(object):
tasks = tasks.Controller()
start = StartController()
@wsme_pecan.wsexpose([APIVersion])
def index(self):
LOG.debug("Fetching API versions.")
host_url = '%s/%s' % (pecan.request.host_url, 'v1')
api_v1 = APIVersion(id='v1.0',
status='CURRENT',
link=Link(href=host_url, target='v1'))
return [api_v1]

View File

@ -0,0 +1,70 @@
# -*- coding: utf-8 -*-
#
# Copyright 2013 - 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 logging
from pecan import abort
from pecan import rest
import pecan
from wsme import types as wtypes
import wsmeext.pecan as wsme_pecan
from simple_app import tasks
LOG = logging.getLogger(__name__)
class Controller(rest.RestController):
"""API root controller"""
@wsme_pecan.wsexpose(wtypes.text)
def get_all(self):
LOG.debug("Fetch items.")
values = {
'tasks': [
'task1',
'task2',
'task3',
'task4'
]
}
if not values:
abort(404)
else:
return values
@wsme_pecan.wsexpose(wtypes.text, wtypes.text)
def get(self, name):
print("Task '%s' is starting" % name)
value = "Task %s accepted" % name
tasks.start_task(**self.get_mistral_headers())
return value
def get_mistral_headers(self):
headers = pecan.request.headers
try:
needed_headers = {
'workbook_name': headers['Mistral-Workbook-Name'],
'execution_id': headers['Mistral-Execution-Id'],
'task_id': headers['Mistral-Task-Id']
}
return needed_headers
except KeyError:
raise RuntimeError("Could not find http headers for "
"defining mistral task")

View File

80
simple_app/cmd/main.py Normal file
View File

@ -0,0 +1,80 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2013 - 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.
"""Script to start Demo API service."""
import eventlet
import logging
import os
from requests import exceptions
import sys
import threading
from time import sleep
from wsgiref import simple_server
from oslo.config import cfg
from simple_app import config
from simple_app.api import app
from simple_app.api import client
eventlet.monkey_patch(
os=True, select=True, socket=True, thread=True, time=True)
logging.basicConfig(level=logging.WARN)
LOG = logging.getLogger(__name__)
CLIENT = client.CLIENT
def upload_wb_and_start():
sleep(5)
try:
client.upload_workbook()
except exceptions.ConnectionError:
LOG.error("Error. Mistral service probably is not working now")
sys.exit(1)
print("Start execution for: %s" % client.TARGET_TASK)
client.start_execution()
def main():
try:
config.parse_args()
host = cfg.CONF.api.host
port = cfg.CONF.api.port
server = simple_server.make_server(host, port, app.setup_app())
LOG.info("Demo app API is serving on http://%s:%s (PID=%s)" %
(host, port, os.getpid()))
server.serve_forever()
except RuntimeError, e:
sys.stderr.write("ERROR: %s\n" % e)
sys.exit(1)
if __name__ == '__main__':
upload_thread = threading.Thread(target=upload_wb_and_start)
upload_thread.run()
main()

36
simple_app/config.py Normal file
View File

@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
#
# Copyright 2013 - 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.
from oslo.config import cfg
from simple_app import version
api_opts = [
cfg.StrOpt('host', default='0.0.0.0', help='Simple-app API server host'),
cfg.IntOpt('port', default=8988, help='Simple-app API server port')
]
CONF = cfg.CONF
CONF.register_opts(api_opts, group='api')
def parse_args(args=None, usage=None, default_config_files=None):
CONF(args=args,
project='mistral-demo',
version=version,
usage=usage,
default_config_files=default_config_files)

57
simple_app/demo.yaml Normal file
View File

@ -0,0 +1,57 @@
Services:
MyRest:
type: REST_API
parameters:
baseUrl: http://localhost:8988
actions:
task1:
parameters:
url: /tasks/task1
method: GET
task-parameters:
task2:
parameters:
url: /tasks/task2
method: GET
task-parameters:
task3:
parameters:
url: /tasks/task3
method: GET
task-parameters:
task4:
parameters:
url: /tasks/task4
method: GET
task-parameters:
Workflow:
tasks:
task1:
action: MyRest:task1
parameters:
task2:
requires: [task1]
action: MyRest:task2
parameters:
task3:
requires: [task1]
action: MyRest:task3
parameters:
task4:
requires: [task2, task3]
action: MyRest:task4
parameters:
events:
task4:
type: periodic
tasks: task4
parameters:
cron-pattern: "*/1 * * * *"

37
simple_app/tasks.py Normal file
View File

@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
#
# Copyright 2013 - 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.
from time import sleep
import threading
from simple_app.api import client
CLIENT = client.CLIENT
def start_task(**kwargs):
thread = threading.Thread(target=finish_task, kwargs=kwargs)
thread.start()
def finish_task(task_id, execution_id, workbook_name):
# simulate working
sleep(8)
task = CLIENT.tasks.update(workbook_name, execution_id,
task_id, "SUCCESS")
print("Task %s - SUCCESS" % task.name)

20
simple_app/version.py Normal file
View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
#
# Copyright 2013 - 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.
from pbr import version
version_info = version.VersionInfo('simple_app')
version_string = version_info.version_string