Просмотр исходного кода

Add user_scripts body validation

Daniel Vincze 5 лет назад
Родитель
Сommit
6e9ed1e2b2
3 измененных файлов с 55 добавлено и 6 удалено
  1. 4 2
      coriolis/api/v1/migrations.py
  2. 9 2
      coriolis/api/v1/replicas.py
  3. 42 2
      coriolis/api/v1/utils.py

+ 4 - 2
coriolis/api/v1/migrations.py

@@ -104,11 +104,13 @@ class MigrationController(api_wsgi.Controller):
                 shutdown_instances, network_map, storage_mappings)
 
     def create(self, req, body):
-        # TODO(alexpilotti): validate body
         migration_body = body.get("migration", {})
         context = req.environ['coriolis.context']
         context.can(migration_policies.get_migrations_policy_label("create"))
-        user_scripts = migration_body.get("user_scripts", {})
+        user_scripts = migration_body.get('user_scripts', {})
+        api_utils.validate_user_scripts(user_scripts)
+        user_scripts = api_utils.normalize_user_scripts(
+            user_scripts, migration_body.get("instances", []))
         replica_id = migration_body.get("replica_id")
         if replica_id:
             clone_disks = migration_body.get("clone_disks", True)

+ 9 - 2
coriolis/api/v1/replicas.py

@@ -77,7 +77,11 @@ class ReplicaController(api_wsgi.Controller):
             'destination_minion_pool_id')
         instance_osmorphing_minion_pool_mappings = replica.get(
             'instance_osmorphing_minion_pool_mappings', {})
-        user_scripts = replica.get("user_scripts", {})
+
+        user_scripts = replica.get('user_scripts', {})
+        api_utils.validate_user_scripts(user_scripts)
+        user_scripts = api_utils.normalize_user_scripts(
+            user_scripts, instances)
 
         # NOTE(aznashwan): we validate the destination environment for the
         # import provider before appending the 'storage_mappings' parameter
@@ -300,7 +304,10 @@ class ReplicaController(api_wsgi.Controller):
         api_utils.validate_storage_mappings(
             merged_body["storage_mappings"])
 
-        api_utils.validate_user_scripts(merged_body["user_scripts"])
+        user_scripts = merged_body['user_scripts']
+        api_utils.validate_user_scripts(user_scripts)
+        merged_body['user_scripts'] = api_utils.normalize_user_scripts(
+            user_scripts, replica.get('instances', []))
 
         return merged_body
 

+ 42 - 2
coriolis/api/v1/utils.py

@@ -7,6 +7,7 @@ import json
 from oslo_log import log as logging
 from webob import exc
 
+from coriolis import constants
 from coriolis import exception
 from coriolis import schemas
 
@@ -65,8 +66,8 @@ def format_keyerror_message(resource='', method=''):
                 raise exception.InvalidInput(exc_message)
             except Exception as err:
                 LOG.exception(err)
-                msg = getattr(err, "message", str(err))
-                raise exception.InvalidInput(msg)
+                msg = getattr(err, "msg", str(err))
+                raise exception.InvalidInput(reason=msg)
         return _wrapper
     return _format_keyerror_message
 
@@ -85,3 +86,42 @@ def _build_keyerror_message(resource, method, key):
             resource, method_mapping[method], key)
 
     return msg
+
+
+def validate_user_scripts(user_scripts):
+    if not isinstance(user_scripts, dict):
+        raise exception.InvalidInput(
+            reason='"user_scripts" must be of JSON object format')
+
+    global_scripts = user_scripts.get('global', {})
+    if not isinstance(global_scripts, dict):
+        raise exception.InvalidInput(
+            reason='"global" must be a mapping between the identifiers of the '
+                   'supported OS types and their respective scripts.')
+    for os_type in global_scripts.keys():
+        if os_type not in constants.VALID_OS_TYPES:
+            raise exception.InvalidInput(
+                reason='The provided global user script os_type "%s" is '
+                       'invalid. Must be one of the '
+                       'following: %s' % (os_type, constants.VALID_OS_TYPES))
+
+    instance_scripts = user_scripts.get('instances', {})
+    if not isinstance(instance_scripts, dict):
+        raise exception.InvalidInput(
+            reason='"instances" must be a mapping between the identifiers of '
+                   'the instances in the Replica/Migration and their '
+                   'respective scripts.')
+
+
+def normalize_user_scripts(user_scripts, instances):
+    """ Removes instance user_scripts if said instance is not one of the
+        selected instances for the replica/migration """
+    for instance in user_scripts.get('instances', {}).keys():
+        if instance not in instances:
+            LOG.warn("Removing provided instance '%s' from user_scripts body "
+                     "because it's not included in one of the selected "
+                     "instances for this replica/migration: %s",
+                     instance, instances)
+            user_scripts.pop(instance, None)
+
+    return user_scripts