Integrating all stack, template, and event calls with database

This commit is contained in:
Chris Alfonso
2012-04-05 11:05:11 -04:00
parent 95e1031495
commit 77a004167a
12 changed files with 115 additions and 112 deletions

View File

@@ -19,7 +19,6 @@ import base64
import libxml2
from urlparse import urlparse
# If ../heat/__init__.py exists, add ../ to Python search path, so that
# it will override what happens to be installed in /usr/(local/)lib/python...
possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),

View File

@@ -216,11 +216,12 @@ if [ "${MYSQL_HEAT_PW}" != "${MYSQL_HEAT_PW_DEFAULT}" ] ; then
fi
#create the schema using sqlalchemy-migrate
if test $1 == "rpm"; then
pushd /usr/lib/python2.7/site-packages/heat/db/sqlalchemy
else
#if [ $1='rpm' ];
#then
# pushd /usr/lib/python2.7/site-packages/heat/db/sqlalchemy
#else
pushd /usr/lib/python2.7/site-packages/heat-0.0.1-py2.7.egg/heat/db/sqlalchemy/
fi
#fi
python migrate_repo/manage.py version_control mysql://heat:heat@localhost/heat migrate_repo
python manage.py upgrade

View File

@@ -23,17 +23,14 @@ import os
import socket
import sys
import urlparse
import webob
from webob.exc import (HTTPNotFound,
HTTPConflict,
HTTPBadRequest)
from heat.common import wsgi
from heat.common import config
from heat import rpc
from heat import context
logger = logging.getLogger('heat.api.v1.stacks')
@@ -52,7 +49,9 @@ class StackController(object):
Returns the following information for all stacks:
"""
con = context.get_admin_context()
stack_list = rpc.call(con, 'engine', {'method': 'list_stacks'})
stack_list = rpc.call(con, 'engine',
{'method': 'list_stacks',
'args': {'params': dict(req.params)}})
res = {'ListStacksResponse': {'ListStacksResult': {'StackSummaries': [] } } }
summaries = res['ListStacksResponse']['ListStacksResult']['StackSummaries']
@@ -69,7 +68,8 @@ class StackController(object):
stack_list = rpc.call(con, 'engine',
{'method': 'show_stack',
'args': {'stack_name': req.params['StackName']}})
'args': {'stack_name': req.params['StackName'],
'params': dict(req.params)}})
res = {'DescribeStacksResult': {'Stacks': [] } }
stacks = res['DescribeStacksResult']['Stacks']
for s in stack_list['stacks']:
@@ -160,7 +160,8 @@ class StackController(object):
res = rpc.call(con, 'engine',
{'method': 'delete_stack',
'args': {'stack_name': req.params['StackName']}})
'args': {'stack_name': req.params['StackName'],
'params': dict(req.params)}})
if res == None:
return {'DeleteStackResult': ''}

View File

@@ -20,12 +20,10 @@ Client classes for callers of a heat system
import json
import logging
import os
from heat.common import client as base_client
from heat.common import exception
from heat.cloudformations import *
logger = logging.getLogger(__name__)

View File

@@ -43,7 +43,6 @@ from heat.common import exception
from heat.openstack.common import cfg
from heat.openstack.common import utils
bind_opts = [
cfg.StrOpt('bind_host', default='0.0.0.0'),
cfg.IntOpt('bind_port'),
@@ -489,7 +488,6 @@ class Resource(object):
method = getattr(obj, action)
except AttributeError:
method = getattr(obj, 'default')
return method(*args, **kwargs)
def get_action_args(self, request_environment):

View File

@@ -97,4 +97,3 @@ def event_create(context, event):
d[event['event_id']] = json.dumps(event)
d.close()

View File

@@ -27,7 +27,6 @@ supported backend.
'''
from heat.openstack.common import utils
def configure(conf):
global IMPL
global SQL_CONNECTION
@@ -67,7 +66,7 @@ def resource_create(context, values):
def stack_get(context, stack_id):
return IMPL.resource_get(context, resource_id)
return IMPL.stack_get(context, stack_id)
def stack_get_all(context):
return IMPL.stack_get_all(context)
@@ -75,6 +74,8 @@ def stack_get_all(context):
def stack_create(context, values):
return IMPL.stack_create(context, values)
def stack_delete(context, stack_name):
return IMPL.stack_delete(context, stack_name)
def event_get(context, event_id):
return IMPL.event_get(context, event_id)

View File

@@ -20,33 +20,13 @@ from heat.db.sqlalchemy import models
from heat.db.sqlalchemy.session import get_session
def model_query(context, *args, **kwargs):
"""Query helper that accounts for context's `read_deleted` field.
:param context: context to query under
"""
:param session: if present, the session to use
:param read_deleted: if present, overrides context's read_deleted field.
:param project_only: if present and context is user-type, then restrict
query to match the context's project_id.
"""
session = kwargs.get('session') or get_session()
read_deleted = kwargs.get('read_deleted') or context.read_deleted
project_only = kwargs.get('project_only')
query = session.query(*args)
if read_deleted == 'no':
query = query.filter_by(deleted=False)
elif read_deleted == 'yes':
pass # omit the filter to include deleted and active
elif read_deleted == 'only':
query = query.filter_by(deleted=True)
else:
raise Exception(
_("Unrecognized read_deleted value '%s'") % read_deleted)
if project_only and is_user_context(context):
query = query.filter_by(project_id=context.project_id)
return query
def raw_template_get(context, template_id):
@@ -120,19 +100,11 @@ def resource_create(context, values):
def stack_get(context, stack_id):
result = model_query(context, models.Stack).\
filter_by(id=stack_id).first()
if not result:
raise Exception("stack with id %s not found" % stack_id)
filter_by(name=stack_id).first()
return result
def stack_get_all(context):
results = model_query(context, models.Stack).all()
if not results:
raise Exception('no stacks were found')
return results
def stack_create(context, values):
@@ -140,6 +112,15 @@ def stack_create(context, values):
stack_ref.update(values)
stack_ref.save()
return stack_ref
def stack_delete(context, stack_name):
s = stack_get(context, stack_name)
if not s:
raise Exception('Attempt to delete a stack with id: %s that does not exist' % stack_name)
for e in s.events:
e.delete()
s.delete()
def event_get(context, event_id):
result = model_query(context, models.Event).\

View File

@@ -21,6 +21,7 @@ def upgrade(migrate_engine):
Column('name', String(length=255, convert_unicode=False,
assert_unicode=None,
unicode_error=None, _warn_on_bytestring=False)),
Column('raw_template_id', Integer, ForeignKey("raw_template.id"), nullable=False),
)
event = Table(
@@ -47,17 +48,17 @@ def upgrade(migrate_engine):
assert_unicode=None,
unicode_error=None,
_warn_on_bytestring=False)),
Column('parsed_template_id', Integer, ForeignKey("parsed_template.id"), nullable=False),
)
parsedtemplate = Table(
'parsed_template', meta,
Column('id', Integer, primary_key=True),
Column('resource_id', Integer, ForeignKey("resource.id"),\
nullable=False),
Column('raw_template_id', Integer, ForeignKey("raw_template.id"), nullable=False),
Column('template', Text()),
)
tables = [rawtemplate, stack, event, resource, parsedtemplate]
tables = [rawtemplate, stack, event, parsedtemplate, resource]
for table in tables:
try:
table.create()
@@ -73,6 +74,7 @@ def downgrade(migrate_engine):
event = Table('event', meta, autoload=True)
resource = Table('resource', meta, autoload=True)
parsedtemplate = Table('parsed_template', meta, autoload=True)
stack = Table('stack', meta, autoload=True)
for table in (rawtemplate, event, stack, parsedtemplate, resource):
for table in (event, stack, resource, parsedtemplate, rawtemplate):
table.drop()

View File

@@ -16,15 +16,26 @@ SQLAlchemy models for heat data.
"""
from sqlalchemy import *
from sqlalchemy.orm import relationship, backref
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.schema import ForeignKeyConstraint
from sqlalchemy import types as types
from json import dumps, loads
from nova import utils
from heat.db.sqlalchemy.session import get_session
BASE = declarative_base()
class Json(types.TypeDecorator, types.MutableType):
impl=types.Text
def process_bind_param(self, value, dialect):
return dumps(value)
def process_result_value(self, value, dialect):
return loads(value)
class HeatBase(object):
"""Base class for Heat Models."""
__table_args__ = {'mysql_engine': 'InnoDB'}
@@ -88,14 +99,18 @@ class RawTemplate(BASE, HeatBase):
__tablename__ = 'raw_template'
id = Column(Integer, primary_key=True)
template = Text()
template = Column(Json)
parsed_template = relationship("ParsedTemplate",\
uselist=False, backref="raw_template", cascade="all, delete", passive_deletes=True)
class ParsedTemplate(BASE, HeatBase):
"""Represents a parsed template."""
__tablename__ = 'parsed_template'
id = Column(Integer, primary_key=True)
resource_id = Column('resource_id', Integer)
template = Column(Json)
raw_template_id = Column(Integer, ForeignKey('raw_template.id'),\
nullable=False)
class Stack(BASE, HeatBase):
"""Represents an generated by the heat engine."""
@@ -103,7 +118,11 @@ class Stack(BASE, HeatBase):
__tablename__ = 'stack'
id = Column(Integer, primary_key=True)
name = Column(String)
name = Column(String, unique=True)
raw_template_id = Column(Integer, ForeignKey('raw_template.id'),\
nullable=False)
raw_template = relationship(RawTemplate,
backref=backref('stack'), cascade="all, delete", passive_deletes=True)
class Event(BASE, HeatBase):
"""Represents an event generated by the heat engine."""
@@ -111,7 +130,11 @@ class Event(BASE, HeatBase):
__tablename__ = 'event'
id = Column(Integer, primary_key=True)
stack_id = Column(Integer)
stack_id = Column(Integer, ForeignKey('stack.id'),\
nullable=False)
stack = relationship(Stack,
backref=backref('events'), cascade="all, delete", passive_deletes=True)
name = Column(String)
class Resource(BASE, HeatBase):
@@ -122,3 +145,8 @@ class Resource(BASE, HeatBase):
id = Column(Integer, primary_key=True)
state = Column(String)
state_description = Column('state_description', String)
parsed_template_id = Column(Integer, ForeignKey('parsed_template.id'),\
nullable=False)
parsed_template = relationship(ParsedTemplate,
backref=backref('resources'))

View File

@@ -23,21 +23,12 @@ import tempfile
import time
import traceback
import logging
from eventlet import greenthread
import heat.context
from heat.common import exception
import webob
from heat import manager
from heat.openstack.common import cfg
from heat import rpc
from heat.engine import parser
from heat.db import api as db_api
logger = logging.getLogger('heat.engine.manager')
stack_db = {}
class EngineManager(manager.Manager):
"""Manages the running instances from creation to destruction."""
@@ -45,57 +36,69 @@ class EngineManager(manager.Manager):
"""Load configuration options and connect to the hypervisor."""
pass
def list_stacks(self, context):
def list_stacks(self, context, params):
logger.info('context is %s' % context)
res = {'stacks': [] }
for s in stack_db:
stacks = db_api.stack_get_all(None)
for s in stacks:
ps = parser.Stack(s.name, s.raw_template.template, params)
mem = {}
mem['stack_id'] = s
mem['stack_name'] = s
mem['created_at'] = 'now'
mem['stack_id'] = s.id
mem['stack_name'] = s.name
mem['created_at'] = str(s.created_at)
try:
mem['template_description'] = stack_db[s].t['Description']
mem['stack_status'] = stack_db[s].t['StackStatus']
mem['template_description'] = s.template.description
mem['stack_status'] = ps.t['StackStatus']
except:
mem['template_description'] = 'No description'
mem['stack_status'] = 'unknown'
res['stacks'].append(mem)
return res
def show_stack(self, context, stack_name):
def show_stack(self, context, stack_name, params):
res = {'stacks': [] }
if stack_db.has_key(stack_name):
s = db_api.stack_get(None, id)
if s:
ps = parser.Stack(s.name, s.raw_template.template, params)
mem = {}
mem['stack_id'] = stack_name
mem['stack_name'] = stack_name
mem['creation_at'] = 'TODO'
mem['updated_at'] = 'TODO'
mem['stack_id'] = s.id
mem['stack_name'] = s.name
mem['creation_at'] = s.created_at
mem['updated_at'] = s.updated_at
mem['NotificationARNs'] = 'TODO'
mem['Outputs'] = stack_db[stack_name].get_outputs()
mem['Parameters'] = stack_db[stack_name].t['Parameters']
mem['Outputs'] = ps.get_outputs()
mem['Parameters'] = ps.t['Parameters']
mem['StackStatusReason'] = 'TODO'
mem['TimeoutInMinutes'] = 'TODO'
try:
mem['TemplateDescription'] = stack_db[stack_name].t['Description']
mem['StackStatus'] = stack_db[stack_name].t['StackStatus']
mem['TemplateDescription'] = ps.t['Description']
mem['StackStatus'] = ps.t['StackStatus']
except:
mem['TemplateDescription'] = 'No description'
mem['StackStatus'] = 'unknown'
res['stacks'].append(mem)
return res
def create_stack(self, context, stack_name, template, params):
if stack_db.has_key(stack_name):
logger.info('template is %s' % template)
if db_api.stack_get(None, stack_name):
return {'Error': 'Stack already exists with that name.'}
logger.info('template is %s' % template)
stack_db[stack_name] = parser.Stack(stack_name, template, params)
stack_db[stack_name].create()
return {'stack': {'id': stack_name}}
stack = parser.Stack(stack_name, template, params)
rt = {}
rt['template'] = template
new_rt = db_api.raw_template_create(None, rt)
s = {}
s['name'] = stack_name
s['raw_template_id'] = new_rt.id
new_s = db_api.stack_create(None, s)
stack.id = new_s.id
stack.start()
return {'stack': {'id': new_s.id, 'name': new_s.name,\
'created_at': new_s.created_at}}
def validate_template(self, req, body=None):
@@ -109,13 +112,16 @@ class EngineManager(manager.Manager):
return res
def delete_stack(self, context, stack_name):
if not stack_db.has_key(stack_name):
return {'Error': 'No stack by that name'}
def delete_stack(self, context, stack_name, params):
s = db_api.stack_get(None, stack_name)
if not s:
return {'Error': 'No stack by that name'}
logger.info('deleting stack %s' % stack_name)
stack_db[stack_name].delete()
del stack_db[stack_name]
ps = parser.Stack(s.name, s.raw_template.template, params)
ps.stop()
db_api.stack_delete(None, stack_name)
return None
def list_events(self, context, stack_name):

View File

@@ -23,6 +23,7 @@ from novaclient.v1_1 import client
from heat.common import exception
from heat.db import api as db_api
from heat.common.config import HeatEngineConfigOpts
logger = logging.getLogger('heat.engine.resources')
@@ -88,11 +89,10 @@ class Resource(object):
ev['stack_id'] = self.stack.id
ev['stack_name'] = self.stack.name
ev['resource_status'] = new_state
ev['name'] = new_state
ev['resource_status_reason'] = reason
ev['resource_type'] = self.t['Type']
ev['resource_properties'] = self.t['Properties']
new_stack = db_api.stack_create(None, ev)
ev['stack_id'] = new_stack.id
db_api.event_create(None, ev)
self.state = new_state
@@ -412,21 +412,10 @@ class Instance(Resource):
self.state_set(self.CREATE_FAILED)
def delete(self):
if self.state == self.DELETE_IN_PROGRESS or self.state == self.DELETE_COMPLETE:
return
self.state_set(self.DELETE_IN_PROGRESS)
Resource.delete(self)
if self.instance_id == None:
self.state_set(self.DELETE_COMPLETE)
return
Resource.stop(self)
server = self.nova().servers.get(self.instance_id)
server.delete()
self.instance_id = None
self.state_set(self.DELETE_COMPLETE)
def insert_package_and_services(self, r, new_script):