Giuseppe Lavagetto has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/261375

Change subject: [WiP] add native ipvs manager
......................................................................

[WiP] add native ipvs manager

Change-Id: Ic3274ca243584c1bc06d31b8f70d228399146170
---
M pybal/ipvs.py
A pybal/ipvs/__init__.py
A pybal/ipvs/native.py
3 files changed, 174 insertions(+), 5 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/operations/debs/pybal 
refs/changes/75/261375/1

diff --git a/pybal/ipvs.py b/pybal/ipvs.py
index 06e73ee..cd0d2db 100644
--- a/pybal/ipvs.py
+++ b/pybal/ipvs.py
@@ -5,8 +5,9 @@
 LVS state/configuration classes for PyBal
 """
 from . import util
-
+from ipvs import native
 import os
+
 log = util.log
 
 
@@ -37,8 +38,6 @@
         stdin.close()
 
         # FIXME: Check return code and act on failure
-
-
 
     @staticmethod
     def subCommandService(service):
@@ -155,8 +154,6 @@
     """Class that maintains the state of a single LVS service
     instance."""
 
-    ipvsManager = IPVSManager
-
     SVC_PROTOS = ('tcp', 'udp')
     SVC_SCHEDULERS = ('rr', 'wrr', 'lc', 'wlc', 'lblc', 'lblcr', 'dh', 'sh',
                       'sed', 'nq')
@@ -178,6 +175,11 @@
 
         self.configuration = configuration
 
+        if configuration.getboolean('native_ipvs', False):
+            self.ipvsManager = native.IPVSManager
+        else:
+            self.ipvsManager = IPVSManager
+
         self.ipvsManager.DryRun = configuration.getboolean('dryrun', False)
         self.ipvsManager.Debug = configuration.getboolean('debug', False)
 
diff --git a/pybal/ipvs/__init__.py b/pybal/ipvs/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/pybal/ipvs/__init__.py
diff --git a/pybal/ipvs/native.py b/pybal/ipvs/native.py
new file mode 100644
index 0000000..49cd996
--- /dev/null
+++ b/pybal/ipvs/native.py
@@ -0,0 +1,167 @@
+# Use github.com/lavagetto/gnlpy, not the facebook's one
+from gnlpy import ipvs as netlink
+from pybal import util
+import socket
+
+log = util.log
+
+
+class IpvsCommand(object):
+    _protocols = {
+        'tcp': socket.IPPROTO_TCP,
+        'udp': socket.IPPROTO_UDP
+    }
+
+    def run(self, client):
+        raise NotImplementedError()
+
+    def log(self):
+        raise NotImplementedError()
+
+
+class IpvsCommandService(netlink.Service, IpvsCommand):
+
+    def __init__(self, service):
+        self._action = 'add'
+        # Let's call the init of the service
+        super(IpvsCommandService, self).__init__(
+            IpvsCommandService._from_tuple(service),
+            validate=True)
+
+    @staticmethod
+    def _from_tuple(tup):
+        return {
+            'proto': tup[0],
+            'vip': tup[1],
+            'port': tup[2],
+            'sched': tup[3] if len(tup) > 3 else 'rr'
+        }
+
+    def log(self):
+        if self.action == 'add':
+            log.debug("Adding service '%s://%s:%d' with scheduler %s",
+                      self.proto_, self.vip_, self.port_, self.sched_)
+        elif self.action == 'del':
+            log.debug("Removing service '%s://%s:%d'", self.proto_, self.vip_,
+                      self.port_)
+
+    def proto(self):
+        return self._protocols.get(self.proto_, socket.IPPROTO_TCP)
+
+    def run(self, client):
+        if self.action == 'add':
+            client.add_service(self.vip_, self.port_, protocol=self.proto(),
+                               sched_name=self.sched_)
+        elif self.action == 'del':
+            client.del_service(self.vip_, self.port_, protocol=proto)
+        else:
+            raise ValueError("Action %s is not supported", self.action)
+
+
+class IpvsCommandServer(netlink.Server, IpvsCommand):
+
+    def __init__(self, server, service):
+        """
+        Manages addition of a server to a pool
+        """
+        self.action = 'add'
+        self.ip_ = server.ip or socket.gethostbyname(server.host)
+        self.weight_ = server.weight or 1
+        self.port_ = server.port
+        self.fwd_method_ = netlink.IPVS_ROUTING
+        self.service = IpvsCommandService(service)
+        self.validate()
+
+    def log(self):
+        log.debug("%s server %s to service %s:%d with weight %d",
+                  self.action.upper(), self.ip_, self.vip_, self.port_,
+                  self.weight_)
+
+    def run(self, client):
+        if self.action == 'add':
+            client.add_dest(self.service.vip(), self.port_, self.ip_,
+                            protocol=self.service.proto(), weight=self.weight_,
+                            method=self.fwd_method_)
+        elif self.action == 'del':
+            client.del_dest(self.service.vip(), self.port_, self.ip_,
+                            protocol=self.service.proto())
+        elif self.action == 'edit':
+            client.update_dest(self.service.vip(), self.port_, self.ip_,
+                               protocol=self.service.proto(),
+                               weight=self.weight_, method=self.fwd_method_)
+        else:
+            raise ValueError("Action %s is not supported", self.action)
+
+
+class IPVSManager(object):
+    """Class that provides the ability to manage ipvs pools via the netlink 
library"""
+
+    DryRun = True
+
+    Debug = False
+
+    @staticmethod
+    def get_client(cls):
+        return netlink.IpvsClient()
+
+    @classmethod
+    def modifyState(cls, cmdList):
+        client = cls.get_client()
+        for cmd in cmdList:
+            if cls.Debug:
+                cmd.log()
+            if not cls.DryRun:
+                cmd.run(client)
+
+    @classmethod
+    def commandRemoveService(cls, service):
+        """Returns an ipvsadm command to remove a single service."""
+        srv = IpvsCommandService(service)
+        srv.action = 'del'
+        return srv
+
+    @classmethod
+    def commandAddService(cls, service):
+        """Returns an ipvsadm command to add a specified service.
+
+        Arguments:
+            service:    tuple(protocol, address, port, ...)
+        """
+        srv = IpvsCommandService(service)
+        return srv
+
+    @classmethod
+    def commandRemoveServer(cls, service, server):
+        """Returns an ipvsadm command to remove a server from a service.
+
+        Arguments:
+            service:   tuple(protocol, address, port, ...)
+            server:    Server
+        """
+        host = IpvsCommandServer(server, service)
+        host.action = 'del'
+        return host
+
+    @classmethod
+    def commandAddServer(cls, service, server):
+        """Returns an ipvsadm command to add a server to a service.
+
+        Arguments:
+            service:   tuple(protocol, address, port, ...)
+            server:    Server
+        """
+        host = IpvsCommandServer(server, service)
+        return host
+
+    @classmethod
+    def commandEditServer(cls, service, server):
+        """Returns an ipvsadm command to edit the parameters of a
+        server.
+
+        Arguments:
+            service:   tuple(protocol, address, port, ...)
+            server:    Server
+        """
+        host = IpvsCommandServer(server, service)
+        host.action = 'edit'
+        return host

-- 
To view, visit https://gerrit.wikimedia.org/r/261375
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ic3274ca243584c1bc06d31b8f70d228399146170
Gerrit-PatchSet: 1
Gerrit-Project: operations/debs/pybal
Gerrit-Branch: master
Gerrit-Owner: Giuseppe Lavagetto <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to