Beispiel #1
0
def _create(storage_ceph_ext):
    storage_ceph_ext = _set_defaults_ceph_external(storage_ceph_ext)

    # Execute the common semantic checks for all backends, if a specific backend
    # is not specified this will not return
    api_helper.common_checks(constants.SB_API_OP_CREATE, storage_ceph_ext)

    _check_backend_ceph_external(storage_ceph_ext)

    _check_and_update_services(storage_ceph_ext)

    # Conditionally update the DB based on any previous create attempts. This
    # creates the StorageCeph object.
    system = pecan.request.dbapi.isystem_get_one()
    storage_ceph_ext['forisystemid'] = system.id
    storage_ceph_ext_obj = pecan.request.dbapi.storage_ceph_external_create(
        storage_ceph_ext)

    # Retrieve the main StorageBackend object.
    storage_backend_obj = pecan.request.dbapi.storage_backend_get(
        storage_ceph_ext_obj.id)

    _apply_ceph_external_backend_changes(constants.SB_API_OP_CREATE,
                                         sb_obj=storage_ceph_ext)

    return storage_backend_obj
Beispiel #2
0
def _delete(sb_uuid):
    # For now delete operation only deletes DB entry

    storage_external_obj = pecan.request.dbapi.storage_external_get(sb_uuid)

    # LOG.error("delete %s" % storage_external_obj.as_dict())

    # Execute the common semantic checks for all backends, if backend is not
    # present this will not return
    api_helper.common_checks(constants.SB_API_OP_DELETE,
                             storage_external_obj.as_dict())

    # Run the backend specific semantic checks
    _check_backend_external(constants.SB_API_OP_DELETE,
                        storage_external_obj.as_dict(),
                        True)

    # Enable the backend changes:
    _apply_backend_changes(constants.SB_API_OP_DELETE, storage_external_obj)

    try:
        pecan.request.dbapi.storage_backend_destroy(storage_external_obj.id)
    except exception.HTTPNotFound:
        msg = _("Deletion of backend %s failed" % storage_external_obj.uuid)
        raise wsme.exc.ClientSideError(msg)
Beispiel #3
0
def _create(storage_lvm):
    # Set the default for the storage backend
    storage_lvm = _set_default_values(storage_lvm)

    # Execute the common semantic checks for all backends, if a specific backend
    # is not specified this will not return
    api_helper.common_checks(constants.SB_API_OP_CREATE, storage_lvm)

    # Run the backend specific semantic checks to validate that we have all the
    # required parameters for manifest application
    _check_backend_lvm(constants.SB_API_OP_CREATE, storage_lvm,
                       storage_lvm.pop('confirmed', False))

    StorageBackendConfig.set_img_conversions_defaults(pecan.request.dbapi,
                                                      controller_fs_api)

    # We have a valid configuration. create it.
    system = pecan.request.dbapi.isystem_get_one()
    storage_lvm['forisystemid'] = system.id
    storage_lvm_obj = pecan.request.dbapi.storage_lvm_create(storage_lvm)

    # Retreive the main StorageBackend object.
    storage_backend_obj = pecan.request.dbapi.storage_backend_get(
        storage_lvm_obj.id)

    # Enable the backend:
    _apply_backend_changes(constants.SB_API_OP_CREATE, storage_backend_obj)

    return storage_backend_obj
Beispiel #4
0
def _check_and_update_services(storage_ceph_ext):
    svcs = api_helper.getListFromServices(storage_ceph_ext)

    # If glance/nova is already a service on other rbd backend, remove it from there
    check_svcs = [constants.SB_SVC_GLANCE, constants.SB_SVC_NOVA]
    for s in check_svcs:
        if s in svcs:
            sb_list = pecan.request.dbapi.storage_backend_get_list()

            if sb_list:
                for sb in sb_list:
                    if (sb.uuid != storage_ceph_ext.get("uuid", None)
                            and sb.backend in [
                                constants.SB_TYPE_CEPH,
                                constants.SB_TYPE_CEPH_EXTERNAL
                            ] and s in sb.get('services')):
                        services = api_helper.getListFromServices(sb)
                        services.remove(s)
                        cap = sb.capabilities
                        for k in HIERA_DATA[s]:
                            cap.pop(k, None)
                        values = {
                            'services': ','.join(services),
                            'capabilities': cap,
                        }
                        pecan.request.dbapi.storage_backend_update(
                            sb.uuid, values)
Beispiel #5
0
def _create(storage_file):
    # Set the default for the storage backend
    storage_file = _set_default_values(storage_file)

    # Execute the common semantic checks for all backends, if a backend is
    # not present this will not return
    api_helper.common_checks(constants.SB_API_OP_CREATE, storage_file)

    # Run the backend specific semantic checks
    _check_backend_file(constants.SB_API_OP_CREATE, storage_file,
                        storage_file.pop('confirmed', False))

    # We have a valid configuration. create it.
    system = pecan.request.dbapi.isystem_get_one()
    storage_file['forisystemid'] = system.id
    storage_file_obj = pecan.request.dbapi.storage_file_create(storage_file)

    # Retreive the main StorageBackend object.
    storage_backend_obj = pecan.request.dbapi.storage_backend_get(
        storage_file_obj.id)

    # Enable the backend:
    _apply_backend_changes(constants.SB_API_OP_CREATE, storage_backend_obj)

    return storage_file_obj
Beispiel #6
0
def _create(storage_ceph_rook):
    # Set the default for the storage backend
    storage_ceph_rook = _set_default_values(storage_ceph_rook)

    # Execute the common semantic checks for all backends, if a backend is
    # not present this will not return
    api_helper.common_checks(constants.SB_API_OP_CREATE, storage_ceph_rook)

    # Run the backend specific semantic checks
    _check_backend_ceph_rook(constants.SB_API_OP_CREATE, storage_ceph_rook,
                             storage_ceph_rook.pop('confirmed', False))

    # We have a valid configuration. create it.
    system = pecan.request.dbapi.isystem_get_one()
    storage_ceph_rook['forisystemid'] = system.id
    storage_ceph_rook_obj = pecan.request.dbapi.storage_ceph_rook_create(
        storage_ceph_rook)

    # Retreive the main StorageBackend object.
    storage_backend_obj = pecan.request.dbapi.storage_backend_get(
        storage_ceph_rook_obj.id)

    # Only apply runtime manifests if at least one controller is unlocked and
    # available/degraded.
    controller_hosts = pecan.request.dbapi.ihost_get_by_personality(
        constants.CONTROLLER)
    valid_controller_hosts = [
        h for h in controller_hosts if
        h['administrative'] == constants.ADMIN_UNLOCKED and h['availability']
        in [constants.AVAILABILITY_AVAILABLE, constants.AVAILABILITY_DEGRADED]
    ]
    if valid_controller_hosts:
        _apply_backend_changes(constants.SB_API_OP_CREATE, storage_backend_obj)

    return storage_ceph_rook_obj
Beispiel #7
0
    def post(self, storage_backend):
        """Create a new storage backend."""
        try:
            storage_backend = storage_backend.as_dict()
            api_helper.validate_backend(storage_backend)
            new_storage_backend = _create(storage_backend)

        except exception.SysinvException as e:
            LOG.exception(e)
            raise wsme.exc.ClientSideError(
                _("Invalid data: failed to create "
                  "a storage backend record."))

        return StorageBackend.convert_with_links(new_storage_backend)
Beispiel #8
0
def _get_options_string(storage_lvm):
    opt_str = ""
    caps = storage_lvm.get('capabilities', {})
    services = api_helper.getListFromServices(storage_lvm)

    # get the backend parameters
    backend_dict = caps.get("backend", {})
    be_str = ""
    for key in backend_dict:
        be_str += "\t%s: %s\n" % (key, backend_dict[key])

    # Only show the backend values if any are present
    if len(be_str) > 0:
        opt_str = "Backend:\n%s" % be_str

    # Get any supported service parameters
    for svc in constants.SB_LVM_SVCS_SUPPORTED:
        svc_dict = caps.get(svc, None)
        if svc_dict and svc in services:
            svc_str = ""
            for key in svc_dict:
                svc_str += "\t%s: %s\n" % (key, svc_dict.get(key, None))

            if len(svc_str) > 0:
                opt_str += "%s:\n%s" % (svc.title(), svc_str)

    if len(opt_str) > 0:
        opt_str = "Applying the following options:\n\n" + opt_str
    return opt_str
Beispiel #9
0
def _apply_backend_changes(op, sb_obj):
    if op == constants.SB_API_OP_CREATE:
        services = api_helper.getListFromServices(sb_obj.as_dict())
        if constants.SB_SVC_CINDER in services:

            # Services are specified: Update backend + service actions
            api_helper.enable_backend(
                sb_obj, pecan.request.rpcapi.update_lvm_cinder_config)

    elif op == constants.SB_API_OP_MODIFY:
        if sb_obj.state == constants.SB_STATE_CONFIG_ERR:
            api_helper.enable_backend(
                sb_obj, pecan.request.rpcapi.update_lvm_cinder_config)

    elif op == constants.SB_API_OP_DELETE:
        pass
Beispiel #10
0
def _check_backend_lvm(req, storage_lvm, confirmed=False):
    # check for the backend parameters
    capabilities = storage_lvm.get('capabilities', {})

    # Discover the latest hiera_data for the supported service
    _discover_and_validate_backend_hiera_data(capabilities)

    for k in HIERA_DATA['backend']:
        if not capabilities.get(k, None):
            raise wsme.exc.ClientSideError("Missing required backend "
                                           "parameter: %s" % k)

    # go through the service list and validate
    req_services = api_helper.getListFromServices(storage_lvm)

    # Cinder is mandatory for lvm backend
    if constants.SB_SVC_CINDER not in req_services:
        raise wsme.exc.ClientSideError(
            "Service %s is mandatory for "
            "the %s backend." %
            (constants.SB_SVC_CINDER, constants.SB_TYPE_LVM))

    for svc in req_services:
        if svc not in constants.SB_LVM_SVCS_SUPPORTED:
            raise wsme.exc.ClientSideError(
                "Service %s is not supported for the"
                " %s backend" % (svc, constants.SB_TYPE_LVM))

        # Service is valid. Discover the latest hiera_data for the supported service
        discover_func = eval('_discover_and_validate_' + svc + '_hiera_data')
        discover_func(capabilities)

        # Service is valid. Check the params
        for k in HIERA_DATA[svc]:
            if not capabilities.get(k, None):
                raise wsme.exc.ClientSideError("Missing required %s service "
                                               "parameter: %s" % (svc, k))
    # Update based on any discovered values
    storage_lvm['capabilities'] = capabilities

    # TODO (rchurch): Put this back in some form for delivery OR move to specific
    # backend checks to limit operations based on the backend
    #
    # if req == constants.SB_API_OP_MODIFY or req == constants.SB_API_OP_DELETE:
    #     raise wsme.exc.ClientSideError("API Operation %s is not supported for "
    #                                    "the %s backend" %
    #                                    (req, constants.SB_TYPE_LVM))

    # Check for confirmation
    if not confirmed:
        _options_str = _get_options_string(storage_lvm)
        raise wsme.exc.ClientSideError(
            _("%s\nWARNING : THIS OPERATION IS NOT REVERSIBLE AND CANNOT BE CANCELLED. \n"
              "\nBy confirming this operation, the LVM backend will be created.\n\n"
              "Please refer to the system admin guide for minimum spec for LVM\n"
              "storage. Set the 'confirmed' field to execute this operation\n"
              "for the %s backend.") % (_options_str, constants.SB_TYPE_LVM))
Beispiel #11
0
def _set_default_values(storage_lvm):
    defaults = {
        'backend': constants.SB_TYPE_LVM,
        'name': constants.SB_DEFAULT_NAMES[constants.SB_TYPE_LVM],
        'state': constants.SB_STATE_CONFIGURING,
        'task': constants.SB_TASK_NONE,
        'services': None,
        'capabilities': {}
    }

    sl = api_helper.set_backend_data(storage_lvm, defaults, HIERA_DATA,
                                     constants.SB_LVM_SVCS_SUPPORTED)
    return sl
def _apply_backend_changes(op, sb_obj):
    if op in [constants.SB_API_OP_CREATE, constants.SB_API_OP_MODIFY]:
        services = api_helper.getListFromServices(sb_obj.as_dict())
        if constants.SB_SVC_CINDER in services:
            # Services are specified: Update backend + service actions
            api_helper.enable_backend(
                sb_obj, pecan.request.rpcapi.update_external_cinder_config)

        else:
            # If no service is specified or glance or swift is the only service
            # this is a DB only change => Set the state to configured
            pecan.request.dbapi.storage_external_update(
                sb_obj.uuid, {'state': constants.SB_STATE_CONFIGURED})

        # update shared_services
        s_s = utils.get_shared_services()
        shared_services = [] if s_s is None else ast.literal_eval(s_s)

        if services is not None:
            for s in services:
                if (s == constants.SB_SVC_CINDER and
                        constants.SERVICE_TYPE_VOLUME not in shared_services):
                    shared_services.append(constants.SERVICE_TYPE_VOLUME)

                if (s == constants.SB_SVC_GLANCE and
                        constants.SERVICE_TYPE_IMAGE not in shared_services):
                    shared_services.append(constants.SERVICE_TYPE_IMAGE)

        system = pecan.request.dbapi.isystem_get_one()

        system.capabilities['shared_services'] = str(shared_services)
        pecan.request.dbapi.isystem_update(
            system.uuid, {'capabilities': system.capabilities})

    elif op == constants.SB_API_OP_DELETE:
        pass
Beispiel #13
0
def _apply_backend_changes(op, sb_obj):
    if op == constants.SB_API_OP_CREATE:
        # This is a DB only change => Set the state to configured
        pecan.request.dbapi.storage_ceph_rook_update(
            sb_obj.uuid, {'state': constants.SB_STATE_CONFIGURED})

        services = api_helper.getListFromServices(sb_obj.as_dict())
        pecan.request.rpcapi.update_ceph_rook_config(pecan.request.context,
                                                     sb_obj.get('uuid'),
                                                     services)

    elif op == constants.SB_API_OP_MODIFY:
        pass

    elif op == constants.SB_API_OP_DELETE:
        pass
Beispiel #14
0
def _set_defaults_ceph_external(storage_ceph_ext):
    defaults = {
        'backend': constants.SB_TYPE_CEPH_EXTERNAL,
        'name': constants.SB_DEFAULT_NAMES[constants.SB_TYPE_CEPH_EXTERNAL].format(0),
        'state': constants.SB_STATE_CONFIGURING,
        'task': None,
        'services': None,
        'ceph_conf': None,
        'capabilities': {},
    }
    sc = api_helper.set_backend_data(storage_ceph_ext,
                                     defaults,
                                     HIERA_DATA,
                                     constants.SB_CEPH_EXTERNAL_SVCS_SUPPORTED)

    return sc
Beispiel #15
0
def _check_backend_file(req, storage_file, confirmed=False):
    # check for the backend parameters
    capabilities = storage_file.get('capabilities', {})

    # Discover the latest hiera_data for the supported service
    _discover_and_validate_backend_hiera_data(capabilities)

    for k in HIERA_DATA['backend']:
        if not capabilities.get(k, None):
            raise wsme.exc.ClientSideError("Missing required backend "
                                           "parameter: %s" % k)

    # go through the service list and validate
    req_services = api_helper.getListFromServices(storage_file)
    for svc in req_services:
        if svc not in constants.SB_FILE_SVCS_SUPPORTED:
            raise wsme.exc.ClientSideError(
                "Service %s is not supported for the"
                " %s backend" % (svc, constants.SB_TYPE_FILE))

        # Service is valid. Discover the latest hiera_data for the supported service
        discover_func = eval('_discover_and_validate_' + svc + '_hiera_data')
        discover_func(capabilities)

        # Service is valid. Check the params
        for k in HIERA_DATA[svc]:
            if not capabilities.get(k, None):
                raise wsme.exc.ClientSideError("Missing required %s service "
                                               "parameter: %s" % (svc, k))

    # Update based on any discovered values
    storage_file['capabilities'] = capabilities

    # TODO (rchurch): Put this back
    # if req == constants.SB_API_OP_MODIFY or req == constants.SB_API_OP_DELETE:
    #     raise wsme.exc.ClientSideError("API Operation %s is not supported for "
    #                                    "the %s backend" %
    #                                    (req, constants.SB_TYPE_FILE))

    # Check for confirmation
    if not confirmed:
        _options_str = _get_options_string(storage_file)
        raise wsme.exc.ClientSideError(
            _("%s\nWARNING : THIS OPERATION IS NOT REVERSIBLE AND CANNOT BE "
              "CANCELLED. \n\nPlease set the 'confirmed' field to execute "
              "this operation for the %s backend.") %
            (_options_str, constants.SB_TYPE_FILE))
def _check_backend_external(req, storage_external, confirmed=False):
    # check if it is running on secondary region
    system = pecan.request.dbapi.isystem_get_one()
    if system and system.capabilities.get('region_config') is not True:
        raise wsme.exc.ClientSideError("External backend can only be added on "
                                       "secondary region.")

    # check for the backend parameters
    capabilities = storage_external.get('capabilities', {})

    # Discover the latest hiera_data for the supported service
    _discover_and_validate_backend_hiera_data(capabilities)

    for k in HIERA_DATA['backend']:
        if not capabilities.get(k, None):
            raise wsme.exc.ClientSideError("Missing required backend "
                                           "parameter: %s" % k)

    # go through the service list and validate
    req_services = api_helper.getListFromServices(storage_external)
    for svc in req_services:
        if svc not in constants.SB_EXTERNAL_SVCS_SUPPORTED:
            raise wsme.exc.ClientSideError(
                "Service %s is not supported for the"
                " %s backend" % (svc, constants.SB_TYPE_EXTERNAL))

        # Service is valid. Discover the latest hiera_data for the supported service
        discover_func = eval('_discover_and_validate_' + svc + '_hiera_data')
        discover_func(capabilities)

        # Service is valid. Check the params
        for k in HIERA_DATA[svc]:
            if not capabilities.get(k, None):
                raise wsme.exc.ClientSideError("Missing required %s service "
                                               "parameter: %s" % (svc, k))

    # Update based on any discovered values
    storage_external['capabilities'] = capabilities

    # Check for confirmation
    if not confirmed:
        _options_str = _get_options_string(storage_external)
        raise wsme.exc.ClientSideError(
            _("%s\nWARNING : THIS OPERATION IS NOT REVERSIBLE AND CANNOT BE "
              "CANCELLED. \n\nPlease set the 'confirmed' field to execute "
              "this operation for the %s backend.") %
            (_options_str, constants.SB_TYPE_EXTERNAL))
Beispiel #17
0
def _check_backend_ceph_rook(req, storage_ceph_rook, confirmed=False):
    # check for the backend parameters
    capabilities = storage_ceph_rook.get('capabilities', {})

    # Discover the latest hiera_data for the supported service
    _discover_and_validate_backend_hiera_data(capabilities)

    for k in HIERA_DATA['backend']:
        if not capabilities.get(k, None):
            raise wsme.exc.ClientSideError("Missing required backend "
                                           "parameter: %s" % k)

    # go through the service list and validate
    req_services = api_helper.getListFromServices(storage_ceph_rook)
    for svc in req_services:
        if svc not in constants.SB_CEPH_ROOK_SVCS_SUPPORTED:
            raise wsme.exc.ClientSideError(
                "Service %s is not supported for the"
                " %s backend" % (svc, constants.SB_TYPE_FILE))

        # Service is valid. Discover the latest hiera_data for the supported service
        discover_func = eval('_discover_and_validate_' + svc + '_hiera_data')
        discover_func(capabilities)

        # Service is valid. Check the params
        for k in HIERA_DATA[svc]:
            if not capabilities.get(k, None):
                raise wsme.exc.ClientSideError("Missing required %s service "
                                               "parameter: %s" % (svc, k))

    # Update based on any discovered values
    storage_ceph_rook['capabilities'] = capabilities
    storage_ceph_rook['state'] = constants.SB_STATE_CONFIGURED
    storage_ceph_rook['task'] = constants.SB_TASK_NONE

    # Check for confirmation
    if not confirmed:
        _options_str = _get_options_string(storage_ceph_rook)
        raise wsme.exc.ClientSideError(
            _("%s\nWARNING : THIS OPERATION IS NOT REVERSIBLE AND CANNOT BE "
              "CANCELLED. \n\nPlease set the 'confirmed' field to execute "
              "this operation for the %s backend.") %
            (_options_str, constants.SB_TYPE_CEPH_ROOK))
Beispiel #18
0
def _apply_ceph_external_backend_changes(op, sb_obj, orig_sb_obj=None):
    if ((op == constants.SB_API_OP_CREATE) or
           (op == constants.SB_API_OP_MODIFY and
            sb_obj.get('ceph_conf') != orig_sb_obj.get('ceph_conf'))):

        values = {'task': constants.SB_TASK_APPLY_CONFIG_FILE}
        pecan.request.dbapi.storage_ceph_external_update(sb_obj.get('uuid'), values)

        try:
            pecan.request.rpcapi.distribute_ceph_external_config(
                pecan.request.context, sb_obj.get('ceph_conf'))
        except Exception as e:
            LOG.exception(e)
            msg = _("Failed to distribute ceph config file.")
            raise wsme.exc.ClientSideError(msg)

        services = api_helper.getListFromServices(sb_obj)

        pecan.request.rpcapi.update_ceph_external_config(
                                                pecan.request.context,
                                                sb_obj.get('uuid'),
                                                services)
    elif op == constants.SB_API_OP_DELETE:
        msg = _("Delete a Ceph external backend is not supported currently.")
        raise wsme.exc.ClientSideError(msg)
    else:
        # Compare ceph pools
        caps = sb_obj.get('capabilities', {})
        orig_caps = orig_sb_obj.get('capabilities', {})
        services = []
        for svc in constants.SB_CEPH_EXTERNAL_SVCS_SUPPORTED:
            for k in HIERA_DATA[svc]:
                if caps.get(k, None) != orig_caps.get(k, None):
                    services.append(svc)

        pecan.request.rpcapi.update_ceph_external_config(
                                                pecan.request.context,
                                                sb_obj.get('uuid'),
                                                services)
    def _build_ceph_entry(self, backend_name, tier_name, ceph_pool):
        """Create a ceph usage summary"""

        if ceph_pool:
            name = ceph_pool['name']

            # No need to build entry for rbd pool
            if name == 'rbd':
                return {}

            # Skip secondary tier names display pools for the primary tier
            if api_helper.is_primary_ceph_backend(backend_name):
                if name not in [
                        constants.CEPH_POOL_VOLUMES_NAME,
                        constants.CEPH_POOL_IMAGES_NAME,
                        constants.CEPH_POOL_EPHEMERAL_NAME,
                        constants.CEPH_POOL_OBJECT_GATEWAY_NAME_HAMMER,
                        constants.CEPH_POOL_OBJECT_GATEWAY_NAME_JEWEL
                ]:
                    return {}
            else:
                # Only show the pools for this specific secondary tier
                if not name.endswith(tier_name):
                    return {}

            # get quota from pool name
            osd_pool_quota = \
                pecan.request.rpcapi.get_osd_pool_quota(pecan.request.context, name)

            quota = osd_pool_quota['max_bytes']
            stats = ceph_pool['stats']
            usage = stats['bytes_used']

            # A quota of 0 means that the service using the pool can use any
            # unused space in the cluster effectively eating into
            # quota assigned to other pools.
            free = 0
            total = 0
            gib = 1024 * 1024 * 1024
            if quota > 0:
                free = quota - usage
                total = free + usage
                total = int(round(total / gib, 2))
                free = int(round(free / gib, 2))
                quota = int(round(quota / gib, 2))
                usage = int(round(usage / gib, 2))
            else:
                try:
                    max_avail = ceph_pool['stats']['max_avail']

                    # calculate cluster total and usage
                    total = max_avail + usage
                    usage = int(round(usage / gib, 2))
                    total = int(round(total / gib, 2))
                    free = int(round(max_avail / gib, 2))

                except Exception as e:
                    LOG.error("Error: : %s" % e)
            service = self._get_service_name(ceph_pool['name'])
            if service:
                dt = dict(service_name=service,
                          name=backend_name,
                          backend=constants.SB_TYPE_CEPH,
                          total_capacity=total,
                          free_capacity=free)
                return dt

        return {}
Beispiel #20
0
def _check_backend_ceph_external(storage_ceph_ext):
    """Prechecks for adding an external Ceph backend."""

    # go through the service list and validate
    svcs = api_helper.getListFromServices(storage_ceph_ext)

    for svc in svcs:
        if svc not in constants.SB_CEPH_EXTERNAL_SVCS_SUPPORTED:
            raise wsme.exc.ClientSideError(
                "Service %s is not supported for the"
                " %s backend" % (svc, constants.SB_TYPE_CEPH_EXTERNAL))

    # check for the backend parameters
    capabilities = storage_ceph_ext.get('capabilities', {})

    # Discover the latest hiera_data for the supported service
    _discover_and_validate_backend_hiera_data(capabilities)

    for svc in svcs:
        for k in HIERA_DATA[svc]:
            if not capabilities.get(k, None):
                raise wsme.exc.ClientSideError("Missing required %s service "
                                               "parameter: %s" % (svc, k))

    for svc in constants.SB_CEPH_EXTERNAL_SVCS_SUPPORTED:
        for k in HIERA_DATA[svc]:
            if capabilities.get(k, None) and svc not in svcs:
                raise wsme.exc.ClientSideError(
                    "Missing required service %s for "
                    "parameter: %s" % (svc, k))

    valid_pars = [i for sublist in HIERA_DATA.values() for i in sublist]
    if len(set(capabilities.keys()) - set(valid_pars)) > 0:
        raise wsme.exc.ClientSideError(
            "Parameter %s is not valid " %
            list(set(capabilities.keys()) - set(valid_pars)))

    # Check the Ceph configuration file
    ceph_conf_file = storage_ceph_ext.get('ceph_conf')
    if ceph_conf_file:
        if (ceph_conf_file == constants.SB_TYPE_CEPH_CONF_FILENAME):
            msg = _("The %s name is reserved for the internally managed Ceph "
                    "cluster.\nPlease use a different name and try again." %
                    constants.SB_TYPE_CEPH_CONF_FILENAME)
            raise wsme.exc.ClientSideError(msg)
    else:
        # Raise error if the Ceph configuration file is not provided.
        msg = _("A Ceph configuration file must be provided for provisioning "
                "an external Ceph cluster.")
        raise wsme.exc.ClientSideError(msg)

    # If a conf file is specified, make sure the backend's name is not already
    # used / one of the default names for other backends.
    if ceph_conf_file:
        backend_name = storage_ceph_ext.get('name')
        backend_list = pecan.request.dbapi.storage_backend_get_list()
        for backend in backend_list:
            if backend.uuid != storage_ceph_ext.get("uuid", None):
                if backend_name in constants.SB_DEFAULT_NAMES.values():
                    msg = _(
                        "The \"%s\" name is reserved for internally managed "
                        "backends." % backend_name)
                    raise wsme.exc.ClientSideError(msg)
                if backend.name == backend_name:
                    msg = _(
                        "The \"%s\" name is already used for another backend."
                        % backend_name)
                    raise wsme.exc.ClientSideError(msg)
Beispiel #21
0
def _patch(storlvm_uuid, patch):

    # Obtain current storage object.
    rpc_storlvm = objects.storage_lvm.get_by_uuid(pecan.request.context,
                                                  storlvm_uuid)

    patch_obj = jsonpatch.JsonPatch(patch)
    for p in patch_obj:
        if p['path'] == '/capabilities':
            p['value'] = jsonutils.loads(p['value'])

    ostorlvm = copy.deepcopy(rpc_storlvm)

    # perform checks based on the current vs.requested modifications
    _pre_patch_checks(rpc_storlvm, patch_obj)

    # Obtain a storage object with the patch applied.
    try:
        storlvm_config = StorageLVM(
            **jsonpatch.apply_patch(rpc_storlvm.as_dict(), patch_obj))

    except utils.JSONPATCH_EXCEPTIONS as e:
        raise exception.PatchError(patch=patch, reason=e)

    # Update current storage object.
    for field in objects.storage_lvm.fields:
        if (field in storlvm_config.as_dict()
                and rpc_storlvm[field] != storlvm_config.as_dict()[field]):
            rpc_storlvm[field] = storlvm_config.as_dict()[field]

    # Obtain the fields that have changed.
    delta = rpc_storlvm.obj_what_changed()
    if len(delta
           ) == 0 and rpc_storlvm['state'] != constants.SB_STATE_CONFIG_ERR:
        raise wsme.exc.ClientSideError(
            _("No changes to the existing backend settings were detected."))

    allowed_attributes = ['services', 'capabilities', 'task']
    for d in delta:
        if d not in allowed_attributes:
            raise wsme.exc.ClientSideError(
                _("Can not modify '%s' with this operation." % d))

    LOG.info("SYS_I orig storage_lvm: %s " % ostorlvm.as_dict())
    LOG.info("SYS_I new  storage_lvm: %s " % storlvm_config.as_dict())

    # Execute the common semantic checks for all backends, if backend is not
    # present this will not return
    api_helper.common_checks(constants.SB_API_OP_MODIFY, rpc_storlvm.as_dict())

    # Run the backend specific semantic checks
    _check_backend_lvm(constants.SB_API_OP_MODIFY, rpc_storlvm.as_dict(), True)

    try:
        rpc_storlvm.save()

        # Enable the backend changes:
        _apply_backend_changes(constants.SB_API_OP_MODIFY, rpc_storlvm)

        return StorageLVM.convert_with_links(rpc_storlvm)

    except exception.HTTPNotFound:
        msg = _("Storlvm update failed: storlvm %s : "
                " patch %s" % (storlvm_config, patch))
        raise wsme.exc.ClientSideError(msg)
Beispiel #22
0
def _patch(stor_ceph_ext_uuid, patch):

    # Obtain current storage object.
    rpc_stor_ceph_ext = objects.storage_ceph_external.get_by_uuid(
        pecan.request.context, stor_ceph_ext_uuid)

    ostor_ceph_ext = copy.deepcopy(rpc_stor_ceph_ext)

    patch_obj = jsonpatch.JsonPatch(patch)
    for p in patch_obj:
        if p['path'] == '/capabilities':
            p['value'] = jsonutils.loads(p['value'])

    # perform checks based on the current vs.requested modifications
    _pre_patch_checks(rpc_stor_ceph_ext, patch_obj)

    # Obtain a storage object with the patch applied.
    try:
        stor_ceph_ext_config = StorageCephExternal(
            **jsonpatch.apply_patch(rpc_stor_ceph_ext.as_dict(), patch_obj))

    except utils.JSONPATCH_EXCEPTIONS as e:
        raise exception.PatchError(patch=patch, reason=e)

    # Update current storage object.
    for field in objects.storage_ceph_external.fields:
        if (field in stor_ceph_ext_config.as_dict()
                and rpc_stor_ceph_ext[field] !=
                stor_ceph_ext_config.as_dict()[field]):
            rpc_stor_ceph_ext[field] = stor_ceph_ext_config.as_dict()[field]

    # Obtain the fields that have changed.
    delta = rpc_stor_ceph_ext.obj_what_changed()
    if len(delta) == 0 and rpc_stor_ceph_ext[
            'state'] != constants.SB_STATE_CONFIG_ERR:
        raise wsme.exc.ClientSideError(
            _("No changes to the existing backend settings were detected."))

    allowed_attributes = ['services', 'ceph_conf', 'capabilities', 'task']
    for d in delta:
        if d not in allowed_attributes:
            raise wsme.exc.ClientSideError(
                _("Can not modify '%s' with this operation." % d))

    LOG.info("SYS_I orig storage_ceph_external: %s " %
             ostor_ceph_ext.as_dict())
    LOG.info("SYS_I new  storage_ceph_external: %s " %
             stor_ceph_ext_config.as_dict())

    # Execute the common semantic checks for all backends, if backend is not
    # present this will not return
    api_helper.common_checks(constants.SB_API_OP_MODIFY, rpc_stor_ceph_ext)

    _check_backend_ceph_external(rpc_stor_ceph_ext)

    _check_and_update_services(rpc_stor_ceph_ext)

    rpc_stor_ceph_ext.save()

    _apply_ceph_external_backend_changes(constants.SB_API_OP_MODIFY,
                                         sb_obj=rpc_stor_ceph_ext,
                                         orig_sb_obj=ostor_ceph_ext)

    return StorageCephExternal.convert_with_links(rpc_stor_ceph_ext)