diff --git a/common.py b/common.py index 2ac68f7..ea50566 100644 --- a/common.py +++ b/common.py @@ -11,6 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import ipaddress from six import string_types @@ -511,3 +512,67 @@ class ResourceDescriptor(object): configure the specific details under the covers. """ 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('-', '_')) + 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): + """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): + 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..d697a1e 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 @@ -59,7 +60,61 @@ 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} 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 iface: string - Network interface to bind to + :param mcastport: int - Multicast port corosync should use for cluster + management traffic + """ + 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) + 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 + + :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) + else: + resources = relations.hacluster.common.CRM() + resources.add( + relations.hacluster.common.InitService(name, service,)) + self.set_local(resources=resources)