Ver Fonte

Improve input validation for Replica update API.

Nashwan Azhari há 7 anos atrás
pai
commit
72a1ba2c99
1 ficheiros alterados com 38 adições e 29 exclusões
  1. 38 29
      coriolis/api/v1/replicas.py

+ 38 - 29
coriolis/api/v1/replicas.py

@@ -156,20 +156,38 @@ class ReplicaController(api_wsgi.Controller):
         return storage_mappings
 
     def _get_merged_replica_values(self, replica, updated_values):
+        """ Looks for the following keys in the original replica body and
+        updated values (preferring the updated values where needed, but using
+        `.update()` on dicts):
+        "source_environment", "destination_environment", "network_map", "notes"
+        Does special merging for the "storage_mappings"
+        Returns a dict with the merged values (or at least all if the keys
+        having a default value of {})
+        """
         final_values = {}
         # NOTE: this just replaces options at the top-level and does not do
         # merging of container types (ex: lists, dicts)
         for option in [
                 "source_environment", "destination_environment",
                 "network_map"]:
-            original_values = replica.get(option, {})
-
-            original_values.update(updated_values.get(
-                option, {}))
-            final_values[option] = original_values
-
-        original_storage_mappings = replica.get('storage_mappings', {})
-        new_storage_mappings = updated_values.get('storage_mappings', {})
+            before = replica.get(option)
+            after = updated_values.get(option)
+            # NOTE: for Replicas created before the separation of these fields
+            # in the DB there is the chance that some of these may be NULL:
+            if before is None:
+                before = {}
+            if after is None:
+                after = {}
+            before.update(after)
+
+            final_values[option] = before
+
+        original_storage_mappings = replica.get('storage_mappings')
+        if original_storage_mappings is None:
+            original_storage_mappings = {}
+        new_storage_mappings = updated_values.get('storage_mappings')
+        if new_storage_mappings is None:
+            new_storage_mappings = {}
         final_values['storage_mappings'] = self._update_storage_mappings(
             original_storage_mappings, new_storage_mappings)
 
@@ -178,20 +196,16 @@ class ReplicaController(api_wsgi.Controller):
         else:
             final_values['notes'] = replica.get('notes', '')
 
-        # until the provider plugin interface is updated
+        # NOTE: until the provider plugin interface is updated
         # to have separate 'network_map' and 'storage_mappings' fields,
         # we add them as part of the destination environment:
         final_storage_mappings = final_values['storage_mappings']
         final_network_map = final_values['network_map']
-        if not final_values.get('destination_environment'):
-            final_values['destination_environment'] = {}
         if final_storage_mappings:
-            final_values[
-                'destination_environment'][
+            final_values['destination_environment'][
                 'storage_mappings'] = final_storage_mappings
         if final_network_map:
-            final_values[
-                'destination_environment'][
+            final_values['destination_environment'][
                 'network_map'] = final_network_map
 
         return final_values
@@ -206,30 +220,25 @@ class ReplicaController(api_wsgi.Controller):
             origin_endpoint_id = replica["origin_endpoint_id"]
             destination_endpoint_id = replica["destination_endpoint_id"]
 
-            source_environment = merged_body.get("source_environment", {})
             self._endpoints_api.validate_source_environment(
-                context, origin_endpoint_id, source_environment)
-
-            network_map = merged_body.get("network_map", {})
-            api_utils.validate_network_map(network_map)
+                context, origin_endpoint_id,
+                merged_body["source_environment"])
 
-            destination_environment = merged_body.get(
-                "destination_environment", {})
+            destination_environment = merged_body["destination_environment"]
             self._endpoints_api.validate_target_environment(
                 context, destination_endpoint_id, destination_environment)
 
-            storage_mappings = merged_body.get("storage_mappings", {})
-            api_utils.validate_storage_mappings(storage_mappings)
+            api_utils.validate_network_map(merged_body["network_map"])
+
+            api_utils.validate_storage_mappings(
+                merged_body["storage_mappings"])
 
             return merged_body
 
         except Exception as ex:
             LOG.exception(ex)
-            if hasattr(ex, "message"):
-                msg = ex.message
-            else:
-                msg = str(ex)
-            raise exception.InvalidInput(msg)
+            raise exception.InvalidInput(
+                getattr(ex, "message", str(ex)))
 
     def update(self, req, id, body):
         context = req.environ["coriolis.context"]