utils.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. # Copyright 2018 Cloudbase Solutions Srl
  2. # All Rights Reserved.
  3. import functools
  4. import json
  5. from oslo_log import log as logging
  6. from webob import exc
  7. from coriolis import constants
  8. from coriolis import exception
  9. from coriolis import schemas
  10. LOG = logging.getLogger(__name__)
  11. def _get_show_deleted(val):
  12. if val is None:
  13. return val
  14. try:
  15. show_deleted = json.loads(val)
  16. if type(show_deleted) is bool:
  17. return show_deleted
  18. except Exception as err:
  19. LOG.warn(
  20. "failed to parse show_deleted: %s" % err)
  21. pass
  22. return None
  23. def validate_network_map(network_map):
  24. """ Validates the JSON schema for the network_map. """
  25. try:
  26. schemas.validate_value(
  27. network_map, schemas.CORIOLIS_NETWORK_MAP_SCHEMA)
  28. except exception.SchemaValidationException as ex:
  29. raise exc.HTTPBadRequest(
  30. explanation="Invalid network_map: %s" % str(ex))
  31. def validate_storage_mappings(storage_mappings):
  32. """ Validates the JSON schema for the storage_mappings. """
  33. try:
  34. schemas.validate_value(
  35. storage_mappings, schemas.CORIOLIS_STORAGE_MAPPINGS_SCHEMA)
  36. except exception.SchemaValidationException as ex:
  37. raise exc.HTTPBadRequest(
  38. explanation="Invalid storage_mappings: %s" % str(ex))
  39. def format_keyerror_message(resource='', method=''):
  40. def _format_keyerror_message(func):
  41. @functools.wraps(func)
  42. def _wrapper(*args, **kwargs):
  43. try:
  44. return func(*args, **kwargs)
  45. except KeyError as err:
  46. LOG.exception(err)
  47. if err.args:
  48. key = err.args[0]
  49. exc_message = _build_keyerror_message(
  50. resource, method, key)
  51. else:
  52. exc_message = str(err)
  53. raise exception.InvalidInput(exc_message)
  54. except Exception as err:
  55. LOG.exception(err)
  56. msg = getattr(err, "msg", str(err))
  57. raise exception.InvalidInput(reason=msg)
  58. return _wrapper
  59. return _format_keyerror_message
  60. def _build_keyerror_message(resource, method, key):
  61. msg = ''
  62. method_mapping = {
  63. "create": "creation",
  64. "update": "update", }
  65. if resource == key:
  66. msg = 'The %s %s body needs to be encased inside the "%s" key' % (
  67. resource, method_mapping[method], key)
  68. else:
  69. msg = 'The %s %s body lacks a required attribute: "%s"' % (
  70. resource, method_mapping[method], key)
  71. return msg
  72. def validate_user_scripts(user_scripts):
  73. if user_scripts is None:
  74. user_scripts = {}
  75. if not isinstance(user_scripts, dict):
  76. raise exception.InvalidInput(
  77. reason='"user_scripts" must be of JSON object format')
  78. global_scripts = user_scripts.get('global', {})
  79. if not isinstance(global_scripts, dict):
  80. raise exception.InvalidInput(
  81. reason='"global" must be a mapping between the identifiers of the '
  82. 'supported OS types and their respective scripts.')
  83. for os_type in global_scripts.keys():
  84. if os_type not in constants.VALID_OS_TYPES:
  85. raise exception.InvalidInput(
  86. reason='The provided global user script os_type "%s" is '
  87. 'invalid. Must be one of the '
  88. 'following: %s' % (os_type, constants.VALID_OS_TYPES))
  89. instance_scripts = user_scripts.get('instances', {})
  90. if not isinstance(instance_scripts, dict):
  91. raise exception.InvalidInput(
  92. reason='"instances" must be a mapping between the identifiers of '
  93. 'the instances in the Replica/Migration and their '
  94. 'respective scripts.')
  95. return user_scripts
  96. def normalize_user_scripts(user_scripts, instances):
  97. """ Removes instance user_scripts if said instance is not one of the
  98. selected instances for the replica/migration """
  99. for instance in user_scripts.get('instances', {}).keys():
  100. if instance not in instances:
  101. LOG.warn("Removing provided instance '%s' from user_scripts body "
  102. "because it's not included in one of the selected "
  103. "instances for this replica/migration: %s",
  104. instance, instances)
  105. user_scripts.pop(instance, None)
  106. return user_scripts
  107. def validate_instances_list_for_transfer(instances):
  108. if not instances:
  109. raise exception.InvalidInput(
  110. "No instance identifiers provided for transfer action.")
  111. if not isinstance(instances, list):
  112. raise exception.InvalidInput(
  113. "Instances must be a list. Got type %s: %s" % (
  114. type(instances), instances))
  115. appearances = {}
  116. for instance in instances:
  117. if instance in appearances:
  118. appearances[instance] = appearances[instance] + 1
  119. else:
  120. appearances[instance] = 1
  121. duplicates = {
  122. inst: count for (inst, count) in appearances.items() if count > 1}
  123. if duplicates:
  124. raise exception.InvalidInput(
  125. "Transfer action instances (%s) list contained duplicates: %s " % (
  126. instances, duplicates))
  127. return instances