From 887a7256b8818cfcdd484da8c9ac08610690db34 Mon Sep 17 00:00:00 2001 From: Liam Young Date: Wed, 1 Jun 2016 09:54:14 +0000 Subject: [PATCH 1/3] Add more common code Add methods for setting up hacluster resources in interface to allow external code to cleanly call .add_ rather than having to import specific methods from common.py --- common.py | 39 +++++++++++++++++++++++++++++++++++++++ requires.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/common.py b/common.py index 2ac68f7..6f1174b 100644 --- a/common.py +++ b/common.py @@ -511,3 +511,42 @@ class ResourceDescriptor(object): configure the specific details under the covers. """ pass + +class InitService(ResourceDescriptor): + def __init__(self, service_name, init_service_name): + self.service_name = service_name + self.init_service_name = init_service_name + + def configure_resource(self, crm): + res_key = 'res_{}_{}'.format( + self.service_name.replace('-', '_'), + self.init_service_name.replace('-', '_')) + clone_key = 'cl_{}'.format(res_key) + res_type = 'lsb:{}'.format(self.init_service_name) + crm.primitive(res_key, res_type, params='op monitor interval="5s"') + crm.init_services(self.init_service_name) + crm.clone(clone_key, res_key) + + +class VirtualIP(ResourceDescriptor): + def __init__(self, service_name, vip, nic=None, cidr=None): + self.service_name = service_name + self.vip = vip + self.nic = nic + self.cidr = cidr + + def configure_resource(self, crm): + vip_key = 'res_{}_{}_vip'.format(self.service_name, self.nic) + ipaddr = ipaddress.ip_address(self.vip) + if isinstance(ipaddr, ipaddress.IPv4Address): + res_type = 'ocf:heartbeat:IPaddr2' + res_params = 'ip="{}"'.format(self.vip) + else: + res_type = 'ocf:heartbeat:IPv6addr' + res_params = 'ipv6addr="{}"'.format(self.vip) + + if self.nic: + res_params = '{} nic="{}"'.format(res_params, self.nic) + if self.cidr: + res_params = '{} cidr_netmask="{}"'.format(res_params, self.cidr) + crm.primitive(vip_key, res_type, params=res_params) diff --git a/requires.py b/requires.py index 498ced9..9750ab4 100644 --- a/requires.py +++ b/requires.py @@ -11,6 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import relations.hacluster.common from charms.reactive import hook from charms.reactive import RelationBase from charms.reactive import scopes @@ -63,3 +64,44 @@ class HAClusterRequires(RelationBase): relation_data = {k: v for k, v in crm.items() if v} self.set_local(**relation_data) self.set_remote(**relation_data) + + + def bind_resources(self, iface, mcastport=None): + """Inform the ha subordinate about each service it should manage. The + child class specifies the services via self.ha_resources + + @param hacluster interface + """ + if not mcastport: + mcastport=4440 + resources = self.get_local('resources') + self.bind_on(iface=iface, mcastport=mcastport) + self.manage_resources(resources) + + + def add_vip(self, name, vip, iface, netmask): + """Add a VirtualIP object for each user specified vip to self.resources + """ + resources = self.get_local('resources') + if not resources: + resources=relations.hacluster.common.CRM() + resources.add( + relations.hacluster.common.VirtualIP( + self.name, + vip, + nic=iface, + cidr=netmask,)) + self.set_local(resources=resources) + + + def add_init_service(self, name, service): + """Add a InitService object for haproxy to self.resources + """ + resources = self.get_local('resources') + if not resources: + resources=relations.hacluster.common.CRM() + resources.add( + relations.hacluster.common.InitService( + name, + service,)) + self.set_local(resources=resources) From e5f2140cf50eb5d6d4e4a7314199dc354761266e Mon Sep 17 00:00:00 2001 From: Liam Young Date: Wed, 1 Jun 2016 09:54:14 +0000 Subject: [PATCH 2/3] Add more common code Add methods for setting up hacluster resources in interface to allow external code to cleanly call .add_ rather than having to import specific methods from common.py --- common.py | 41 ++++++++++++++++++++++++++++++++++++++++- requires.py | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/common.py b/common.py index 2ac68f7..8b937a6 100644 --- a/common.py +++ b/common.py @@ -11,9 +11,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +import ipaddress from six import string_types - class CRM(dict): """ Configuration object for Pacemaker resources for the HACluster @@ -511,3 +511,42 @@ class ResourceDescriptor(object): configure the specific details under the covers. """ pass + +class InitService(ResourceDescriptor): + def __init__(self, service_name, init_service_name): + self.service_name = service_name + self.init_service_name = init_service_name + + def configure_resource(self, crm): + res_key = 'res_{}_{}'.format( + self.service_name.replace('-', '_'), + self.init_service_name.replace('-', '_')) + clone_key = 'cl_{}'.format(res_key) + res_type = 'lsb:{}'.format(self.init_service_name) + crm.primitive(res_key, res_type, params='op monitor interval="5s"') + crm.init_services(self.init_service_name) + crm.clone(clone_key, res_key) + + +class VirtualIP(ResourceDescriptor): + def __init__(self, service_name, vip, nic=None, cidr=None): + self.service_name = service_name + self.vip = vip + self.nic = nic + self.cidr = cidr + + def configure_resource(self, crm): + vip_key = 'res_{}_{}_vip'.format(self.service_name, self.nic) + ipaddr = ipaddress.ip_address(self.vip) + if isinstance(ipaddr, ipaddress.IPv4Address): + res_type = 'ocf:heartbeat:IPaddr2' + res_params = 'ip="{}"'.format(self.vip) + else: + res_type = 'ocf:heartbeat:IPv6addr' + res_params = 'ipv6addr="{}"'.format(self.vip) + + if self.nic: + res_params = '{} nic="{}"'.format(res_params, self.nic) + if self.cidr: + res_params = '{} cidr_netmask="{}"'.format(res_params, self.cidr) + crm.primitive(vip_key, res_type, params=res_params) diff --git a/requires.py b/requires.py index 498ced9..a917d3b 100644 --- a/requires.py +++ b/requires.py @@ -11,6 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import relations.hacluster.common from charms.reactive import hook from charms.reactive import RelationBase from charms.reactive import scopes @@ -61,5 +62,51 @@ class HAClusterRequires(RelationBase): """ relation_data = {k: v for k, v in crm.items() if v} + print(relation_data) self.set_local(**relation_data) self.set_remote(**relation_data) + + + def bind_resources(self, iface, mcastport=None): + """Inform the ha subordinate about each service it should manage. The + child class specifies the services via self.ha_resources + + @param hacluster interface + """ + if not mcastport: + mcastport=4440 + resources = self.get_local('resources') + self.bind_on(iface=iface, mcastport=mcastport) + self.manage_resources(resources) + + + def add_vip(self, name, vip, iface, netmask): + """Add a VirtualIP object for each user specified vip to self.resources + """ + resource_dict = self.get_local('resources') + if resource_dict: + resources=relations.hacluster.common.CRM(**resource_dict) + else: + resources=relations.hacluster.common.CRM() + resources.add( + relations.hacluster.common.VirtualIP( + name, + vip, + nic=iface, + cidr=netmask,)) + self.set_local(resources=resources) + + + def add_init_service(self, name, service): + """Add a InitService object for haproxy to self.resources + """ + resource_dict = self.get_local('resources') + if resource_dict: + resources=relations.hacluster.common.CRM(**resource_dict) + else: + resources=relations.hacluster.common.CRM() + resources.add( + relations.hacluster.common.InitService( + name, + service,)) + self.set_local(resources=resources) From 3e1adbf9094f30c64a14e3d202eec0ef37028775 Mon Sep 17 00:00:00 2001 From: Liam Young Date: Wed, 8 Jun 2016 14:03:50 +0000 Subject: [PATCH 3/3] Added docstring, lint fixes and general tidyup --- common.py | 26 ++++++++++++++++++++++++++ requires.py | 36 ++++++++++++++++++++++-------------- 2 files changed, 48 insertions(+), 14 deletions(-) diff --git a/common.py b/common.py index 8b937a6..ea50566 100644 --- a/common.py +++ b/common.py @@ -14,6 +14,7 @@ import ipaddress from six import string_types + class CRM(dict): """ Configuration object for Pacemaker resources for the HACluster @@ -512,12 +513,24 @@ class ResourceDescriptor(object): """ pass + class InitService(ResourceDescriptor): def __init__(self, service_name, init_service_name): + """Class for managing init resource + + :param service_name: string - Name of service + :param init_service_name: string - Name service uses in init system + :returns: None + """ self.service_name = service_name self.init_service_name = init_service_name def configure_resource(self, crm): + """"Configure new init system service resource in crm + + :param crm: CRM() instance - Config object for Pacemaker resources + :returns: None + """ res_key = 'res_{}_{}'.format( self.service_name.replace('-', '_'), self.init_service_name.replace('-', '_')) @@ -530,12 +543,25 @@ class InitService(ResourceDescriptor): class VirtualIP(ResourceDescriptor): def __init__(self, service_name, vip, nic=None, cidr=None): + """Class for managing VIP resource + + :param service_name: string - Name of service + :param vip: string - Virtual IP to be managed + :param nic: string - Network interface to bind vip to + :param cidr: string - Netmask for vip + :returns: None + """ self.service_name = service_name self.vip = vip self.nic = nic self.cidr = cidr def configure_resource(self, crm): + """Configure new vip resource in crm + + :param crm: CRM() instance - Config object for Pacemaker resources + :returns: None + """ vip_key = 'res_{}_{}_vip'.format(self.service_name, self.nic) ipaddr = ipaddress.ip_address(self.vip) if isinstance(ipaddr, ipaddress.IPv4Address): diff --git a/requires.py b/requires.py index a917d3b..d697a1e 100644 --- a/requires.py +++ b/requires.py @@ -60,34 +60,41 @@ class HAClusterRequires(RelationBase): hacluster.manage_resources(crm) + :param crm: CRM() instance - Config object for Pacemaker resources + :returns: None """ relation_data = {k: v for k, v in crm.items() if v} - print(relation_data) self.set_local(**relation_data) self.set_remote(**relation_data) - def bind_resources(self, iface, mcastport=None): """Inform the ha subordinate about each service it should manage. The child class specifies the services via self.ha_resources - @param hacluster interface + :param iface: string - Network interface to bind to + :param mcastport: int - Multicast port corosync should use for cluster + management traffic """ - if not mcastport: - mcastport=4440 + if mcastport is None: + mcastport = 4440 resources = self.get_local('resources') self.bind_on(iface=iface, mcastport=mcastport) self.manage_resources(resources) - def add_vip(self, name, vip, iface, netmask): """Add a VirtualIP object for each user specified vip to self.resources + + :param name: string - Name of service + :param vip: string - Virtual IP to be managed + :param iface: string - Network interface to bind vip to + :param netmask: string - Netmask for vip + :returns: None """ resource_dict = self.get_local('resources') if resource_dict: - resources=relations.hacluster.common.CRM(**resource_dict) + resources = relations.hacluster.common.CRM(**resource_dict) else: - resources=relations.hacluster.common.CRM() + resources = relations.hacluster.common.CRM() resources.add( relations.hacluster.common.VirtualIP( name, @@ -96,17 +103,18 @@ class HAClusterRequires(RelationBase): cidr=netmask,)) self.set_local(resources=resources) - def add_init_service(self, name, service): """Add a InitService object for haproxy to self.resources + + :param name: string - Name of service + :param service: string - Name service uses in init system + :returns: None """ resource_dict = self.get_local('resources') if resource_dict: - resources=relations.hacluster.common.CRM(**resource_dict) + resources = relations.hacluster.common.CRM(**resource_dict) else: - resources=relations.hacluster.common.CRM() + resources = relations.hacluster.common.CRM() resources.add( - relations.hacluster.common.InitService( - name, - service,)) + relations.hacluster.common.InitService(name, service,)) self.set_local(resources=resources)