First commit of the proposed hacluster interface.
This commit includes a rough implementation of the hacluster interface which allows a charm to interact with the hacluster subordintate charm.
This commit is contained in:
commit
a73846f575
|
@ -0,0 +1,2 @@
|
|||
.tox
|
||||
.testrepository
|
|
@ -0,0 +1,90 @@
|
|||
# Overview
|
||||
|
||||
This interface handles the communication with the hacluster subordinate
|
||||
charm using the `ha` interface protocol.
|
||||
|
||||
# Usage
|
||||
|
||||
## Requires
|
||||
|
||||
The interface layer will set the following reactive states, as appropriate:
|
||||
|
||||
* `{relation_name}.connected` The relation is established and ready for
|
||||
the local charm to configure the hacluster subordinate charm. The
|
||||
configuration of the resources to managed for the hacluster charm
|
||||
can be managed via one of the following methods:
|
||||
|
||||
* `manage_resources` method
|
||||
* `bind_on` method
|
||||
|
||||
Configuration of the managed resources within the hacluster can be
|
||||
managed by passing `common.CRM` object definitions to the
|
||||
`manage_resources` method.
|
||||
|
||||
* `{relation_name}.available` The hacluster is up and ready.
|
||||
|
||||
For example:
|
||||
```python
|
||||
from charms.reactive import when, when_not
|
||||
from charms.reactive import set_state, remove_state
|
||||
|
||||
from relations.hacluster.common import CRM
|
||||
|
||||
|
||||
@when('ha.connected')
|
||||
def cluster_connected(hacluster):
|
||||
|
||||
resources = CRM()
|
||||
resources.primitive('res_vip', 'ocf:IPAddr2',
|
||||
params='ip=10.0.3.100 nic=eth0',
|
||||
op='monitor interval="10s"')
|
||||
resources.clone('cl_res_vip', 'res_vip')
|
||||
|
||||
hacluster.bind_on(iface='eth0', mcastport=4430)
|
||||
hacluster.manage_resources(resources)
|
||||
```
|
||||
|
||||
Additionally, for more code clarity a custom object implements the interface
|
||||
defined in common.ResourceDescriptor can be used to simplify the code for
|
||||
reuse.
|
||||
|
||||
For example:
|
||||
```python
|
||||
import ipaddress
|
||||
|
||||
from relation.hacluster.common import CRM
|
||||
from relation.haclsuter.common import ResourceDescriptor
|
||||
|
||||
class VirtualIP(ResourceDescriptor):
|
||||
def __init__(self, vip, nic='eth0'):
|
||||
self.vip = vip
|
||||
self.nic = 'eth0'
|
||||
|
||||
def configure_resource(self, crm):
|
||||
ipaddr = ipaddress.ip_address(self.vip)
|
||||
if isinstance(ipaddr, ipaddress.IPv4Address):
|
||||
res_type = 'ocf:heartbeat:IPAddr2'
|
||||
res_parms = 'ip={ip} nic={nic}'.format(ip=self.vip,
|
||||
nic=self.nic)
|
||||
else:
|
||||
res_type = 'ocf:heartbeat:IPv6addr'
|
||||
res_params = 'ipv6addr={ip} nic={nic}'.format(ip=self.vip,
|
||||
nic=self.nic)
|
||||
|
||||
crm.primitive('res_vip', res_type, params=res_params,
|
||||
op='monitor interval="10s"')
|
||||
crm.clone('cl_res_vip', 'res_vip')
|
||||
```
|
||||
|
||||
Once the VirtualIP class above has been defined in charm code, it can make
|
||||
the code a bit cleaner. The example above can thusly be written as:
|
||||
|
||||
```python
|
||||
@when('ha.connected')
|
||||
def cluster_connected(hacluster):
|
||||
resources = CRM()
|
||||
resources.add(VirtualIP('192.168.100.1'))
|
||||
|
||||
hacluster.bind_on(iface='eth0', mcastport=4430)
|
||||
hacluster.manage_resources(resources)
|
||||
```
|
|
@ -0,0 +1,513 @@
|
|||
#!/usr/bin/python
|
||||
# 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.
|
||||
|
||||
from six import string_types
|
||||
|
||||
|
||||
class CRM(dict):
|
||||
"""
|
||||
Configuration object for Pacemaker resources for the HACluster
|
||||
interface. This class provides access to the supported resources
|
||||
available in the 'crm configure' within the HACluster.
|
||||
|
||||
See Also
|
||||
--------
|
||||
More documentation is available regarding the definitions of
|
||||
primitives, clones, and other pacemaker resources at the crmsh
|
||||
site at http://crmsh.github.io/man
|
||||
"""
|
||||
|
||||
# Constants provided for ordering constraints (e.g. the kind value)
|
||||
MANDATORY = "Mandatory"
|
||||
OPTIONAL = "Optional"
|
||||
SERIALIZE = "Serialize"
|
||||
|
||||
# Constants defining weights of constraints
|
||||
INFINITY = "inf"
|
||||
NEG_INFINITY = "-inf"
|
||||
|
||||
# Constaints aliased to their interpretations for constraints
|
||||
ALWAYS = INFINITY
|
||||
NEVER = NEG_INFINITY
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self['resources'] = {}
|
||||
self['delete_resources'] = []
|
||||
self['resource_params'] = {}
|
||||
self['groups'] = {}
|
||||
self['ms'] = {}
|
||||
self['orders'] = {}
|
||||
self['colocations'] = {}
|
||||
self['clones'] = {}
|
||||
self['locations'] = {}
|
||||
self['init_Services'] = []
|
||||
super(CRM, self).__init__(*args, **kwargs)
|
||||
|
||||
def primitive(self, name, agent, description=None, **kwargs):
|
||||
"""Configures a primitive resource within Pacemaker.
|
||||
|
||||
A primitive is used to describe a resource which should be managed
|
||||
by the cluster. Primitives consist of a name, the agent type, and
|
||||
various configuration options to the primitive. For example:
|
||||
|
||||
crm.primitive('www8', 'apache',
|
||||
params='configfile=/etc/apache/www8.conf',
|
||||
operations='$id-ref=apache_ops')
|
||||
|
||||
will create the an apache primitive (resource) for the www8 service
|
||||
hosted by the Apache HTTP server. The parameters specified can either
|
||||
be provided individually (e.g. a string) or as an iterable.
|
||||
|
||||
The following example shows how to specify multiple ops for a drbd
|
||||
volume in a Master/Slave configuration::
|
||||
|
||||
ops = ['monitor role=Master interval=60s',
|
||||
'monitor role=Slave interval=300s']
|
||||
|
||||
crm.primitive('r0', 'ocf:linbit:drbd',
|
||||
params='drbd_resource=r0',
|
||||
op=ops)
|
||||
|
||||
Additional arguments may be passed in as kwargs in which the key of
|
||||
the kwarg is prepended to the value.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name: str
|
||||
the name of the primitive.
|
||||
agent: str
|
||||
the type of agent to use to monitor the primitive resource
|
||||
(e.g. ocf:linbit:drbd).
|
||||
description: str, optional, kwarg
|
||||
a description about the resource
|
||||
params: str or iterable, optional, kwarg
|
||||
parameters which are provided to the resource agent
|
||||
meta: str or iterable, optional, kwarg
|
||||
metadata information for the primitive resource
|
||||
utilization: str or iterable, optional, kwarg
|
||||
utilization information for the primitive resource
|
||||
operations: str or iterable, optional, kwarg
|
||||
operations information for the primitive resource in id_spec
|
||||
format (e.g. $id=<id> or $id-ref=<id>)
|
||||
op: str or iterable, optional, kwarg
|
||||
op information regarding the primitive resource. This takes the
|
||||
form of '<start|stop|monitor> [<attr>=<value> <attr>=<value> ...]'
|
||||
|
||||
Returns
|
||||
-------
|
||||
None
|
||||
|
||||
See Also
|
||||
--------
|
||||
http://crmsh.github.io/man/#cmdhelp_configure_primitive
|
||||
"""
|
||||
resources = self['resources']
|
||||
resources[name] = agent
|
||||
|
||||
specs = ''
|
||||
if description:
|
||||
specs = specs + 'description="%s"' % description
|
||||
|
||||
# Use the ordering specified in the crm manual
|
||||
for key in 'params', 'meta', 'utilization', 'operations', 'op':
|
||||
if key not in kwargs:
|
||||
continue
|
||||
specs = specs + (' %s' % self._parse(key, kwargs[key]))
|
||||
|
||||
if specs:
|
||||
self['resource_params'][name] = specs
|
||||
|
||||
def _parse(self, prefix, data):
|
||||
results = ''
|
||||
if isinstance(data, string_types):
|
||||
data = [data]
|
||||
|
||||
first = True
|
||||
for d in data:
|
||||
if first:
|
||||
results = results + ' '
|
||||
first = False
|
||||
results = results + ('%s %s' % (prefix, d))
|
||||
|
||||
return results
|
||||
|
||||
def clone(self, name, resource, description=None, **kwargs):
|
||||
"""Creates a resource which should run on all nodes.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name: str
|
||||
the name of the clone
|
||||
resource: str
|
||||
the name or id of the resource to clone
|
||||
description: str, optional
|
||||
text containing a description for the clone
|
||||
meta: str or list of str, optional, kwarg
|
||||
metadata attributes to assign to the clone
|
||||
params: str or list of str, optional, kwarg
|
||||
parameters to assign to the clone
|
||||
|
||||
Returns
|
||||
-------
|
||||
None
|
||||
|
||||
See Also
|
||||
--------
|
||||
http://crmsh.github.io/man/#cmdhelp_configure_clone
|
||||
"""
|
||||
clone_specs = resource
|
||||
if description:
|
||||
clone_specs = clone_specs + (' description="%s"' % description)
|
||||
|
||||
for key in 'meta', 'params':
|
||||
if key not in kwargs:
|
||||
continue
|
||||
value = kwargs[key]
|
||||
if not value:
|
||||
continue
|
||||
clone_specs = clone_specs + (' %s' % self._parse(key, value))
|
||||
|
||||
self['clones'][name] = clone_specs
|
||||
|
||||
def colocation(self, name, score=ALWAYS, *resources, **kwargs):
|
||||
"""Configures the colocation constraints of resources.
|
||||
|
||||
Provides placement constraints regarding resources defined within
|
||||
the cluster. Using the colocate function, resource affinity or
|
||||
anti-affinity can be defined.
|
||||
|
||||
For example, the following code ensures that the nova-console service
|
||||
always runs where the cluster vip is running:
|
||||
|
||||
crm.colocation('console_with_vip', ALWAYS,
|
||||
'nova-console', 'vip')
|
||||
|
||||
The affinity or anti-affinity of resources relationships is be
|
||||
expressed in the `score` parameter. A positive score indicates that
|
||||
the resources should run on the same node.A score of INFINITY (or
|
||||
ALWAYS) will ensure the resources are always run on the same node(s)
|
||||
and a score of NEG_INFINITY (or NEVER) ensures that the resources are
|
||||
never run on the same node(s).
|
||||
|
||||
crm.colocation('never_apache_with_dummy', NEVER,
|
||||
'apache', 'dummy')
|
||||
|
||||
Any *resources values which are provided are treated as resources which
|
||||
the colocation constraint applies to. At least two resources must be
|
||||
defined as part of the ordering constraint.
|
||||
|
||||
The resources take the form of <resource_name>[:role]. If the
|
||||
colocation constraint applies specifically to a role, this information
|
||||
should be included int he resource supplied.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
id: str
|
||||
id or name of the colocation constraint
|
||||
score: str {ALWAYS, INFINITY, NEVER, NEGATIVE_INFINITY} or int
|
||||
the score or weight of the colocation constraint. A positive value
|
||||
will indicate that the resources should run on the same node. A
|
||||
negative value indicates that the resources should run on separate
|
||||
nodes.
|
||||
resources: str or list
|
||||
the list of resources which the colocation constraint applies to.
|
||||
node_attribute: str, optional, kwarg
|
||||
can be used to run the resources on a set of nodes, not just a
|
||||
single node.
|
||||
|
||||
Returns
|
||||
-------
|
||||
None
|
||||
|
||||
See Also
|
||||
--------
|
||||
http://crmsh.github.io/man/#cmdhelp_configure_colocation
|
||||
"""
|
||||
specs = '%s: %s' % (score, ' '.join(resources))
|
||||
if 'node_attribute' in kwargs:
|
||||
specs = specs + (' node-attribute=%s' % kwargs['node_attribute'])
|
||||
self['colocations'][name] = specs
|
||||
|
||||
def group(self, name, *resources, **kwargs):
|
||||
"""Creates a group of resources within Pacemaker.
|
||||
|
||||
The created group includes the list of resources provided in the list
|
||||
of resources supplied. For example::
|
||||
|
||||
crm.group('grp_mysql', 'res_mysql_rbd', 'res_mysql_fs',
|
||||
'res_mysql_vip', 'res_mysqld')
|
||||
|
||||
will create the 'grp_mysql' resource group consisting of the
|
||||
res_mysql_rbd, res_mysql_fs, res_mysql_vip, and res_mysqld resources.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name: str
|
||||
the name of the group resource
|
||||
resources: list of str
|
||||
the names or ids of resources to include within the group.
|
||||
description: str, optional, kwarg
|
||||
text to describe the resource
|
||||
meta: str or list of str, optional, kwarg
|
||||
metadata attributes to assign to the group
|
||||
params: str or list of str, optional, kwarg
|
||||
parameters to assign to the group
|
||||
|
||||
Returns
|
||||
-------
|
||||
None
|
||||
|
||||
See Also
|
||||
--------
|
||||
http://crmsh.github.io/man/#cmdhelp_configure_group
|
||||
"""
|
||||
specs = ' '.join(resources)
|
||||
if 'description' in kwargs:
|
||||
specs = specs + (' description="' % kwargs['description'])
|
||||
|
||||
for key in 'meta', 'params':
|
||||
if key not in kwargs:
|
||||
continue
|
||||
value = kwargs[key]
|
||||
specs = specs + (' %s' % self._parse(key, value))
|
||||
|
||||
self['groups'][name] = specs
|
||||
|
||||
def delete_resource(self, *resources):
|
||||
"""Deletes one or more objects/resources within Pacemaker.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
resources: str or list
|
||||
the name or id of the specific resource to delete.
|
||||
|
||||
Returns
|
||||
-------
|
||||
None
|
||||
|
||||
See Also
|
||||
--------
|
||||
http://crmsh.github.io/man/#cmdhelp_configure_delete
|
||||
"""
|
||||
self['delete_resources'].extend(resources)
|
||||
|
||||
def init_services(self, *resources):
|
||||
"""Specifies that the service(s) is an init or upstart service.
|
||||
|
||||
Services (resources) which are noted as upstart services are
|
||||
disabled, stopped, and left to pacemaker to manage the resource.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
resources: str or list of str, varargs
|
||||
The resources which should be noted as init services.
|
||||
|
||||
Returns
|
||||
-------
|
||||
None
|
||||
"""
|
||||
self['init_services'].extend(resources)
|
||||
|
||||
def ms(self, name, resource, description=None, **kwargs):
|
||||
"""Create a master/slave resource type.
|
||||
|
||||
The following code provides an example of creating a master/slave
|
||||
resource on drbd disk1::
|
||||
|
||||
crm.ms('disk1', 'drbd1', meta='notify=true globally-unique=false')
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name: str
|
||||
the name or id of the master resource
|
||||
resource: str
|
||||
the name or id of the resource which now ha a master/slave
|
||||
assocation tied to it.
|
||||
description: str, optional
|
||||
a textual description of the master resource
|
||||
meta: str or list of strs, optional, kwargs
|
||||
strings defining the metadata for the master/slave resource type
|
||||
params: str or list of strs, optional, kwargs
|
||||
parameter strings which should be passed to the master/slave
|
||||
resource creation
|
||||
|
||||
Returns
|
||||
-------
|
||||
None
|
||||
|
||||
See Also
|
||||
--------
|
||||
http://crmsh.github.io/man/#cmdhelp_configure_ms
|
||||
"""
|
||||
specs = resource
|
||||
if description:
|
||||
specs = specs + (' description="%s"' % description)
|
||||
|
||||
for key in 'meta', 'params':
|
||||
if key not in kwargs:
|
||||
continue
|
||||
value = kwargs[key]
|
||||
specs = specs + (' %s' % self._parse(key, value))
|
||||
|
||||
self['ms'][name] = specs
|
||||
|
||||
def location(self, name, resource, **kwargs):
|
||||
"""Defines the preference of nodes for the given resource.
|
||||
|
||||
The location constraitns consist of one or more rules which specify
|
||||
a score to be awarded if the rules match.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name: str
|
||||
the name or id of the location constraint
|
||||
resource: str
|
||||
the name, id, resource, set, tag, or resoruce pattern defining the
|
||||
set of resources which match the location placement constraint.
|
||||
attributes: str or list str, optional, kwarg
|
||||
attributes which should be assigned to the location constraint
|
||||
rule: str or list of str, optional, kwarg
|
||||
the rule(s) which define the location constraint rules when
|
||||
selecting a location to run the resource.
|
||||
|
||||
Returns
|
||||
-------
|
||||
None
|
||||
|
||||
See Also
|
||||
--------
|
||||
http://crmsh.github.io/man/#cmdhelp_configure_location
|
||||
"""
|
||||
specs = resource
|
||||
|
||||
# Check if there are attributes assigned to the location and if so,
|
||||
# format the spec string with the attributes
|
||||
if 'attributes' in kwargs:
|
||||
attrs = kwargs['attributes']
|
||||
if isinstance(attrs, string_types):
|
||||
attrs = [attrs]
|
||||
specs = specs + (' %s' % ' '.join(attrs))
|
||||
|
||||
if 'rule' in kwargs:
|
||||
rules = kwargs['rule']
|
||||
specs = specs + (' %s' % self._parse('rule', rules))
|
||||
|
||||
self['locations'][name] = specs
|
||||
|
||||
def order(self, name, score=None, *resources, **kwargs):
|
||||
"""Configures the ordering constraints of resources.
|
||||
|
||||
Provides ordering constraints to resources defined in a Pacemaker
|
||||
cluster which affect the way that resources are started, stopped,
|
||||
promoted, etc. Basic ordering is provided by simply specifying the
|
||||
ordering name and an ordered list of the resources which the ordering
|
||||
constraint applies to.
|
||||
|
||||
For example, the following code ensures that the apache resource is
|
||||
started after the ClusterIP is started::
|
||||
|
||||
hacluster.order('apache-after-ip', 'ClusterIP', 'apache')
|
||||
|
||||
By default, the ordering constraint will specify that the ordering
|
||||
constraint is mandatory. The constraint behavior can be specified
|
||||
using the 'score' keyword argument, e.g.::
|
||||
|
||||
hacluster.order('apache-after-ip', score=hacluster.OPTIONAL,
|
||||
'ClusterIP', 'apache')
|
||||
|
||||
Any *resources values which are provided are treated as resources which
|
||||
the ordering constraint applies to. At least two resources must be
|
||||
defined as part of the ordering constraint.
|
||||
|
||||
The resources take the form of <resource_name>[:<action>]. If the
|
||||
ordering constraint applies to a specific action for the resource,
|
||||
this information should be included in the resource supplied.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name: str
|
||||
the id or name of the order constraint
|
||||
resoures: str or list of strs in varargs format
|
||||
the resources the ordering constraint applies to. The ordering
|
||||
of the list of resources is used to provide the ordering.
|
||||
score: {MANDATORY, OPTIONAL, SERIALIZED}, optional
|
||||
the score of the ordering constraint.
|
||||
symmetrical: boolean, optional, kwarg
|
||||
when True, then the services for the resources will be stopped in
|
||||
the reverse order. The default value for this is True.
|
||||
|
||||
Returns
|
||||
-------
|
||||
None
|
||||
|
||||
See Also
|
||||
--------
|
||||
http://crmsh.github.io/man/#cmdhelp_configure_order
|
||||
"""
|
||||
specs = ''
|
||||
if score:
|
||||
specs = '%s:' % score
|
||||
|
||||
specs = specs + (' %s' % ' '.join(resources))
|
||||
if 'symmetrical' in kwargs:
|
||||
specs = specs + (' symmetrical=' % kwargs['symmetrical'])
|
||||
|
||||
self['orders'][name] = specs
|
||||
|
||||
def add(self, resource_desc):
|
||||
"""Adds a resource descriptor object to the CRM configuration.
|
||||
|
||||
Adds a `ResourceDescriptor` object to the CRM configuration which
|
||||
understands how to configure the resource itself. The
|
||||
`ResourceDescriptor` object needs to know how to interact with this
|
||||
CRM class in order to properly configure the pacemaker resources.
|
||||
|
||||
The minimum viable resource descriptor object will implement a method
|
||||
which takes a reference parameter to this CRM in order to configure
|
||||
itself.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
resource_desC: ResourceDescriptor
|
||||
an object which provides an abstraction of a monitored resource
|
||||
within pacemaker.
|
||||
|
||||
Returns
|
||||
-------
|
||||
None
|
||||
"""
|
||||
method = getattr(resource_desc, 'configure_resource', None)
|
||||
if not callable(method):
|
||||
raise ValueError('Invalid resource_desc. The "configure_resource"'
|
||||
' function has not been defined.')
|
||||
|
||||
method(self)
|
||||
|
||||
|
||||
class ResourceDescriptor(object):
|
||||
"""
|
||||
A ResourceDescriptor provides a logical resource or concept and knows
|
||||
how to configure pacemaker.
|
||||
"""
|
||||
|
||||
def configure_resource(self, crm):
|
||||
"""Configures the logical resource(s) within the CRM.
|
||||
|
||||
This is the callback method which is invoked by the CRM in order
|
||||
to allow this ResourceDescriptor to fully configure the logical
|
||||
resource.
|
||||
|
||||
For example, a Virtual IP may provide a standard abstraction and
|
||||
configure the specific details under the covers.
|
||||
"""
|
||||
pass
|
|
@ -0,0 +1,21 @@
|
|||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0
|
||||
|
||||
Files: *
|
||||
Copyright: 2015, Canonical Ltd.
|
||||
License: Apache-2.0
|
||||
|
||||
License: Apache-2.0
|
||||
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.
|
||||
.
|
||||
On Debian-based systems the full text of the Apache version 2.0 license
|
||||
can be found in `/usr/share/common-licenses/Apache-2.0'.
|
|
@ -0,0 +1,5 @@
|
|||
name: hacluster
|
||||
summary: |
|
||||
Provides the hacluster interface used for configuring Corosync
|
||||
and Pacemaker services.
|
||||
maintainer: OpenStack Charmers <openstack-charmers@lists.ubuntu.com>
|
|
@ -0,0 +1,65 @@
|
|||
#!/usr/bin/python
|
||||
# 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.
|
||||
|
||||
from charms.reactive import hook
|
||||
from charms.reactive import RelationBase
|
||||
from charms.reactive import scopes
|
||||
|
||||
|
||||
class HAClusterRequires(RelationBase):
|
||||
# The hacluster charm is a subordinate charm and really only works
|
||||
# for a single service to the HA Cluster relation, therefore set the
|
||||
# expected scope to be GLOBAL.
|
||||
scope = scopes.GLOBAL
|
||||
|
||||
@hook('{requires:hacluster}-relation-joined')
|
||||
def joined(self):
|
||||
self.set_state('{relation_name}.connected')
|
||||
|
||||
@hook('{requires:hacluster}-relation-changed')
|
||||
def changed(self):
|
||||
self.set_state('{relation_name}.available')
|
||||
|
||||
@hook('{requires:hacluster}-relation-{broken,departed}')
|
||||
def departed(self):
|
||||
self.remove_state('{relation_name}.available')
|
||||
self.remove_state('{relation_name}.connected')
|
||||
|
||||
def bind_on(self, iface=None, mcastport=None):
|
||||
relation_data = {}
|
||||
if iface:
|
||||
relation_data['corosync_bindiface'] = iface
|
||||
if mcastport:
|
||||
relation_data['corosync_mcastport'] = mcastport
|
||||
|
||||
if relation_data:
|
||||
self.set_local(**relation_data)
|
||||
self.set_remote(**relation_data)
|
||||
|
||||
def manage_resources(self, crm):
|
||||
"""
|
||||
Request for the hacluster to manage the resources defined in the
|
||||
crm object.
|
||||
|
||||
res = CRM()
|
||||
res.primitive('res_neutron_haproxy', 'lsb:haproxy',
|
||||
op='monitor interval="5s"')
|
||||
res.init_services('haproxy')
|
||||
res.clone('cl_nova_haproxy', 'res_neutron_haproxy')
|
||||
|
||||
hacluster.manage_resources(crm)
|
||||
|
||||
"""
|
||||
relation_data = {k: v for k, v in crm.items() if v}
|
||||
self.set_local(**relation_data)
|
||||
self.set_remote(**relation_data)
|
|
@ -0,0 +1,3 @@
|
|||
flake8>=2.2.4,<=2.4.1
|
||||
os-testr>=0.4.1
|
||||
charm-tools
|
|
@ -0,0 +1,25 @@
|
|||
[tox]
|
||||
envlist = lint,py27
|
||||
skipsdist = True
|
||||
|
||||
[testenv]
|
||||
setenv = VIRTUAL_ENV={envdir}
|
||||
PYTHONHASHSEED=0
|
||||
install_command =
|
||||
pip install --allow-unverified python-apt {opts} {packages}
|
||||
commands = ostestr {posargs}
|
||||
|
||||
[testenv:py27]
|
||||
basepython = python2.7
|
||||
deps = -r{toxinidir}/test-requirements.txt
|
||||
|
||||
[testenv:lint]
|
||||
basepython = python2.7
|
||||
deps = -r{toxinidir}/test-requirements.txt
|
||||
commands = flake8 {posargs}
|
||||
|
||||
[testenv:venv]
|
||||
commands = {posargs}
|
||||
|
||||
[flake8]
|
||||
ignore = E402,E226
|
Loading…
Reference in New Issue