10 KiB
Profile Types
In Senlin, each node is associated with a physical object created by
instantiating a profile <profile>
. Profiles themselves are
objects instantiated from "profile types". In other words, a profile
type provides the specification for creating profiles while a profile
can be used to create multiple homogeneous objects.
Profile type implementations are managed as plugins. Users can use
the built-in profile types directly and they can provide their own
implementation of new profile types. The plan is to have Senlin engine
support dynamical loading of plugins. Currently, this can be done by
adding new senlin.profiles
entry in the
entry_points
section in the setup.cfg
file
followed by a reinstall (i.e. pip install
) operation.
The Base Class 'Profile'
The base class Profile
provides some common logics
regarding the following operations:
- the initialization of the
spec_data
based on thespec_schema
property and thespec
input. - the initialization of a basic request context using the Senlin service credentials.
- the serialization and deserialization of profile object into/from database.
- the validation of data provided through
spec
field of the profile; - the north bound APIs that are provided as class methods, including:
create_object()
: create an object using logic from the profile type implementation, with data from the profile object as inputs;delete_object()
: delete an object using the profile type implementation;update_object()
: update an object by invoking operation provided by a profile type implementation, with data from a different profile object as inputs;get_details()
: retrieve object details into a dictionary by invoking the corresponding method provided by a profile type implementation;join_cluster()
: a hook API that will be invoked when an object is made into a member of a cluster; the purpose is to give the profile type implementation a chance to make changes to the object accordingly;leave_cluster()
: a hook API that will be invoked when an object is removed from its current cluster; the purpose is to give the profile type implementation a chance to make changes to the object accordingly;recover_object()
: recover an object with operation given by inputs from the profile object. By default,recreate
is used if no operation is provided to delete firstly then create the object.
Abstract Methods
In addition to the above logics, the base class Profile
also defines some abstract methods for a profile type implementation to
implement. When invoked, these methods by default return
NotImplemented
, a special value that indicates the method
is not implemented.
do_create(obj)
: an object creation method for a profile type implementation to override;do_delete(obj)
: an object deletion method for a profile type implementation to override;do_update(obj, new_profile)
: an object update method for a profile type implementation to override;do_check(obj)
: a method that is meant to do a health check over the provided object;do_get_details(obj)
: a method that can be overridden so that the caller can get a dict that contains properties specific to the object;do_join(obj)
: a method for implementation to override so that profile type specific changes can be made to the object when object joins a cluster.do_leave(obj)
: a method for implementation to override so that profile type specific changes can be made to the object when object leaves its cluster.do_recover(obj)
: an object recover method for a profile type implementation to override. Nova server, for example, overrides the recover operation byREBUILD
.
The VERSIONS
Property
Each profile type class has a VERSIONS
class property
that documents the changes to the profile type. This information is
returned when users request to list all profile types supported.
The VERSIONS
property is a dict with version numbers as
keys. For each specific version, the value is list of support status
changes made to the profile type. Each change record contains a
status
key whose value is one of EXPERIMENTAL
,
SUPPORTED
, DEPRECATED
or
UNSUPPORTED
, and a since
key whose value is of
format yyyy.mm
where yyyy
and mm
are the year and month of the release that bears the change to the
support status. For example, the following record indicates that the
specific profile type was introduced in April, 2016 (i.e. version 1.0
release of Senlin) as an experimental feature; later, in October, 2016
(i.e. version 2.0 release of Senlin) it has graduated into a mature
feature supported by the developer team.
= {
VERSIONS '1.0': [
{"status": "EXPERIMENTAL",
"since": "2016.04"
},
{"status": "SUPPORTED",
"since": "2016.10"
}
] }
The context
Property
In the Profile
class, there is a special property named
context
. This is the data structure containing all
necessary information needed when the profile type implementation wants
to authenticate with a cloud platform. Refer to authorization <authorization>
, Senlin makes use
of the trust mechanism provided by the OpenStack Keystone service.
The dictionary in this context
property by default
contains the credentials for the Senlin service account. Using the trust
built between the requesting user and the service account, a profile
type implementation can authenticate itself with the backend Keystone
service and then interact with the supporting service like Nova, Heat
etc.
All profile type implementations can include a context
key in their spec, the default value is an empty dictionary. A user may
customize the contents when creating a profile object by specifying a
region_name
, for example, to enable a multi-region cluster
deployment. They could even specify a different auth_url
so
that a cluster can be built across OpenStack clouds.
Providing New Profile Types
When released, Senlin provides some built-in profile types. However, developing new profile types for Senlin is not a difficult task.
Develop a New Profile Type
The first step is to create a new file containing a subclass of
Profile
. Then you will define the spec schema for the new
profile which is a python dictionary named spec_schema
,
with property names as keys. For each property, you will specify its
value to be an object of one of the schema types listed below:
String
: A string property.Boolean
: A boolean property.Integer
: An integer property.List
: A property containing a list of values.Map
: A property containing a map of key-value pairs.
For example:
= {
spec_schema 'name': schema.String('name of object'),
'capacity': schema.Integer('capacity of object', default=10),
'shared': schema.Boolean('whether object is shared', default=True)
}
If a profile property is a List
, you can further define
the type of elements in the list, which can be a String
, a
Boolean
, an Integer
or a Map
. For
example:
= {
spec_schema
...'addresses': schema.List(
'address of object on each network',
=schema.String('address on a network')
schema
),
... }
If a profile property is a Map
, you can further define
the "schema" of that map, which itself is another Python dictionary
containing property definitions. For example:
= {
spec_schema
...'dimension': schema.Map(
'dimension of object',
={
schema'length': schema.Integer('length of object'),
'width': schema.Integer('width of object')
}
)
... }
By default, a property is not required. If a property has to be
provided, you can specify required=True
in the property
type constructor. For example:
= {
spec_schema
...'name_length': schema.Integer('length of name', required=True)
... }
A property can have a default value when no value is specified. If a property has a default value, you don't need to specify it is required. For example:
= {
spec_schema
...'min_size': schema.Integer('minimum size of object', default=0)
... }
After the properties are defined, you can continue to work on
overriding the abstract methods inherited from the base
Profile
type as appropriate.
Registering a New Profile Type
For Senlin to make use of the new profile type you have just developed, you will register it to Senlin service. Currently, this is done through a manual process. In future, Senlin will provide dynamical loading support to profile type plugins.
To register a new profile type, you will add a line to the
setup.cfg
file that can be found at the root directory of
Senlin code base. For example:
[entry_points]
senlin.profiles =
os.heat.stack-1.0 = senlin.profiles.os.heat.stack:StackProfile
os.nova.server-1.0 = senlin.profiles.os.nova.server:ServerProfile
my.cool.profile-1.0 = <path to the profile module>:<profile class name>
Finally, save that file and do a reinstall of the Senlin service,
followed by a restart of the senlin-engine
process.
$ sudo pip install -e .
Now, when you do a openstack cluster profile type list
, you will see
your profile type listed along with other existing profile types.