Skip to content
This repository has been archived by the owner on Oct 5, 2020. It is now read-only.

Commit

Permalink
Merge pull request #18 from cloudify-cosmo/feature/CFY-780-events-api
Browse files Browse the repository at this point in the history
Feature/cfy 780 events api
  • Loading branch information
idanmo committed Jun 11, 2014
2 parents d6d7233 + 4f01aef commit ce656ec
Show file tree
Hide file tree
Showing 10 changed files with 136 additions and 355 deletions.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,3 @@ install:

script:
- flake8 .
- nosetests cosmo_manager_rest_client/tests
20 changes: 11 additions & 9 deletions cloudify_rest_client/blueprints.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ def __init__(self, blueprint):

@property
def id(self):
"""
:return: The identifier of the blueprint.
"""
return self['id']


Expand Down Expand Up @@ -152,7 +155,7 @@ def delete(self, blueprint_id):
"""
assert blueprint_id
response = self.api.delete('/blueprints/{0}'.format(blueprint_id))
return response
return Blueprint(response)

def download(self, blueprint_id, output_file=None):
"""
Expand All @@ -163,26 +166,25 @@ def download(self, blueprint_id, output_file=None):
(optional)
:return: The file path of the downloaded blueprint.
"""
resource_path = '/blueprints/{0}/archive'.format(blueprint_id)
url = self.api_client.resource_url(resource_path)

r = requests.get(url, stream=True)
self.api_client.raise_if_not(requests.codes.ok, r, url)
url = '{0}{1}'.format(self.api.url,
'/blueprints/{0}/archive'.format(blueprint_id))
response = requests.get(url, stream=True)
self.api.verify_response_status(response, 200)

if not output_file:
if self.CONTENT_DISPOSITION_HEADER not in r.headers:
if self.CONTENT_DISPOSITION_HEADER not in response.headers:
raise RuntimeError(
'Cannot determine attachment filename: {0} header not'
' found in response headers'.format(
self.CONTENT_DISPOSITION_HEADER))
output_file = r.headers[
output_file = response.headers[
self.CONTENT_DISPOSITION_HEADER].split('filename=')[1]

if os.path.exists(output_file):
raise OSError("Output file '%s' already exists" % output_file)

with open(output_file, 'wb') as f:
for chunk in r.iter_content(chunk_size=8096):
for chunk in response.iter_content(chunk_size=8096):
if chunk:
f.write(chunk)
f.flush()
Expand Down
2 changes: 2 additions & 0 deletions cloudify_rest_client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from cloudify_rest_client.executions import ExecutionsClient
from cloudify_rest_client.nodes import NodesClient
from cloudify_rest_client.node_instances import NodeInstancesClient
from cloudify_rest_client.events import EventsClient
from cloudify_rest_client.exceptions import CloudifyClientError


Expand Down Expand Up @@ -121,3 +122,4 @@ def __init__(self, host, port=80):
self.executions = ExecutionsClient(self._client)
self.nodes = NodesClient(self._client)
self.node_instances = NodeInstancesClient(self._client)
self.events = EventsClient(self._client)
35 changes: 26 additions & 9 deletions cloudify_rest_client/deployments.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ def id(self):
"""
return self['id']

@property
def blueprint_id(self):
"""
:return: The identifier of the blueprint this deployment belongs to.
"""
return self['blueprint_id']


class Workflows(dict):

Expand All @@ -43,11 +50,11 @@ def __init__(self, workflows):

@property
def blueprint_id(self):
return self['blueprintId']
return self['blueprint_id']

@property
def deployment_id(self):
return self['deploymentId']
return self['deployment_id']

@property
def workflows(self):
Expand All @@ -63,6 +70,10 @@ def __init__(self, workflow):
def id(self):
return self['name']

@property
def name(self):
return self['name']


class DeploymentsClient(object):

Expand Down Expand Up @@ -101,22 +112,27 @@ def create(self, blueprint_id, deployment_id):
assert blueprint_id
assert deployment_id
data = {
'blueprintId': blueprint_id
'blueprint_id': blueprint_id
}
uri = '/deployments/{0}'.format(deployment_id)
response = self.api.put(uri, data, expected_status_code=201)
return Deployment(response)

def delete(self, deployment_id):
def delete(self, deployment_id, ignore_live_nodes=False):
"""
Deletes the deployment whose id matches the provided deployment id.
By default, deployment with live nodes deletion is not allowed and
this behavior can be changed using the ignore_live_nodes argument.
:param deployment_id: The deployment's to be deleted id.
:param ignore_live_nodes: Determines whether to ignore live nodes.
:return: The deleted deployment.
"""
assert deployment_id
response = self.api.delete('/deployments/{0}'.format(deployment_id))
return response
params = {'ignore_live_nodes': 'true'} if ignore_live_nodes else None
response = self.api.delete('/deployments/{0}'.format(deployment_id),
params=params)
return Deployment(response)

def list_executions(self, deployment_id):
"""
Expand Down Expand Up @@ -156,13 +172,14 @@ def execute(self, deployment_id, workflow_id, force=False):
assert deployment_id
assert workflow_id
data = {
'workflowId': workflow_id
'workflow_id': workflow_id
}
query_params = {
params = {
'force': str(force).lower()
}
uri = '/deployments/{0}/executions'.format(deployment_id)
response = self.api.post(uri,
data=data,
query_params=query_params)
params=params,
expected_status_code=201)
return Execution(response)
67 changes: 67 additions & 0 deletions cloudify_rest_client/events.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
########
# Copyright (c) 2014 GigaSpaces Technologies Ltd. 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.

__author__ = 'idanmo'


class EventsClient(object):

def __init__(self, api):
self.api = api

@staticmethod
def _create_events_query(execution_id, include_logs):
query = {
"bool": {
"must": [
{"match": {"context.execution_id": execution_id}},
]
}
}
match_cloudify_event = {"match": {"type": "cloudify_event"}}
if include_logs:
match_cloudify_log = {"match": {"type": "cloudify_log"}}
query['bool']['should'] = [
match_cloudify_event, match_cloudify_log
]
else:
query['bool']['must'].append(match_cloudify_event)
return query

def get(self,
execution_id,
from_event=0,
batch_size=100,
include_logs=False):
"""
Returns event for the provided execution id.
:param execution_id: Id of execution to get events for.
:param from_event: Index of first event to retrieve on pagination.
:param batch_size: Maximum number of events to retrieve per call.
:param include_logs: Whether to also get logs.
:return: Events list and total number of currently available
events (tuple).
"""
body = {
"from": from_event,
"size": batch_size,
"sort": [{"@timestamp": {"order": "asc"}}],
"query": self._create_events_query(execution_id, include_logs)
}
response = self.api.get('/events', data=body)
events = map(lambda x: x['_source'], response['hits']['hits'])
total_events = response['hits']['total']
return events, total_events
31 changes: 30 additions & 1 deletion cloudify_rest_client/executions.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,41 @@


class Execution(dict):
"""
Cloudify workflow execution.
"""

def __init__(self, execution):
self.update(execution)

@property
def id(self):
"""
:return: The execution's id.
"""
return self['id']

@property
def status(self):
"""
:return: The execution's status.
"""
return self['status']

@property
def error(self):
"""
:return: The execution error in a case of failure, otherwise None.
"""
return self['error']

@property
def workflow_id(self):
"""
:return: The id of the workflow this execution represents.
"""
return self['workflow_id']


class ExecutionsClient(object):

Expand Down Expand Up @@ -79,5 +106,7 @@ def cancel(self, execution_id):
:return: Cancelled execution.
"""
uri = '/executions/{0}'.format(execution_id)
response = self.api.post(uri, data={'action': 'cancel'})
response = self.api.post(uri,
data={'action': 'cancel'},
expected_status_code=201)
return Execution(response)
Loading

0 comments on commit ce656ec

Please sign in to comment.