Merge "Application Development Framework"
This commit is contained in:
commit
18112bd58c
|
@ -0,0 +1,659 @@
|
||||||
|
..
|
||||||
|
This work is licensed under a Creative Commons Attribution 3.0 Unported
|
||||||
|
License.
|
||||||
|
|
||||||
|
http://creativecommons.org/licenses/by/3.0/legalcode
|
||||||
|
|
||||||
|
=================================
|
||||||
|
Application Development Framework
|
||||||
|
=================================
|
||||||
|
|
||||||
|
https://blueprints.launchpad.net/murano/+spec/application-development-framework
|
||||||
|
|
||||||
|
Build a library of MuranoPL classes to define basic building blocks for the
|
||||||
|
applications utilizing standard patterns for scaling, load balancing, healing
|
||||||
|
etc.
|
||||||
|
|
||||||
|
|
||||||
|
Problem description
|
||||||
|
===================
|
||||||
|
|
||||||
|
Currently Murano Applications are not opinionated about the workflow they have
|
||||||
|
to follow to be scalable, highly available, (self) healable and so on. The only
|
||||||
|
interface which is declared for a standard murano application defines a single
|
||||||
|
method called “deploy” which has to implement the complete provisioning
|
||||||
|
procedure of the app. This approach is cumbersome, requires lots of coding
|
||||||
|
while most of the code is a boilerplate which could be reused by most the
|
||||||
|
applications.
|
||||||
|
|
||||||
|
Also, the “deploy” workflow is just a beginning of applications’ life in the
|
||||||
|
cloud: Murano app should define the lifecycle management of the app as well: to
|
||||||
|
handle the scaling, healing and other special behaviors. Similarly to the
|
||||||
|
deployment behaviors these kinds of workflow may have some generic steps which
|
||||||
|
should be made on most of the applications and should not require manual
|
||||||
|
copying.
|
||||||
|
|
||||||
|
It would be beneficial for the developers of Murano Applications to have a set
|
||||||
|
of base classes defining the standard building blocks for the typical
|
||||||
|
applications and their life cycle management operations.
|
||||||
|
|
||||||
|
So Murano should allow Application Developers to focus on their
|
||||||
|
application-specific tasks only (e.g. “how to install the software on the
|
||||||
|
VMs”, “how to configure it to interact with other apps” etc) without the real
|
||||||
|
need to dive into resource orchestration, server farm configuration and so on.
|
||||||
|
The application developers’ experience has to be as lightweight as possible:
|
||||||
|
ideally they should be able to focus on the software configuration tools
|
||||||
|
(scripts, puppets etc) and completely ignore the MuranoPL if they do not need
|
||||||
|
to define any custom workflow logic.
|
||||||
|
|
||||||
|
|
||||||
|
Proposed change
|
||||||
|
===============
|
||||||
|
|
||||||
|
It is proposed to implement a set of base classes for the applications and
|
||||||
|
their components.
|
||||||
|
|
||||||
|
Library structure
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Scaling primitives
|
||||||
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
To properly handle various scaling scenarios it is required to have a set of
|
||||||
|
classes which will be able to group similar resources together, produce new
|
||||||
|
copies of the same resources or release the existing ones on request.
|
||||||
|
|
||||||
|
The following hierarchy of classes is proposed to define this functionality on
|
||||||
|
the generic level as well as to implement it for the case of the Servers/VMs:
|
||||||
|
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
+-------+
|
||||||
|
| +-------+
|
||||||
|
| | +--------+ +------------------+ +-----------------+
|
||||||
|
| | | | | | | |
|
||||||
|
+-+ | Object <--+ ReplicationGroup +----> ReplicaProvider |
|
||||||
|
+-+ | | | | |
|
||||||
|
+--------+ +------+-----------+ +-+-------------+-+
|
||||||
|
^ ^ ^
|
||||||
|
| | |
|
||||||
|
| +--------------+----------+ |
|
||||||
|
| | | |
|
||||||
|
+-------+ | | TemplateReplicaProvider | |
|
||||||
|
| +-------+ | | +--+----+
|
||||||
|
| | +----------+ | +----------+--------------+ |
|
||||||
|
| | | | | | CloneReplicaProvider |
|
||||||
|
+-+ | Instance +-----+ | | |
|
||||||
|
+-+ | | | +--------+-------------+
|
||||||
|
+----------+ | | ^
|
||||||
|
| | |
|
||||||
|
| | +-----------+------+
|
||||||
|
| | | |
|
||||||
|
+-------+-----------+-+ | InstanceProvider +--+
|
||||||
|
| +---------> | |
|
||||||
|
| InstanceGroup | +-----+------------+ +---+
|
||||||
|
| | | | |
|
||||||
|
+---------------------+ +---+-----------+ |
|
||||||
|
| |
|
||||||
|
+---------------+
|
||||||
|
(other replica providers)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**ReplicationGroup**
|
||||||
|
|
||||||
|
A base class which does the object replication. It holds the collection of
|
||||||
|
objects in one of its InputOutput properties (so the objects may be both
|
||||||
|
generated in runtime and passed as the user input) and contains a reference
|
||||||
|
to a ``ReplicaProvider`` object which is used to dynamically generate the
|
||||||
|
objects in runtime.
|
||||||
|
|
||||||
|
Input properties of this class include the ``minReplicas`` and
|
||||||
|
``maxReplicas`` allowing to limit the number of objects it holds in its
|
||||||
|
collection.
|
||||||
|
|
||||||
|
An input-output property ``requiredNumberOfReplicas`` allows to
|
||||||
|
declaratively change the set of objects in the collection by setting its
|
||||||
|
size.
|
||||||
|
|
||||||
|
The ``deploy`` method of this class will be used to apply the replica
|
||||||
|
settings: it will drop the objects from the collection if their number
|
||||||
|
exceeds the specified by the ``requiredNumberOfReplicas`` or generate some
|
||||||
|
new if there are not enough of them.
|
||||||
|
|
||||||
|
|
||||||
|
**ReplicaProvider**
|
||||||
|
|
||||||
|
A class to generate the objects for a ``ReplicationGroup``. The base one
|
||||||
|
is abstract, its inheritors should implement the abstract
|
||||||
|
``createInstance`` method to create the actual object. The method may
|
||||||
|
accept some index parameter to properly parametrize the newly created copy.
|
||||||
|
|
||||||
|
The concrete implementations of this class should define all the input
|
||||||
|
properties needed to create new instances of object. Thus the provider
|
||||||
|
actually acts as a template of the object it generates.
|
||||||
|
|
||||||
|
|
||||||
|
**TemplateReplicaProvider**
|
||||||
|
|
||||||
|
An implementation of ``ReplicaProvider`` capable to create replicas based
|
||||||
|
on a user-provided template, being a yaml-based definition of some
|
||||||
|
arbitrary object.
|
||||||
|
|
||||||
|
|
||||||
|
**CloneReplicaProvider**
|
||||||
|
|
||||||
|
An implementation of ``ReplicaProvider`` similar to the
|
||||||
|
``TemplateReplicaProvider``, capable to create replicas by cloning some
|
||||||
|
user-provided object. The difference between this class and the
|
||||||
|
``TemplateReplicaProvider`` is that for ``CloneReplicaProvider`` the target
|
||||||
|
object should be a real object (thus having all the properties valid,
|
||||||
|
matching all the contracts etc), while the template of
|
||||||
|
``TemplateReplicaProvider`` is just a dict which may be missing some of the
|
||||||
|
required properties etc.
|
||||||
|
|
||||||
|
|
||||||
|
**InstanceGroup**
|
||||||
|
|
||||||
|
A subclass of ``ReplicationGroup`` class to replicate the ``Instance``
|
||||||
|
objects it holds.
|
||||||
|
|
||||||
|
The ``deploy`` method of this group not only generates new instances of
|
||||||
|
servers but also deploys them if needed.
|
||||||
|
|
||||||
|
**InstanceProvider**
|
||||||
|
|
||||||
|
A subclass of ``CloneReplicaProvider`` which is used to produce the objects
|
||||||
|
of ``Instance`` class by cloning them with subsequent parameterization of
|
||||||
|
the hostnames. May be passed as ``replicaProvider`` property to objects of
|
||||||
|
``InstanceGroup`` class.
|
||||||
|
|
||||||
|
**other replica providers**
|
||||||
|
|
||||||
|
Other subclasses of ``ReplicaProvider`` may be created to produce different
|
||||||
|
objects of ``Instance`` class and its subclasses depending on particular
|
||||||
|
application needs.
|
||||||
|
|
||||||
|
|
||||||
|
Software Components
|
||||||
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The main classes to handle the lifecycle of the application are the
|
||||||
|
``BaseSoftwareComponent`` and its subclasses:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
+-----------------------+
|
||||||
|
| |
|
||||||
|
| BaseSoftwareComponent |
|
||||||
|
| |
|
||||||
|
+---+---------------+---+
|
||||||
|
^ ^
|
||||||
|
| |
|
||||||
|
+-----------+-+ +-+------------+
|
||||||
|
| | | |
|
||||||
|
| Installable | | Configurable |
|
||||||
|
| | | |
|
||||||
|
+-----------+-+ +-+------------+
|
||||||
|
^ ^
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
+-+---------------+-+
|
||||||
|
| |
|
||||||
|
| SoftwareComponent |
|
||||||
|
| |
|
||||||
|
+-------------------+
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
The hierarchy of the ``SoftwareComponent`` classes should be used to define the
|
||||||
|
workflows of different application lifecycles. The general idea is to have the
|
||||||
|
generic logic in the methods of the base classes and let the derived classes
|
||||||
|
implement the handlers for the custom logic. The model is event-driven: the
|
||||||
|
workflow consists of the multiple steps, and most of the steps invoke
|
||||||
|
appropriate `on%StepName%` methods intended to provide application-specific
|
||||||
|
logic.
|
||||||
|
|
||||||
|
It is proposed to split 'internal' step logic and their 'public' handlers
|
||||||
|
into separate methods. Technically this is not necessary since the subclass may
|
||||||
|
always call `super()` to invoke the base logic, but the developers tend to
|
||||||
|
forget to invoke these super-implementations – so having the logic split into
|
||||||
|
two parts should improve the developers' experience and simplify the code of
|
||||||
|
derived classes.
|
||||||
|
|
||||||
|
The standard workflows (such as Installation and Configuration) will be defined
|
||||||
|
by two subclasses of ``BaseSoftwareComponent`` - ``Installable`` and
|
||||||
|
``Configurable``. The main implementation - ``SoftwareComponent`` will inherit
|
||||||
|
both these classes and will define its deployment workflow as a sequence of
|
||||||
|
Installation and Configuration flows. Other future implementations may add new
|
||||||
|
workflow interfaces and mix them in to change the deployment workflow or add
|
||||||
|
new actions.
|
||||||
|
|
||||||
|
|
||||||
|
Installation workflow consists of the following methods:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
+----------------------------------------------------------------------------------------------------------------------+
|
||||||
|
| INSTALL |
|
||||||
|
| |
|
||||||
|
| +------------------------------+ +---------------+ |
|
||||||
|
| +------------------------------+ | +---------------+ | |
|
||||||
|
| +------------------------------+ | | +---------------+ +---------------+ | | +----------------------+ |
|
||||||
|
| | | | | | | | | | | | | |
|
||||||
|
| | checkServerNeedsInstallation | +-+ +----> beforeInstall +----> installServer | +-+ +----> completeInstallation | |
|
||||||
|
| | +-+ | | | +-+ | | |
|
||||||
|
| +------------------------------+ +------+--------+ +------+--------+ +-----------+----------+ |
|
||||||
|
| | | | |
|
||||||
|
+----------------------------------------------------------------------------------------------------------------------+
|
||||||
|
| | |
|
||||||
|
| | |
|
||||||
|
| | |
|
||||||
|
v v v
|
||||||
|
onBeforeInstall onInstallServer onCompleteInstallation
|
||||||
|
|
||||||
|
|
||||||
|
**install**
|
||||||
|
* **Arguments:** ``ServerGroup``
|
||||||
|
* **Description:**
|
||||||
|
Entry point of the installation workflow.
|
||||||
|
|
||||||
|
Iterates through all the servers of the passed ServerGroup and calls the
|
||||||
|
``checkServerNeedsInstallation`` method for each of them. If at least one
|
||||||
|
of the calls has returned `True` calls a ``beforeInstall`` method. Then,
|
||||||
|
for each server which returned `True` as the result of the
|
||||||
|
``checkServerNeedsInstallation`` calls the ``installServer`` method to do
|
||||||
|
the actual software installation.
|
||||||
|
After the installation has been completed on all the servers and if at
|
||||||
|
least one of the previous calls of ``checkServerNeedsInstallation``
|
||||||
|
returned `True` the method runs the ``completeInstallation`` method.
|
||||||
|
|
||||||
|
If all the calls to ``checkServerNeedsInstallation`` returned `False`
|
||||||
|
this method concludes without calling any others.
|
||||||
|
|
||||||
|
**checkServerNeedsInstallation**
|
||||||
|
* **Arguments:** ``Server``
|
||||||
|
* **Description:** checks if the given server requires a (re)deployment of
|
||||||
|
the software component. By default checks for the presence of attribute
|
||||||
|
`installed_at_%serverId%` being set by the ``installServer`` method.
|
||||||
|
|
||||||
|
May be overriden by subclasses to provide some better logic (e.g. the
|
||||||
|
app developer may provide code to check if the given software is
|
||||||
|
pre-installed on the image which was provisioned on the VM)
|
||||||
|
|
||||||
|
**beforeInstall**
|
||||||
|
* **Arguments:** ``ServerGroup``
|
||||||
|
* **Description:**
|
||||||
|
Reports the beginning of installation process, resets an error counter of
|
||||||
|
the current deployment to zero and calls the public event handler
|
||||||
|
``onBeforeInstall``.
|
||||||
|
|
||||||
|
**onBeforeInstall**
|
||||||
|
* **Arguments:** ``ServerGroup``
|
||||||
|
* **Description:** Public handler of the `beforeInstall` event. Empty in
|
||||||
|
the base class, may be overriden in subclasses if some custom pre-install
|
||||||
|
logic needs to be executed.
|
||||||
|
|
||||||
|
**installServer**
|
||||||
|
* **Arguments:** ``Server``
|
||||||
|
* **Description:** does the actual software deployment on a given server by
|
||||||
|
calling an ``onInstallServer`` public event handler. If the installation
|
||||||
|
completes successfully sets the `installed_at_%serverId%` attribute of
|
||||||
|
the component's attribute storage to indicate that the software component
|
||||||
|
was installed on that particular machine. If an exception was encountered
|
||||||
|
during the invocation of ``onInstallServer`` the method will handle that
|
||||||
|
exception, report a warning and increment the error counter for the
|
||||||
|
particular deployment.
|
||||||
|
|
||||||
|
**onInstallServer**
|
||||||
|
* **Arguments:** ``Server``
|
||||||
|
* **Description:** an event-handler method which is called by the
|
||||||
|
``installServer`` method when the actual software deployment is needed.
|
||||||
|
Is empty in the base class. The implementations should override it with
|
||||||
|
custom logic to deploy the actual software bits.
|
||||||
|
|
||||||
|
**completeInstallation**
|
||||||
|
* **Arguments:** ``ServerGroup``
|
||||||
|
* **Description:** is executed after all the ``installServer`` methods were
|
||||||
|
called. Checks for the number of errors reported during the installation:
|
||||||
|
if it is greater than some pre-configurable threshold an exception is
|
||||||
|
risen to interrupt the deployment workflow. Otherwise the method calls an
|
||||||
|
``onCompleteInstallation`` event handler and then reports a successful
|
||||||
|
completion of the installation workflow.
|
||||||
|
|
||||||
|
**onCompleteInstallation**
|
||||||
|
* **Arguments:** ``ServerGroup``
|
||||||
|
* **Description:** an event-handler method which is called by the
|
||||||
|
``completeInstallation`` method when the component installation is about
|
||||||
|
to be completed.
|
||||||
|
|
||||||
|
Default implementation is empty. Inheritors may implement this method to
|
||||||
|
add some final handling, reporting etc.
|
||||||
|
|
||||||
|
|
||||||
|
Configuration workflow consists of the following methods:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
+-------------------------------------------------------------------------------------------------------------------------+
|
||||||
|
| CONFIGURATION |
|
||||||
|
| +-------------------------------------+ |
|
||||||
|
| | | |
|
||||||
|
| | +------------------+ +-----------------+ |
|
||||||
|
| | +------------------+ | +-----------------+ | |
|
||||||
|
| +------------v--+ +--------------+ +------------------+ | | +-----------------+ | | +-----------------------+ |
|
||||||
|
| | | | | | | | | | | | | | | |
|
||||||
|
| | checkNeedsRe\ +---> preConfigure +---> checkServerNeeds\| +-+---> configureServer | +-+---> completeConfiguration | |
|
||||||
|
| | configuration | | | | Reconfiguration +-+ | +-+ | | |
|
||||||
|
| +------------+--+ +------+-------+ +------------------+ +--------+--------+ +-----------+-----------+ |
|
||||||
|
| | | | | |
|
||||||
|
| | | | | |
|
||||||
|
| +----v---+ | | | |
|
||||||
|
| | | | | | |
|
||||||
|
| | getKey | | | | |
|
||||||
|
| | | | | | |
|
||||||
|
| +--------+ | | | |
|
||||||
|
| | | | |
|
||||||
|
+-------------------------------------------------------------------------------------------------------------------------+
|
||||||
|
| | |
|
||||||
|
| | |
|
||||||
|
v v v
|
||||||
|
onPreConfigure onConfigureServer onCompleteConfiguration
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**configure**
|
||||||
|
* **Arguments:** ``ServerGroup``
|
||||||
|
* **Description:**
|
||||||
|
Entry point of the configuration workflow.
|
||||||
|
|
||||||
|
Calls a ``checkNeedsReconfiguration`` method. If the call does not return
|
||||||
|
`True` workflow exits without doing anything. Otherwise calls
|
||||||
|
``preConfigure`` method and then iterates through all the servers of
|
||||||
|
the passed ServerGroup. For each server it calls
|
||||||
|
``checkServerNeedsReconfiguration`` method. If that call returns `True`
|
||||||
|
then a ``configureServer`` is called for that server. At the end calls a
|
||||||
|
``completeConfiguration`` method if at least one call of
|
||||||
|
``configureServer`` was made.
|
||||||
|
|
||||||
|
**checkNeedsReconfiguration**
|
||||||
|
* **Arguments:** ``ServerGroup``
|
||||||
|
* **Description:** has to return `True` if the configuration (i.e. the
|
||||||
|
values of input properties) of the component has been changed since it
|
||||||
|
was last deployed on the given Server Group. Default implementation calls
|
||||||
|
a ``getKey`` method and compares the returned result with a value of
|
||||||
|
`configuration_of_%serverGroupId%` attribute. If the results do not match
|
||||||
|
returns `True` otherwise `False`.
|
||||||
|
|
||||||
|
**getKey**
|
||||||
|
* **Arguments:** None
|
||||||
|
* **Description:** should return some values describing the configuration
|
||||||
|
state of the component. This state is used to track the changes of the
|
||||||
|
configuration by the ``checkNeedsReconfiguration`` method.
|
||||||
|
|
||||||
|
Default implementation returns a synthetic value which gets updated on
|
||||||
|
every environment redeployment. Thus the subsequent calls of the
|
||||||
|
``configure`` method on the same server group during the same deployment
|
||||||
|
will not cause the reconfiguration, while the calls on the next
|
||||||
|
deployment will reapply the configuration again.
|
||||||
|
|
||||||
|
The inheritors may redefine this to include the actual values of the
|
||||||
|
configuration properties, so the configuration is reapplied only if the
|
||||||
|
appropriate input properties were changed.
|
||||||
|
|
||||||
|
**preConfigure**
|
||||||
|
* **Arguments:** ``ServerGroup``
|
||||||
|
* **Description:**
|
||||||
|
Reports the beginning of configuration process, resets an error counter
|
||||||
|
of the current configuration to zero and calls the public event handler
|
||||||
|
``onPreConfigure``. This method is called once per the server group and
|
||||||
|
only if the changes in configuration are detected.
|
||||||
|
|
||||||
|
**onPreConfigure**
|
||||||
|
* **Arguments:** ``ServerGroup``
|
||||||
|
* **Description:**
|
||||||
|
a public event-handler which is called by the ``preConfigure`` method
|
||||||
|
when the (re)configuration of the component is required.
|
||||||
|
|
||||||
|
Default implementation is empty. Inheritors my implement this method to
|
||||||
|
set various kinds of cluster-wide states or output properties which may
|
||||||
|
be of use at later stages of the workflow.
|
||||||
|
|
||||||
|
**checkServerNeedsReconfiguration**
|
||||||
|
* **Arguments:** ``Server``
|
||||||
|
* **Description:** is called to check if the particular server of the
|
||||||
|
server group has to be reconfigured thus providing more precise control
|
||||||
|
compared to cluster-wide ``checkNeedsReconfiguration``.
|
||||||
|
|
||||||
|
Default implementation calls a ``getKey`` method and compares the
|
||||||
|
returned result with a value of `configuration_of_%serverId%` attribute.
|
||||||
|
If the results do not match returns `True` otherwise `False`.
|
||||||
|
|
||||||
|
This method gets called only if the ``checkNeedsReconfiguration`` method
|
||||||
|
returned `True` for the whole server group.
|
||||||
|
|
||||||
|
**configureServer**
|
||||||
|
* **Arguments:** ``Server``
|
||||||
|
* **Description:** does the actual software configuration on a given server
|
||||||
|
by calling an ``onConfigureServer`` public event handler.
|
||||||
|
If the configuration completes successfully calls the ``getKey`` method
|
||||||
|
and sets the `configuration_of_%serverId%` attribute to resulting value
|
||||||
|
thus saving the configuration applied to a given server.
|
||||||
|
|
||||||
|
If an exception was encountered during the invocation of
|
||||||
|
``onConfigureServer`` the method will handle that exception, report a
|
||||||
|
warning and increment the error counter for the particular deployment.
|
||||||
|
|
||||||
|
**onConfigureServer**
|
||||||
|
* **Arguments:** ``Server``
|
||||||
|
* **Description:** an event-handler method which is called by the
|
||||||
|
``configureServer`` method when the actual software configuration is
|
||||||
|
needed. Is empty in the base class. The implementations should override
|
||||||
|
it with custom logic to apply the actual software configuration on a
|
||||||
|
given server.
|
||||||
|
|
||||||
|
**completeConfiguration**
|
||||||
|
* **Arguments:** ``ServerGroup``
|
||||||
|
* **Description:** is executed after all the ``configureServer`` methods
|
||||||
|
were called. Checks for the number of errors reported during the
|
||||||
|
configuration: if it is greater than some pre-configurable threshold an
|
||||||
|
exception is risen to interrupt the deployment workflow. Otherwise the
|
||||||
|
method calls an ``onCompleteConfiguration`` event handler and then
|
||||||
|
reports a successful completion of the configuration workflow.
|
||||||
|
|
||||||
|
**onCompleteConfiguration**
|
||||||
|
* **Arguments:** ``ServerGroup``
|
||||||
|
* **Description:** an event-handler method which is called by the
|
||||||
|
``completeConfiguration`` method when the component configuration was
|
||||||
|
finished at all the servers.
|
||||||
|
|
||||||
|
Default implementation is empty. Inheritors may implement this method to
|
||||||
|
add some final handling, reporting etc.
|
||||||
|
|
||||||
|
|
||||||
|
Uninstallation workflow consists of the following methods:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
+-----------------------------------------------------------------------------------+
|
||||||
|
| UNINSTALL |
|
||||||
|
| |
|
||||||
|
| +----------------+ |
|
||||||
|
| +-----------------+ | |
|
||||||
|
| +-----------------+ +-----------------+ | | +------------------------+ |
|
||||||
|
| | | | | | | | | |
|
||||||
|
| | beforeUninstall +------> uninstallServer | +-+------> completeUninstallation | |
|
||||||
|
| | | | +-+ | | |
|
||||||
|
| +-------+---------+ +--------+--------+ +-----------+------------+ |
|
||||||
|
| | | | |
|
||||||
|
| | | | |
|
||||||
|
+-----------------------------------------------------------------------------------+
|
||||||
|
| | |
|
||||||
|
v v v
|
||||||
|
onBeforeUninstall onUninstallServer onCompleteUninstallation
|
||||||
|
|
||||||
|
|
||||||
|
**uninstall**
|
||||||
|
* **Arguments:** ``ServerGroup``
|
||||||
|
* **Description:**
|
||||||
|
Entry point of the uninstallation workflow.
|
||||||
|
|
||||||
|
Iterates through all the servers of the passed ServerGroup, for each of
|
||||||
|
them checks the presence of the `installed_at_%serverId%` attribute.
|
||||||
|
If at least one attribute is present calls a ``beforeUninstall`` method
|
||||||
|
once, and then calls an ``uninstallServer`` method for each server which
|
||||||
|
has the attribute. If at least one method was called, calls an
|
||||||
|
``afterUninstall`` method at the end.
|
||||||
|
|
||||||
|
**beforeUninstall**
|
||||||
|
* **Arguments:** ``ServerGroup``
|
||||||
|
* **Description:** reports the beginning of uninstalling process and then
|
||||||
|
calls an ``onBeforeUninstall`` public event handler.
|
||||||
|
|
||||||
|
**onBeforeUninstall**
|
||||||
|
* **Arguments:** ``ServerGroup``
|
||||||
|
* **Description:** Public handler of the `beforeUninstall` event. Empty in
|
||||||
|
the base class, may be overriden in subclasses if some custom pre
|
||||||
|
uninstall logic needs to be executed.
|
||||||
|
|
||||||
|
**uninstallServer**
|
||||||
|
* **Arguments:** ``Server``
|
||||||
|
* **Description:** does the actual software removal on a given server by
|
||||||
|
calling an ``onUninstallServer`` public event handler. If the removal
|
||||||
|
completes successfully clear the `installed_at_%serverId%` attribute of
|
||||||
|
the component's attribute storage to indicate that the software component
|
||||||
|
is no longer installed on that particular machine.
|
||||||
|
If an exception was encountered during the invocation of
|
||||||
|
``onUninstallServer`` the method will handle that exception, report a
|
||||||
|
warning and increment the error counter for the particular deployment.
|
||||||
|
|
||||||
|
**onUninstallServer**
|
||||||
|
* **Arguments:** ``Server``
|
||||||
|
* **Description:** an event-handler method which is called by the
|
||||||
|
``uninstallServer`` method when the actual software removal is needed.
|
||||||
|
Is empty in the base class. The implementations should override it with
|
||||||
|
custom logic to uninstall the actual software bits.
|
||||||
|
|
||||||
|
**completeUninstallation**
|
||||||
|
* **Arguments:** ``ServerGroup``
|
||||||
|
* **Description:** is executed after all the ``uninstallServer`` methods
|
||||||
|
were called. Checks for the number of errors reported during the
|
||||||
|
uninstalling: if it is greater than some pre-configurable threshold an
|
||||||
|
exception is risen to interrupt the uninstalling workflow. Otherwise the
|
||||||
|
method calls an ``onCompleteUninstallation`` event handler and then
|
||||||
|
reports a successful completion of the uninstalling workflow.
|
||||||
|
|
||||||
|
**onCompleteUninstallation**
|
||||||
|
* **Arguments:** ``ServerGroup``
|
||||||
|
* **Description:** an event-handler method which is called by the
|
||||||
|
``completeUninstallation`` method when the component removal is done on
|
||||||
|
all the servers.
|
||||||
|
|
||||||
|
Default implementation is empty. Inheritors may implement this method to
|
||||||
|
add some final handling, reporting etc.
|
||||||
|
|
||||||
|
|
||||||
|
Alternatives
|
||||||
|
------------
|
||||||
|
|
||||||
|
The only alternative is to let application developers to write their own code
|
||||||
|
for these common tasks. We don't completely drop this alternative, since the
|
||||||
|
developers are not forced to use the framework and may still continue having
|
||||||
|
the applications which do not inherit its base classes.
|
||||||
|
|
||||||
|
Data model impact
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
None
|
||||||
|
|
||||||
|
REST API impact
|
||||||
|
---------------
|
||||||
|
|
||||||
|
None
|
||||||
|
|
||||||
|
|
||||||
|
Versioning impact
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
The first implementation of this spec will utilize the existing version of the
|
||||||
|
core library. Subsequent ones - redefining the hierarchy of base resource
|
||||||
|
classes - will need to increment the major version of the core library.
|
||||||
|
|
||||||
|
Other end user impact
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
End users should not notice the difference between apps written using the
|
||||||
|
proposed framework and regular ones.
|
||||||
|
|
||||||
|
|
||||||
|
Deployer impact
|
||||||
|
---------------
|
||||||
|
|
||||||
|
The Framework's library package should be deployed in the target catalog for
|
||||||
|
other applications to use it.
|
||||||
|
|
||||||
|
|
||||||
|
Developer impact
|
||||||
|
----------------
|
||||||
|
|
||||||
|
This is all about simplifying the life of application developer. Developers
|
||||||
|
will have to learn the classes and patterns to utilize the benefits of the
|
||||||
|
framework.
|
||||||
|
|
||||||
|
Murano-dashboard / Horizon impact
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
None
|
||||||
|
|
||||||
|
Implementation
|
||||||
|
==============
|
||||||
|
|
||||||
|
Assignee(s)
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Primary assignee:
|
||||||
|
ativelkov
|
||||||
|
|
||||||
|
Other contributors:
|
||||||
|
tbd
|
||||||
|
|
||||||
|
Work Items
|
||||||
|
----------
|
||||||
|
|
||||||
|
* Implement the base ``Server`` class and a stub for its core-library-compatible
|
||||||
|
inheritor.
|
||||||
|
|
||||||
|
* Implement scalable primitives (ReplicationGroup, ReplicaProvider and their
|
||||||
|
inheritors)
|
||||||
|
|
||||||
|
* Implement a Event/Notification layer in MuranoPL
|
||||||
|
|
||||||
|
* Implement ``SoftwareComponent`` class with its standard
|
||||||
|
Install/Configure/Uninstall workflows.
|
||||||
|
|
||||||
|
* Implement base application classes binding ``SoftwareComponent`` objects to
|
||||||
|
``ReplicationGroup`` objects producing Servers.
|
||||||
|
|
||||||
|
Dependencies
|
||||||
|
============
|
||||||
|
|
||||||
|
None
|
||||||
|
|
||||||
|
Testing
|
||||||
|
=======
|
||||||
|
|
||||||
|
All the new MuranoPL classes should be covered by test-runner based tests.
|
||||||
|
|
||||||
|
Documentation Impact
|
||||||
|
====================
|
||||||
|
|
||||||
|
The framework should be well documented so the package developers have a
|
||||||
|
reliable and up-to-date source of information.
|
||||||
|
|
||||||
|
References
|
||||||
|
==========
|
||||||
|
|
||||||
|
None
|
Loading…
Reference in New Issue