Custom Search

Tuesday, July 8, 2014

OpenStack heat-engine flow of stack-create action

1)
/usr/lib/python2.7/dist-packages/heat/openstack/common/rpc/amqp.py

class ProxyCallback(_ThreadPoolWithWait):
    """Calls methods on a proxy object based on method and args."""
   
    def __call__(self, message_data):
        self.pool.spawn_n(self._process_data, ctxt, version, method, namespace, args)   
   
    def _process_data(self, ctxt, version, method, namespace, args):
        """Process a message in a new thread.

        If the proxy object we have has a dispatch method
        (see rpc.dispatcher.RpcDispatcher), pass it the version,
        method, and args and let it dispatch as appropriate.  If not, use
        the old behavior of magically calling the specified method on the
        proxy we have here.
        """
        rval = self.proxy.dispatch(ctxt, version, method, namespace, **args) <===
        ctxt.reply(rval, None, connection_pool=self.connection_pool)

2)
/usr/lib/python2.7/dist-packages/heat/openstack/common/rpc/dispatcher.py

    def dispatch(self, ctxt, version, method, namespace, **kwargs):
        """Dispatch a message based on a requested version.

        :param ctxt: The request context
        :param method: The method requested to be called by the incoming
                       message.
        :param namespace: The namespace for the requested method.  If None,
                          the dispatcher will look for a method on a callback
                          object with no namespace set.
        :param kwargs: A dict of keyword arguments to be passed to the method.
        """
       
        import pdb
        pdb.set_trace()

       
        kwargs = self._deserialize_args(ctxt, kwargs)
        result = getattr(proxyobj, method)(ctxt, **kwargs)
        return self.serializer.serialize_entity(ctxt, result)


IMP (Debug)
===========

a)
Stop "heat-engine"

#sudo service heat-engine stop
or
#ps -aux | grep heat
#sudo kill -9 pid pid


b)
Run "heat-engine" manually

#sudo /usr/bin/heat-engine --config-file /etc/heat/heat.conf

c)
Run the command "#heat create-stack"


d)
(Pdb) method
u'create_stack' <=====

(Pdb) namespace

(Pdb) kwargs
blabal

(Pdb) ctxt


(Pdb) ctxt.request_id
u'req-ffe57677-8b8a-4ec3-9c21-9786c1ee8f24'

(Pdb) getattr(proxyobj, method)
>

3)
/usr/lib/python2.7/dist-packages/heat/engine/service.py

def request_context(func):
    @functools.wraps(func)
    def wrapped(self, ctx, *args, **kwargs):
        if ctx is not None and not isinstance(ctx, context.RequestContext):
            ctx = context.RequestContext.from_dict(ctx.to_dict())
        try:
            return func(self, ctx, *args, **kwargs)
        except exception.HeatException:
            raise rpc_common.ClientException()
    return wrapped

    @request_context    def create_stack(self, cnxt, stack_name, template, params, files, args):
        """
        The create_stack method creates a new stack using the template
        provided.
        Note that at this stage the template has already been fetched from the
        heat-api process if using a template-url.

        :param cnxt: RPC context.
        :param stack_name: Name of the stack you want to create.
        :param template: Template of stack you want to create.
        :param params: Stack Input Params
        :param files: Files referenced from the template
        :param args: Request parameters/args passed from API
        """
        def _stack_create(stack):
            #Create a stack, and create the periodic task if successful
            stack.create() <===       
       
        stack = parser.Stack(cnxt, stack_name, tmpl,
                             env, **common_params)

        self._validate_deferred_auth_context(cnxt, stack)

        stack.validate() <===

        stack.store() <===

        self.thread_group_mgr.start_with_lock(cnxt, stack, self.engine_id,
                                              _stack_create, stack)



4)
/usr/lib/python2.7/dist-packages/heat/engine/parser.py

class Stack(collections.Mapping):

    ACTIONS = (CREATE, DELETE, UPDATE, ROLLBACK, SUSPEND, RESUME, ADOPT
               ) = ('CREATE', 'DELETE', 'UPDATE', 'ROLLBACK', 'SUSPEND',
                    'RESUME', 'ADOPT')

    STATUSES = (IN_PROGRESS, FAILED, COMPLETE
                ) = ('IN_PROGRESS', 'FAILED', 'COMPLETE')


    def total_resources(self):
        '''
        Return the total number of resources in a stack, including nested
        stacks below.
        '''

    @classmethod
    def load(
cls, context, stack_id=None, stack=None, resolve_data=True,
             parent_resource=None, show_deleted=True):
        '''Retrieve a Stack from the database.'''

    def store(self, backup=False):
        '''
        Store the stack in the database and return its ID
        If self.id is set, we update the existing stack
        '''
        s = {
            'name': self.name,
            'raw_template_id': self.t.store(self.context),
            'parameters': self.env.user_env_as_dict(),
            'owner_id': self.owner_id,
            'username': self.context.username,
            'tenant': self.tenant_id,
            'action': self.action,
        }
       
        new_creds = db_api.user_creds_create(self.context) <===
        new_s = db_api.stack_create(self.context, s) <===


    def validate(self):
        '''
        Validates the template.
        '''

    def state_set(self, action, status, reason):
        '''Update the stack state in the database.'''
        stack = db_api.stack_get(self.context, self.id)
        stack.update_and_save({'action': action,
                                   'status': status,
                                   'status_reason': reason})

    def create(self):
        '''
        Create the stack and all of the resources.
        '''

    @scheduler.wrappertask
    def stack_task(self, action, reverse=False, post_func=None):
        '''
        A task to perform an action on the stack and all of the resources
        in forward or reverse dependency order as specfifed by reverse
        '''

    def delete(self, action=DELETE, backup=False):
        '''
        Delete all of the resources, and then the stack itself.
        The action parameter is used to differentiate between a user
        initiated delete and an automatic stack rollback after a failed
        create, which amount to the same thing, but the states are recorded
        differently.
        '''

4)
DB API


4a)
Heat db api

/usr/lib/python2.7/dist-packages/heat/db/api.py

from heat.openstack.common.db import api as db_api

_BACKEND_MAPPING = {'sqlalchemy': 'heat.db.sqlalchemy.api'} <===
IMPL = db_api.DBAPI(backend_mapping=_BACKEND_MAPPING) <===


def user_creds_create(context):
    return IMPL.user_creds_create(context)

def stack_create(context, values):
    return IMPL.stack_create(context, values)

4b)
common db api

/usr/lib/python2.7/dist-packages/heat/openstack/common/db/api.py

from oslo.config import cfg
from heat.openstack.common import importutils

db_opts = [
    cfg.StrOpt('backend',
               default='sqlalchemy',
               deprecated_name='db_backend',
               deprecated_group='DEFAULT',
               help='The backend to use for db'),
]

CONF = cfg.CONF
CONF.register_opts(db_opts, 'database')

class DBAPI(object):
    def __init__(self, backend_mapping=None):
        backend_name = CONF.database.backend
        backend_path = backend_mapping.get(backend_name, backend_name) <===
        backend_mod = importutils.import_module(backend_path) <===
        self.__backend = backend_mod.get_backend() <===


4c)
sqlalchemy db api

/usr/lib/python2.7/dist-packages/heat/db/sqlalchemy/api.py

import sqlalchemy
from sqlalchemy.orm.session import Session
from heat.db.sqlalchemy import models
from heat.openstack.common.db.sqlalchemy import session as db_session

def stack_create(context, values):
    stack_ref = models.Stack() <===
    stack_ref.update(values) <===
    stack_ref.save(_session(context)) <===

    return stack_ref

4d)
/usr/lib/python2.7/dist-packages/heat/db/sqlalchemy/models.py

class Stack(BASE, HeatBase, SoftDelete):
    """Represents a stack created by the heat engine."""

    __tablename__ = 'stack'

    id = sqlalchemy.Column(sqlalchemy.String(36), primary_key=True,
                           default=lambda: str(uuid.uuid4()))
    name = sqlalchemy.Column(sqlalchemy.String(255))
    raw_template_id = sqlalchemy.Column(
        sqlalchemy.Integer,
        sqlalchemy.ForeignKey('raw_template.id'),
        nullable=False)
    raw_template = relationship(RawTemplate, backref=backref('stack'))
    username = sqlalchemy.Column(sqlalchemy.String(256))
    tenant = sqlalchemy.Column(sqlalchemy.String(256))
    action = sqlalchemy.Column('action', sqlalchemy.String(255))
    status = sqlalchemy.Column('status', sqlalchemy.String(255))
    status_reason = sqlalchemy.Column('status_reason', sqlalchemy.String(255))
    parameters = sqlalchemy.Column('parameters', Json)
    user_creds_id = sqlalchemy.Column(
        sqlalchemy.Integer,
        sqlalchemy.ForeignKey('user_creds.id'),
        nullable=False)
    owner_id = sqlalchemy.Column(sqlalchemy.String(36), nullable=True)
    timeout = sqlalchemy.Column(sqlalchemy.Integer)
    disable_rollback = sqlalchemy.Column(sqlalchemy.Boolean, nullable=False)
    stack_user_project_id = sqlalchemy.Column(sqlalchemy.String(64),
                                              nullable=True)
    updated_at = sqlalchemy.Column(sqlalchemy.DateTime)

5)

Next : OpenStack heat-api flow of stack-create action
http://fosshelp.blogspot.com/2014/07/openstack-heat-api-flow-of-stack-create.html




No comments:

Post a Comment