bug(descriptor): missing fields in stored descriptors. 1408, 1388
[osm/NBI.git] / osm_nbi / base_topic.py
index 5492a8f..f597d17 100644 (file)
@@ -65,6 +65,26 @@ def versiontuple(v):
     return tuple(filled)
 
 
+def increment_ip_mac(ip_mac, vm_index=1):
+    if not isinstance(ip_mac, str):
+        return ip_mac
+    try:
+        # try with ipv4 look for last dot
+        i = ip_mac.rfind(".")
+        if i > 0:
+            i += 1
+            return "{}{}".format(ip_mac[:i], int(ip_mac[i:]) + vm_index)
+        # try with ipv6 or mac look for last colon. Operate in hex
+        i = ip_mac.rfind(":")
+        if i > 0:
+            i += 1
+            # format in hex, len can be 2 for mac or 4 for ipv6
+            return ("{}{:0" + str(len(ip_mac) - i) + "x}").format(ip_mac[:i], int(ip_mac[i:], 16) + vm_index)
+    except Exception:
+        pass
+    return None
+
+
 class BaseTopic:
     # static variables for all instance classes
     topic = None        # to_override
@@ -127,7 +147,7 @@ class BaseTopic:
             if count >= quota:
                 name = proj["name"]
                 raise ValidationError("quota ({}={}) exceeded for project {} ({})".format(quota_name, quota, name, pid),
-                                      http_code=HTTPStatus.UNAUTHORIZED)
+                                      http_code=HTTPStatus.UNPROCESSABLE_ENTITY)
 
     def _validate_input_new(self, input, force=False):
         """
@@ -211,10 +231,10 @@ class BaseTopic:
         :param final_content: data once modified. This method may change it.
         :param edit_content: incremental data that contains the modifications to apply
         :param _id: internal _id
-        :return: None or raises EngineException
+        :return: final_content or raises EngineException
         """
         if not self.multiproject:
-            return
+            return final_content
         # Change public status
         if session["public"] is not None:
             if session["public"] and "ANY" not in final_content["_admin"]["projects_read"]:
@@ -229,6 +249,8 @@ class BaseTopic:
                 if p not in final_content["_admin"]["projects_read"]:
                     final_content["_admin"]["projects_read"].append(p)
 
+        return final_content
+
     def check_unique_name(self, session, name, _id=None):
         """
         Check that the name is unique for this project
@@ -288,6 +310,7 @@ class BaseTopic:
 
     def _send_msg(self, action, content, not_send_msg=None):
         if self.topic_msg and not_send_msg is not False:
+            content = content.copy()
             content.pop("_admin", None)
             if isinstance(not_send_msg, list):
                 not_send_msg.append((self.topic_msg, action, content))
@@ -557,19 +580,16 @@ class BaseTopic:
             if indata and session.get("set_project"):
                 raise EngineException("Cannot edit content and set to project (query string SET_PROJECT) at same time",
                                       HTTPStatus.UNPROCESSABLE_ENTITY)
-            
             # TODO self._check_edition(session, indata, _id, force)
             if not content:
                 content = self.show(session, _id)
-            
             indata = self._validate_input_edit(indata, content, force=session["force"])
-            
             deep_update_rfc7396(content, indata)
 
             # To allow project addressing by name AS WELL AS _id. Get the _id, just in case the provided one is a name
             _id = content.get("_id") or _id
 
-            self.check_conflict_on_edit(session, content, indata, _id=_id)
+            content = self.check_conflict_on_edit(session, content, indata, _id=_id)
             op_id = self.format_on_edit(content, indata)
 
             self.db.replace(self.topic, _id, content)