class Controller(rest.RestController): """Version 1 API controller root.""" isystems = system.SystemController() ihosts = host.HostController() helm_charts = helm_charts.HelmChartsController() inodes = node.NodeController() icpus = cpu.CPUController() imemorys = memory.MemoryController() iinterfaces = interface.InterfaceController() ports = port.PortController() ethernet_ports = ethernet_port.EthernetPortController() istors = storage.StorageController() ilvgs = lvg.LVGController() ipvs = pv.PVController() idisks = disk.DiskController() partitions = partition.PartitionController() iprofile = profile.ProfileController() itrapdest = trapdest.TrapDestController() icommunity = community.CommunityController() iuser = user.UserController() idns = dns.DNSController() intp = ntp.NTPController() ptp = ptp.PTPController() iextoam = network_oam.OAMNetworkController() controller_fs = controller_fs.ControllerFsController() storage_backend = storage_backend.StorageBackendController() storage_lvm = storage_lvm.StorageLVMController() storage_file = storage_file.StorageFileController() storage_external = storage_external.StorageExternalController() storage_ceph = storage_ceph.StorageCephController() storage_tiers = storage_tier.StorageTierController() storage_ceph_external = \ storage_ceph_external.StorageCephExternalController() ceph_mon = ceph_mon.CephMonController() drbdconfig = drbdconfig.drbdconfigsController() addresses = address.AddressController() addrpools = address_pool.AddressPoolController() routes = route.RouteController() certificate = certificate.CertificateController() isensors = sensor.SensorController() isensorgroups = sensorgroup.SensorGroupController() loads = load.LoadController() pci_devices = pci_device.PCIDeviceController() upgrade = upgrade.UpgradeController() networks = network.NetworkController() interface_networks = interface_network.InterfaceNetworkController() service_parameter = service_parameter.ServiceParameterController() clusters = cluster.ClusterController() lldp_agents = lldp_agent.LLDPAgentController() lldp_neighbours = lldp_neighbour.LLDPNeighbourController() services = service.SMServiceController() servicenodes = servicenode.SMServiceNodeController() servicegroup = servicegroup.SMServiceGroupController() health = health.HealthController() registry_image = registry_image.RegistryImageController() remotelogging = remotelogging.RemoteLoggingController() sdn_controller = sdn_controller.SDNControllerController() license = license.LicenseController() labels = label.LabelController() fernet_repo = fernet_repo.FernetKeyController() apps = kube_app.KubeAppController() datanetworks = datanetwork.DataNetworkController() interface_datanetworks = interface_datanetwork.InterfaceDataNetworkController() host_fs = host_fs.HostFsController() @wsme_pecan.wsexpose(V1) def get(self): # NOTE: The reason why convert() it's being called for every # request is because we need to get the host url from # the request object to make the links. return V1.convert()
class StorageTierController(rest.RestController): """REST controller for storage tiers.""" istors = storage_api.StorageController(from_tier=True) "Expose istors as a sub-element of storage_tier" _custom_actions = { 'detail': ['GET'], } def __init__(self, from_cluster=False, **kwargs): self._from_cluster = from_cluster self._ceph = ceph.CephApiOperator() def _get_tiers_collection(self, uuid, marker, limit, sort_key, sort_dir, expand=False, resource_url=None): if self._from_cluster and not uuid: raise exception.InvalidParameterValue( _("Cluster id not specified.")) limit = utils.validate_limit(limit) sort_dir = utils.validate_sort_dir(sort_dir) marker_obj = None if marker: marker_obj = objects.storage_tier.get_by_uuid( pecan.request.context, marker) if self._from_cluster: storage_tiers = pecan.request.dbapi.storage_tier_get_by_cluster( uuid, limit=limit, marker=marker_obj, sort_key=sort_key, sort_dir=sort_dir) else: storage_tiers = pecan.request.dbapi.storage_tier_get_list( limit, marker_obj, sort_key=sort_key, sort_dir=sort_dir) return StorageTierCollection.convert_with_links(storage_tiers, limit, url=resource_url, expand=expand, sort_key=sort_key, sort_dir=sort_dir) @wsme_pecan.wsexpose(StorageTierCollection, types.uuid, types.uuid, int, wtypes.text, wtypes.text) def get_all(self, uuid=None, marker=None, limit=None, sort_key='id', sort_dir='asc'): """Retrieve a list of storage tiers.""" return self._get_tiers_collection(uuid, marker, limit, sort_key, sort_dir) @wsme_pecan.wsexpose(StorageTierCollection, types.uuid, types.uuid, int, wtypes.text, wtypes.text) def detail(self, tier_uuid=None, marker=None, limit=None, sort_key='id', sort_dir='asc'): """Retrieve a list of storage tiers with detail.""" parent = pecan.request.path.split('/')[:-1][-1] if parent != 'storage_tiers': raise exception.HTTPNotFound expand = True resource_url = '/'.join(['storage_tiers', 'detail']) return self._get_tiers_collection(tier_uuid, marker, limit, sort_key, sort_dir, expand, resource_url) @wsme_pecan.wsexpose(StorageTier, types.uuid) def get_one(self, tier_uuid): """Retrieve information about the given storage tier.""" if self._from_cluster: raise exception.OperationNotPermitted rpc_tier = objects.storage_tier.get_by_uuid(pecan.request.context, tier_uuid) return StorageTier.convert_with_links(rpc_tier) @cutils.synchronized(LOCK_NAME) @wsme_pecan.wsexpose(StorageTier, body=StorageTier) def post(self, tier): """Create a new storage tier.""" if self._from_cluster: raise exception.OperationNotPermitted try: tier = tier.as_dict() LOG.debug("storage tier post dict= %s" % tier) new_tier = _create(self, tier) except exception.SysinvException as e: LOG.exception(e) raise wsme.exc.ClientSideError( _("Invalid data: failed to create " "a storage tier object")) return StorageTier.convert_with_links(new_tier) @cutils.synchronized(LOCK_NAME) @wsme.validate(types.uuid, [StorageTierPatchType]) @wsme_pecan.wsexpose(StorageTier, types.uuid, body=[StorageTierPatchType]) def patch(self, tier_uuid, patch): """Update an existing storage tier.""" if self._from_cluster: raise exception.OperationNotPermitted LOG.debug("patch_data: %s" % patch) rpc_tier = objects.storage_tier.get_by_uuid(pecan.request.context, tier_uuid) patch_obj = jsonpatch.JsonPatch(patch) backend = dict(name='*unknown*') for p in patch_obj: if p['path'] == '/backend_uuid': p['path'] = '/forbackendid' backend = objects.storage_backend.get_by_uuid( pecan.request.context, p['value']) p['value'] = backend.id elif p['path'] == '/cluster_uuid': p['path'] = '/forclusterid' cluster = objects.cluster.get_by_uuid(pecan.request.context, p['value']) p['value'] = cluster.id otier = copy.deepcopy(rpc_tier) # Validate provided patch data meets validity checks _pre_patch_checks(rpc_tier, patch_obj) try: tier = StorageTier( **jsonpatch.apply_patch(rpc_tier.as_dict(), patch_obj)) except utils.JSONPATCH_EXCEPTIONS as e: raise exception.PatchError(patch=patch, reason=e) # Semantic Checks _check(self, "modify", tier.as_dict()) try: # Update only the fields that have changed for field in objects.storage_tier.fields: if rpc_tier[field] != getattr(tier, field): rpc_tier[field] = getattr(tier, field) # Obtain the fields that have changed. delta = rpc_tier.obj_what_changed() if len(delta) == 0: raise wsme.exc.ClientSideError( _("No changes to the existing tier settings were detected." )) allowed_attributes = ['name'] for d in delta: if d not in allowed_attributes: raise wsme.exc.ClientSideError( _("Cannot modify '%s' with this operation." % d)) LOG.info("SYS_I orig storage_tier: %s " % otier.as_dict()) LOG.info("SYS_I new storage_tier: %s " % rpc_tier.as_dict()) if 'name' in delta: default_tier_name = constants.SB_TIER_DEFAULT_NAMES[ constants.SB_TIER_TYPE_CEPH] if rpc_tier.name == default_tier_name: raise wsme.exc.ClientSideError( _("Cannot modify tier '%s'. Name '%s' is used " "by the default tier" % (otier.name, rpc_tier.name))) self._ceph.crushmap_tier_rename(otier.name, rpc_tier.name) # Save and return rpc_tier.save() return StorageTier.convert_with_links(rpc_tier) except (exception.HTTPNotFound, exception.CephFailure) as e: msg = _( "Storage Tier update failed: backend %s storage tier %s : patch %s. " " Reason: %s") % (backend['name'], otier['name'], patch, str(e)) raise wsme.exc.ClientSideError(msg) @cutils.synchronized(LOCK_NAME) @wsme_pecan.wsexpose(None, types.uuid, status_code=204) def delete(self, tier_uuid): """Delete a storage tier.""" if self._from_cluster: raise exception.OperationNotPermitted _delete(self, tier_uuid)