result = c.describe_stacks(**parameters)
print json.dumps(result, indent=2)
+@catch_error('events_list')
+def stack_events_list(options, arguments):
+ '''
+ '''
+ parameters = {}
+ try:
+ parameters['StackName'] = arguments.pop(0)
+ except IndexError:
+ print "Please specify the stack name "
+ print "as the first argument"
+ return FAILURE
+
+ c = get_client(options)
+ result = c.list_stack_events(**parameters)
+ print json.dumps(result, indent=2)
+
@catch_error('list')
def stack_list(options, arguments):
'''
'update': stack_update,
'delete': stack_delete,
'list': stack_list,
+ 'events_list': stack_events_list,
'validate': template_validate,
'gettemplate': get_template,
'describe': stack_describe,
jeos_create Create a JEOS image
+ events_list List events for a stack
+
"""
oparser = optparse.OptionParser(version='%%prog %s'
action="delete", conditions=dict(method=["DELETE"]))
mapper.connect("/UpdateStack", controller=stacks_resource,
action="update", conditions=dict(method=["PUT"]))
+ mapper.connect("/DescribeStackEvents", controller=stacks_resource,
+ action="events_list", conditions=dict(method=["GET"]))
super(API, self).__init__(mapper)
return webob.exc.HTTPNotFound()
+ def events_list(self, req):
+ """
+ Returns the following information for all stacks:
+ """
+ c = engine.get_engine_client(req.context)
+ stack_list = c.get_stack_events(**req.params)
+
+ res = {'DescribeStackEventsResult': {'StackEvents': [] } }
+ summaries = res['DescribeStackEventsResult']['StackEvents']
+ for s in stack_list:
+ summaries.append(s)
+
+ return res
+
def create_resource(options):
"""Stacks resource factory method."""
deserializer = wsgi.JSONRequestDeserializer()
data = json.loads(res.read())
return data
+ def list_stack_events(self, **kwargs):
+ params = self._extract_params(kwargs, SUPPORTED_PARAMS)
+ self._insert_common_parameters(params)
+
+ res = self.do_request("GET", "/DescribeStackEvents", params=params)
+ data = json.loads(res.read())
+ return data
+
Client = V1Client
from heat.common import wsgi
from heat.engine.api.v1 import stacks
+from heat.engine.api.v1 import events
class API(wsgi.Router):
"""WSGI entry point for all stac requests."""
collection={'detail': 'GET'})
mapper.connect("/", controller=stacks_resource, action="index")
+ events_resource = events.create_resource(conf)
+ mapper.resource("event", "events", controller=events_resource,
+ parent_resource=dict(member_name='stack',
+ collection_name='stacks'))
+
super(API, self).__init__(mapper)
--- /dev/null
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+#
+# 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.
+
+"""
+Implementation of the stacks server WSGI controller.
+"""
+import json
+import logging
+
+import webob
+from webob.exc import (HTTPNotFound,
+ HTTPConflict,
+ HTTPBadRequest)
+
+from heat.common import exception
+from heat.common import wsgi
+
+from heat.engine import capelistener
+from heat.engine import simpledb
+
+logger = logging.getLogger('heat.engine.api.v1.events')
+
+
+class EventsController(object):
+ '''
+ The controller for the events child "resource"
+ stacks/events
+ '''
+
+ def __init__(self, conf):
+ self.conf = conf
+ self.event_db = {}
+ self.listener = capelistener.CapeEventListener()
+
+ def index(self, req, stack_id):
+ return simpledb.events_get(stack_id)
+
+def create_resource(conf):
+ """Events resource factory method."""
+ deserializer = wsgi.JSONRequestDeserializer()
+ serializer = wsgi.JSONResponseSerializer()
+ return wsgi.Resource(EventsController(conf), deserializer, serializer)
stack_db = {}
-class Controller(object):
+class StacksController(object):
'''
bla
'''
def create(self, req, body=None):
if body is None:
- msg = _("TemplateBody or TemplateUrl were not given.")
+ msg = _("No Template provided.")
return webob.exc.HTTPBadRequest(explanation=msg)
if stack_db.has_key(body['StackName']):
"""Stacks resource factory method."""
deserializer = wsgi.JSONRequestDeserializer()
serializer = wsgi.JSONResponseSerializer()
- return wsgi.Resource(Controller(conf), deserializer, serializer)
+ return wsgi.Resource(StacksController(conf), deserializer, serializer)
import eventlet
from eventlet.green import socket
import fcntl
+import libxml2
import logging
import os
import stat
+from heat.engine import simpledb
-class CapeEventListener:
+
+logger = logging.getLogger('heat.engine.capelistener')
+
+class CapeEventListener(object):
def __init__(self):
self.backlog = 50
if stat.S_ISSOCK(st.st_mode):
os.remove(self.file)
else:
- raise ValueError("File %s exists and is not a socket", self.file)
+ raise ValueError("File %s exists and is not a socket",
+ self.file)
sock.bind(self.file)
sock.listen(self.backlog)
os.chmod(self.file, 0600)
def cape_event_listner(self, sock):
eventlet.serve(sock, self.cape_event_handle)
+ def store(self, xml_event):
+
+ try:
+ doc = libxml2.parseDoc(xml_event)
+ except:
+ return
+
+ event = {'EventId': ''}
+ root = doc.getRootElement()
+ child = root.children
+ while child is not None:
+ if child.type != "element":
+ child = child.next
+ elif child.name == 'event':
+ child = child.children
+ elif child.name == 'application':
+ event['StackId'] = child.prop('name')
+ event['StackName'] = child.prop('name')
+ child = child.children
+ elif child.name == 'node':
+ event['ResourceType'] = 'AWS::EC2::Instance'
+ event['LogicalResourceId'] = child.prop('name')
+ child = child.children
+ elif child.name == 'resource':
+ event['ResourceType'] = 'ORG::HA::Service'
+ event['LogicalResourceId'] = child.prop('name')
+ child = child.children
+ elif child.name == 'state':
+ event['ResourceStatus'] = child.content
+ child = child.next
+ elif child.name == 'reason':
+ event['ResourceStatusReason'] = child.content
+ child = child.next
+ else:
+ child = child.next
+
+ simpledb.event_append(event)
+ doc.freeDoc()
+
def cape_event_handle(self, sock, client_addr):
while True:
x = sock.recv(4096)
- # TODO(asalkeld) format this event "nicely"
- logger.info('%s' % x.strip('\n'))
+ self.store(x.strip('\n'))
if not x: break
-
-
stack = data['stack']
return stack
- def delete_stack(self, stack_name):
+ def delete_stack(self, stack_id):
"""
Deletes Engine's information about an stack
"""
- res = self.do_request("DELETE", "/stacks/%s" % stack_name)
+ res = self.do_request("DELETE", "/stacks/%s" % stack_id)
return res
+ def get_stack_events(self, **kwargs):
+ params = self._extract_params(kwargs, SUPPORTED_PARAMS)
+ res = self.do_request("GET", "/stacks/%s/events" % (params['StackName']),
+ params=params)
+ return json.loads(res.read())['events']
+
def get_engine_addr(conf):
conf.register_opts(engine_addr_opts)
return (conf.engine_host, conf.engine_port)
--- /dev/null
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+#
+# 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 anydbm
+import json
+
+def event_append(event):
+ name = event['StackName']
+ d = anydbm.open('/var/lib/heat/%s.events.db' % name, 'c')
+ if d.has_key('lastid'):
+ newid = int(d['lastid']) + 1
+ else:
+ newid = 1
+ event['EventId'] = '%d' % newid
+ d['lastid'] = event['EventId']
+ d[event['EventId']] = json.dumps(event)
+
+ d.close()
+
+
+def events_get(stack_id):
+ events = {'events': []}
+ try:
+ d = anydbm.open('/var/lib/heat/%s.events.db' % stack_id, 'r')
+ except:
+ return events
+
+ for k, v in d.iteritems():
+ if k != 'lastid':
+ events['events'].append(json.loads(v))
+
+ d.close()
+ return events
+