modules.opnfv: fuel adapter: Switch to MCP
[releng.git] / modules / opnfv / deployment / manager.py
index f0e4429..2b5aedb 100644 (file)
@@ -27,7 +27,7 @@ class Deployment(object):
                  status,
                  openstack_version,
                  sdn_controller,
-                 nodes=[]):
+                 nodes=None):
 
         self.deployment_info = {
             'installer': installer,
@@ -56,7 +56,7 @@ class Deployment(object):
             version = self.deployment_info['openstack_version'].split('.')[0]
             name = os_versions[version]
             return name
-        except Exception as e:
+        except Exception:
             return 'Unknown release'
 
     def get_dict(self):
@@ -89,26 +89,38 @@ class Deployment(object):
             sdn_controller=self.deployment_info['sdn_controller'])
 
         for node in self.deployment_info['nodes']:
-            s += '\t\t{node_object}\n'.format(node_object=node)
+            s += '{node_object}\n'.format(node_object=node)
 
         return s
 
 
-class Node(object):
+class Role():
+    INSTALLER = 'installer'
+    CONTROLLER = 'controller'
+    COMPUTE = 'compute'
+    ODL = 'opendaylight'
+    ONOS = 'onos'
+
 
+class NodeStatus():
     STATUS_OK = 'active'
     STATUS_INACTIVE = 'inactive'
     STATUS_OFFLINE = 'offline'
-    STATUS_FAILED = 'failed'
+    STATUS_ERROR = 'error'
+    STATUS_UNUSED = 'unused'
+    STATUS_UNKNOWN = 'unknown'
+
+
+class Node(object):
 
     def __init__(self,
                  id,
                  ip,
                  name,
                  status,
-                 roles,
-                 ssh_client,
-                 info={}):
+                 roles=None,
+                 ssh_client=None,
+                 info=None):
         self.id = id
         self.ip = ip
         self.name = name
@@ -117,11 +129,21 @@ class Node(object):
         self.roles = roles
         self.info = info
 
+        self.cpu_info = 'unknown'
+        self.memory = 'unknown'
+        self.ovs = 'unknown'
+
+        if ssh_client and Role.INSTALLER not in self.roles:
+            sys_info = self.get_system_info()
+            self.cpu_info = sys_info['cpu_info']
+            self.memory = sys_info['memory']
+            self.ovs = self.get_ovs_info()
+
     def get_file(self, src, dest):
         '''
         SCP file from a node
         '''
-        if self.status is not Node.STATUS_OK:
+        if self.status is not NodeStatus.STATUS_OK:
             logger.info("The node %s is not active" % self.ip)
             return 1
         logger.info("Fetching %s from %s" % (src, self.ip))
@@ -137,7 +159,7 @@ class Node(object):
         '''
         SCP file to a node
         '''
-        if self.status is not Node.STATUS_OK:
+        if self.status is not NodeStatus.STATUS_OK:
             logger.info("The node %s is not active" % self.ip)
             return 1
         logger.info("Copying %s to %s" % (src, self.ip))
@@ -153,14 +175,16 @@ class Node(object):
         '''
         Run command remotely on a node
         '''
-        if self.status is not Node.STATUS_OK:
-            logger.info("The node %s is not active" % self.ip)
-            return 1
+        if self.status is not NodeStatus.STATUS_OK:
+            logger.error(
+                "Error running command %s. The node %s is not active"
+                % (cmd, self.ip))
+            return None
         _, stdout, stderr = (self.ssh_client.exec_command(cmd))
         error = stderr.readlines()
         if len(error) > 0:
             logger.error("error %s" % ''.join(error))
-            return error
+            return None
         output = ''.join(stdout.readlines()).rstrip()
         return output
 
@@ -174,33 +198,97 @@ class Node(object):
             'name': self.name,
             'status': self.status,
             'roles': self.roles,
+            'cpu_info': self.cpu_info,
+            'memory': self.memory,
+            'ovs': self.ovs,
             'info': self.info
         }
 
-    def get_attribute(self, attribute):
+    def is_active(self):
         '''
-        Returns an attribute given the name
+        Returns if the node is active
         '''
-        return self.get_dict()[attribute]
+        if self.status == NodeStatus.STATUS_OK:
+            return True
+        return False
 
     def is_controller(self):
         '''
         Returns if the node is a controller
         '''
-        if 'controller' in self.get_attribute('roles'):
-            return True
-        return False
+        return Role.CONTROLLER in self.roles
 
     def is_compute(self):
         '''
         Returns if the node is a compute
         '''
-        if 'compute' in self.get_attribute('roles'):
-            return True
-        return False
+        return Role.COMPUTE in self.roles
+
+    def is_odl(self):
+        '''
+        Returns if the node is an opendaylight
+        '''
+        return Role.ODL in self.roles
+
+    def is_onos(self):
+        '''
+        Returns if the node is an ONOS
+        '''
+        return Role.ONOS in self.roles
+
+    def get_ovs_info(self):
+        '''
+        Returns the ovs version installed
+        '''
+        if self.is_active():
+            cmd = "ovs-vsctl --version 2>/dev/null|head -1| sed 's/^.*) //'"
+            return self.run_cmd(cmd) or None
+        return None
+
+    def get_system_info(self):
+        '''
+        Returns system information
+        '''
+        cmd = 'grep MemTotal /proc/meminfo'
+        memory = self.run_cmd(cmd).partition('MemTotal:')[-1].strip().encode()
+
+        cpu_info = {}
+        cmd = 'lscpu'
+        result = self.run_cmd(cmd)
+        for line in result.splitlines():
+            if line.startswith('CPU(s)'):
+                cpu_info['num_cpus'] = line.split(' ')[-1].encode()
+            elif line.startswith('Thread(s) per core'):
+                cpu_info['threads/core'] = line.split(' ')[-1].encode()
+            elif line.startswith('Core(s) per socket'):
+                cpu_info['cores/socket'] = line.split(' ')[-1].encode()
+            elif line.startswith('Model name'):
+                cpu_info['model'] = line.partition(
+                    'Model name:')[-1].strip().encode()
+            elif line.startswith('Architecture'):
+                cpu_info['arch'] = line.split(' ')[-1].encode()
+
+        return {'memory': memory, 'cpu_info': cpu_info}
 
     def __str__(self):
-        return str(self.get_dict())
+        return '''
+            name:    {name}
+            id:      {id}
+            ip:      {ip}
+            status:  {status}
+            roles:   {roles}
+            cpu:     {cpu_info}
+            memory:  {memory}
+            ovs:     {ovs}
+            info:    {info}'''.format(name=self.name,
+                                      id=self.id,
+                                      ip=self.ip,
+                                      status=self.status,
+                                      roles=self.roles,
+                                      cpu_info=self.cpu_info,
+                                      memory=self.memory,
+                                      ovs=self.ovs,
+                                      info=self.info)
 
 
 class DeploymentHandler(object):
@@ -236,14 +324,14 @@ class DeploymentHandler(object):
             self.installer_node = Node(id='',
                                        ip=installer_ip,
                                        name=installer,
-                                       status='active',
+                                       status=NodeStatus.STATUS_OK,
                                        ssh_client=self.installer_connection,
-                                       roles='installer node')
+                                       roles=Role.INSTALLER)
         else:
             raise Exception(
                 'Cannot establish connection to the installer node!')
 
-        self.nodes = self.nodes()
+        self.nodes = self.get_nodes()
 
     @abstractmethod
     def get_openstack_version(self):
@@ -267,24 +355,30 @@ class DeploymentHandler(object):
         raise Exception(DeploymentHandler.FUNCTION_NOT_IMPLEMENTED)
 
     @abstractmethod
-    def nodes(self, options=None):
+    def get_nodes(self, options=None):
         '''
             Generates a list of all the nodes in the deployment
         '''
         raise Exception(DeploymentHandler.FUNCTION_NOT_IMPLEMENTED)
 
-    def get_nodes(self, options=None):
-        '''
-            Returns the list of Node objects
-        '''
-        return self.nodes
-
     def get_installer_node(self):
         '''
             Returns the installer node object
         '''
         return self.installer_node
 
+    def get_arch(self):
+        '''
+            Returns the architecture of the first compute node found
+        '''
+        arch = None
+        for node in self.nodes:
+            if node.is_compute():
+                arch = node.cpu_info.get('arch', None)
+                if arch:
+                    break
+        return arch
+
     def get_deployment_info(self):
         '''
             Returns an object of type Deployment