Multiple fixes for maas machine processing

- Strict object type check before skipping the node in case if it
  is already in deployed state
- Implementing skipped list for machine processing
- Check for duplicate mac address from the maas nodes list
- Check if machine in machines list before assigning an ip
- Check if machine in machines list before deploying it

Prod-Related: PROD-35006
Change-Id: Ic7675563bac4205305d682bf8ee151305b73fb8a
diff --git a/_modules/maas.py b/_modules/maas.py
index 368507c..0152eba 100644
--- a/_modules/maas.py
+++ b/_modules/maas.py
@@ -100,10 +100,8 @@
                                 None, **data).read()
 
     def process(self, objects_name=None):
-        # FIXME: probably, should be extended with "skipped" return.
-        # For example, currently "DEPLOYED" nodes are skipped, and no changes
-        # applied - but they fall into 'updated' list.
         ret = {
+            'skipped': [],
             'success': [],
             'errors': {},
             'updated': [],
@@ -140,10 +138,11 @@
 
             def process_single(name, config_data):
                 self._update = False
+                err_msgs = []
                 try:
                     data = self.fill_data(name, config_data, **extra)
                     if data is None:
-                        ret['updated'].append(name)
+                        ret['skipped'].append(name)
                         return
                     if name in all_elements:
                         self._update = True
@@ -151,11 +150,24 @@
                         self.send(data)
                         ret['updated'].append(name)
                     else:
-                        self.send(data)
-                        ret['success'].append(name)
+                        # Check for duplicate mac_addresses
+                        skip_send = False
+                        for _obj_name, _obj_val in all_elements.iteritems():
+                            if isinstance(_obj_val, dict) and 'boot_interface' in _obj_val:
+                                if isinstance(data, dict) and isinstance(data['mac_addresses'], (unicode, str)):
+                                    for mac_addr in data['mac_addresses'].split(','):
+                                        if mac_addr == _obj_val['boot_interface']['mac_address']:
+                                             err_msg = 'Error: %s uses same mac [%s] as node %s in maas' % (data['hostname'], mac_addr, _obj_val['fqdn'])
+                                             err_msgs.append(err_msg)
+                                             LOG.error(err_msg)
+                                             skip_send = True
+                        # Decision
+                        if skip_send:
+                            ret['errors'][name] = ','.join(err_msgs)
+                        else:
+                            self.send(data)
+                            ret['success'].append(name)
                 except urllib2.HTTPError as e:
-                    # FIXME add exception's for response:
-                    # '{"mode": ["Interface is already set to DHCP."]}
                     etxt = e.read()
                     LOG.error('Failed for object %s reason %s', name, etxt)
                     ret['errors'][name] = str(etxt)
@@ -172,8 +184,9 @@
                     process_single(object_name, config[object_name])
             else:
                 for name, config_data in config.iteritems():
-                    if isinstance(config_data, dict) and 'status_name' in all_elements[name] and all_elements[name]['status_name'] == 'Deployed':
+                    if isinstance(config_data, dict) and isinstance(all_elements, dict) and name in all_elements and 'status_name' in all_elements[name] and all_elements[name]['status_name'] == 'Deployed':
                         LOG.info('Machine %s already deployed, skipping it.' % name)
+                        ret['skipped'].append(name)
                     else:
                         process_single(name, config_data)
 
@@ -625,7 +638,12 @@
             raise Exception(str(e))
 
     def fill_data(self, name, data, machines):
-        machine = machines[name]
+        if name in machines:
+            machine = machines[name]
+        else:
+            LOG.debug("Skipping node:{} "
+                      "since it is not in maas yet".format(name))
+            return
         if machine['status'] == self.DEPLOYED:
             LOG.debug("Skipping node:{} "
                       "since it in status:DEPLOYED".format(name))
@@ -671,7 +689,12 @@
                                               None, 'hostname')}
 
     def fill_data(self, name, machine_data, machines):
-        machine = machines[name]
+        if name in machines:
+            machine = machines[name]
+        else:
+            LOG.debug("Skipping node:{} "
+                      "since it is not in maas yet".format(name))
+            return
         if machine['status'] == self.DEPLOYED:
             return
         if machine['status'] != self.READY: