/* * Copyright (c) 2015 EMC Corporation * All Rights Reserved */ package com.emc.sa.api; import static com.emc.sa.api.mapper.CatalogServiceMapper.createNewObject; import static com.emc.sa.api.mapper.CatalogServiceMapper.createNewObjectList; import static com.emc.sa.api.mapper.CatalogServiceMapper.map; import static com.emc.sa.api.mapper.CatalogServiceMapper.toCatalogServiceList; import static com.emc.sa.api.mapper.CatalogServiceMapper.updateObject; import static com.emc.sa.api.mapper.CatalogServiceMapper.updateObjectList; import static com.emc.storageos.db.client.URIUtil.uri; import java.net.URI; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import com.emc.sa.api.utils.CatalogConfigUtils; import org.springframework.beans.factory.annotation.Autowired; import com.emc.sa.api.mapper.CatalogServiceFilter; import com.emc.sa.api.utils.CatalogACLInputFilter; import com.emc.sa.api.utils.ValidationUtils; import com.emc.sa.catalog.CatalogCategoryManager; import com.emc.sa.catalog.CatalogServiceManager; import com.emc.sa.descriptor.ServiceDescriptor; import com.emc.sa.descriptor.ServiceDescriptors; import com.emc.sa.descriptor.ServiceField; import com.emc.storageos.db.client.model.uimodels.CatalogCategory; import com.emc.storageos.db.client.model.uimodels.CatalogService; import com.emc.storageos.db.client.model.uimodels.CatalogServiceAndFields; import com.emc.storageos.db.client.model.uimodels.CatalogServiceField; import com.emc.sa.model.util.SortedIndexUtils; import com.emc.storageos.api.service.impl.resource.ArgValidator; import com.emc.storageos.db.exceptions.DatabaseException; import com.emc.storageos.model.BulkIdParam; import com.emc.storageos.model.ResourceTypeEnum; import com.emc.storageos.model.auth.ACLAssignmentChanges; import com.emc.storageos.model.auth.ACLAssignments; import com.emc.storageos.security.authentication.StorageOSUser; import com.emc.storageos.security.authorization.ACL; import com.emc.storageos.security.authorization.CheckPermission; import com.emc.storageos.security.authorization.DefaultPermissions; import com.emc.storageos.security.authorization.Role; import com.emc.storageos.services.OperationTypeEnum; import com.emc.storageos.svcs.errorhandling.resources.APIException; import com.emc.storageos.volumecontroller.impl.monitoring.RecordableEventManager; import com.emc.vipr.model.catalog.CatalogServiceBulkRep; import com.emc.vipr.model.catalog.CatalogServiceCommonParam; import com.emc.vipr.model.catalog.CatalogServiceCreateParam; import com.emc.vipr.model.catalog.CatalogServiceFieldParam; import com.emc.vipr.model.catalog.CatalogServiceList; import com.emc.vipr.model.catalog.CatalogServiceRestRep; import com.emc.vipr.model.catalog.CatalogServiceUpdateParam; @DefaultPermissions( readRoles = { Role.TENANT_ADMIN, Role.SYSTEM_MONITOR, Role.SYSTEM_ADMIN }, writeRoles = { Role.TENANT_ADMIN }, readAcls = { ACL.ANY }) @Path("/catalog/services") public class CatalogServiceService extends CatalogTaggedResourceService { private static final String EVENT_SERVICE_TYPE = "catalog-service"; @Autowired private CatalogServiceManager catalogServiceManager; @Autowired private CatalogCategoryManager catalogCategoryManager; @Autowired private RecordableEventManager eventManager; @Autowired private ServiceDescriptors serviceDescriptors; private CatalogConfigUtils catalogConfigUtils; public void setCatalogConfigUtils(CatalogConfigUtils catalogConfigUtils) { this.catalogConfigUtils = catalogConfigUtils; } @Override protected CatalogService queryResource(URI id) { return getCatalogServiceById(id, false); } @Override protected URI getTenantOwner(URI id) { CatalogService catalogService = queryResource(id); CatalogCategory parentCatalogCategory = catalogCategoryManager.getCatalogCategoryById(catalogService.getCatalogCategoryId() .getURI()); return uri(parentCatalogCategory.getTenant()); } @Override protected ResourceTypeEnum getResourceType() { return ResourceTypeEnum.CATALOG_SERVICE; } @Override public String getServiceType() { return EVENT_SERVICE_TYPE; } /** * Gets the map of service descriptors by service ID->descriptor. * * @return the service descriptor mapping. */ private Map<String, ServiceDescriptor> getServiceDescriptors() { Map<String, ServiceDescriptor> descriptors = new HashMap<>(); for (ServiceDescriptor descriptor : serviceDescriptors.listDescriptors(Locale.getDefault())) { descriptors.put(descriptor.getServiceId(), descriptor); } return descriptors; } /** * Gets a service descriptor by ID, returning null if no such service exists. * * @param serviceId * the service ID. * @return the service descriptor, or null. */ private ServiceDescriptor getServiceDescriptor(String serviceId) { try { return serviceDescriptors.getDescriptor(Locale.getDefault(), serviceId); } catch (IllegalStateException e) { return null; } } /** * Gets the service descriptor for the given service. * * @param service * the catalog service. * @return the service descriptor, or null. */ private ServiceDescriptor getServiceDescriptor(CatalogService service) { return getServiceDescriptor(service.getBaseService()); } /** * Get info for catalog category * * @param id the URN of a Catalog Category * @prereq none * @brief Show catalog category * @return Catalog Category details */ @GET @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}") public CatalogServiceRestRep getCatalogService(@PathParam("id") URI id) { CatalogService catalogService = queryResource(id); ServiceDescriptor serviceDescriptor = getServiceDescriptor(catalogService); List<CatalogServiceField> catalogServiceFields = catalogServiceManager.getCatalogServiceFields(catalogService.getId()); return map(catalogService, serviceDescriptor, catalogServiceFields); } /** * Creates a new catalog service * * @param createParam * the parameter to create a new catalog service * @prereq none * @brief Create Catalog Service * @return none */ @POST @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN }) @Path("") public CatalogServiceRestRep createCatalogService(CatalogServiceCreateParam createParam) { StorageOSUser user = getUserFromContext(); CatalogCategory parentCatalogCategory = catalogCategoryManager.getCatalogCategoryById(createParam.getCatalogCategory()); verifyAuthorizedInTenantOrg(uri(parentCatalogCategory.getTenant()), user); validateParam(createParam, null); CatalogService catalogService = createNewObject(createParam, parentCatalogCategory); List<CatalogServiceField> catalogServiceFields = createNewObjectList(catalogService, createParam.getCatalogServiceFields()); catalogServiceManager.createCatalogService(catalogService, catalogServiceFields); auditOpSuccess(OperationTypeEnum.CREATE_CATALOG_SERVICE, catalogService.auditParameters()); // Refresh Objects catalogService = catalogServiceManager.getCatalogServiceById(catalogService.getId()); catalogServiceFields = catalogServiceManager.getCatalogServiceFields(catalogService.getId()); ServiceDescriptor serviceDescriptor = getServiceDescriptor(catalogService); return map(catalogService, serviceDescriptor, catalogServiceFields); } /** * Update catalog service * * @param param Catalog Service update parameters * @param id the URN the catalog service * @prereq none * @brief Update Catalog Service * @return No data returned in response body */ @PUT @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}") @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN }) public CatalogServiceRestRep updateCatalogService(@PathParam("id") URI id, CatalogServiceUpdateParam param) { CatalogService catalogService = getCatalogServiceById(id, true); List<CatalogServiceField> catalogServiceFields = catalogServiceManager.getCatalogServiceFields(id); StorageOSUser user = getUserFromContext(); CatalogCategory parentCatalogCategory = catalogCategoryManager.getCatalogCategoryById(param.getCatalogCategory()); verifyAuthorizedInTenantOrg(uri(parentCatalogCategory.getTenant()), user); validateParam(param, catalogService); updateObject(catalogService, param, parentCatalogCategory); List<CatalogServiceField> updatedCatalogServiceFields = updateObjectList(catalogService, catalogServiceFields, param.getCatalogServiceFields()); catalogServiceManager.updateCatalogService(catalogService, updatedCatalogServiceFields); auditOpSuccess(OperationTypeEnum.UPDATE_CATALOG_SERVICE, catalogService.auditParameters()); // Refresh Objects catalogService = catalogServiceManager.getCatalogServiceById(catalogService.getId()); catalogServiceFields = catalogServiceManager.getCatalogServiceFields(catalogService.getId()); ServiceDescriptor serviceDescriptor = getServiceDescriptor(catalogService); return map(catalogService, serviceDescriptor, catalogServiceFields); } @GET @Path("/{id}/acl") @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @CheckPermission(roles = { Role.SECURITY_ADMIN, Role.TENANT_ADMIN }, acls = { ACL.OWN }) public ACLAssignments getRoleAssignments(@PathParam("id") URI id) { return getRoleAssignmentsResponse(id); } @PUT @Path("/{id}/acl") @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @CheckPermission(roles = { Role.SECURITY_ADMIN, Role.TENANT_ADMIN }, acls = { ACL.OWN }, blockProxies = true) public ACLAssignments updateRoleAssignments(@PathParam("id") URI id, ACLAssignmentChanges changes) { CatalogService catalogService = catalogServiceManager.getCatalogServiceById(id); CatalogCategory parentCatalogCategory = catalogCategoryManager.getCatalogCategoryById(catalogService.getCatalogCategoryId() .getURI()); URI tenantId = uri(parentCatalogCategory.getTenant()); _permissionsHelper.updateACLs(catalogService, changes, new CatalogACLInputFilter(tenantId)); catalogServiceManager.updateCatalogService(catalogService, null); ; auditOpSuccess(OperationTypeEnum.MODIFY_CATALOG_SERVICE_ACL, catalogService.getId() .toString(), catalogService.getLabel(), changes); catalogConfigUtils.notifyCatalogAclChange(); return getRoleAssignmentsResponse(id); } @PUT @Path("/{id}/move/up") @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN }) public Response moveUpCatalogService(@PathParam("id") URI id) { catalogServiceManager.moveUpCatalogService(id); return Response.ok().build(); } @PUT @Path("/{id}/move/down") @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN }) public Response moveDownCatalogService(@PathParam("id") URI id) { catalogServiceManager.moveDownCatalogService(id); return Response.ok().build(); } private ACLAssignments getRoleAssignmentsResponse(URI id) { CatalogService catalogService = catalogServiceManager.getCatalogServiceById(id); ACLAssignments response = new ACLAssignments(); response.setAssignments(_permissionsHelper.convertToACLEntries(catalogService.getAcls())); return response; } @PUT @Path("/{id}/fields/{name}/move/up") @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN }) public Response moveUpCatalogServiceField(@PathParam("id") URI id, @PathParam("name") String name) { catalogServiceManager.moveUpCatalogServiceField(id, name); return Response.ok().build(); } @PUT @Path("/{id}/fields/{name}/move/down") @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @CheckPermission(roles = { Role.TENANT_ADMIN }, acls = { ACL.OWN }) public Response moveDownCatalogService(@PathParam("id") URI id, @PathParam("name") String name) { catalogServiceManager.moveDownCatalogServiceField(id, name); return Response.ok().build(); } /** * Deactivates the catalog service * * @param id the URN of an catalog service to be deactivated * @brief Deactivate Catalog Service * @return OK if deactivation completed successfully * @throws DatabaseException when a DB error occurs */ @POST @Path("/{id}/deactivate") @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @CheckPermission(roles = { Role.TENANT_ADMIN }) public Response deactivateCatalogService(@PathParam("id") URI id) throws DatabaseException { CatalogService catalogService = queryResource(id); ArgValidator.checkEntity(catalogService, id, true); catalogServiceManager.deleteCatalogService(catalogService); auditOpSuccess(OperationTypeEnum.DELETE_CATALOG_SERVICE, catalogService.auditParameters()); return Response.ok().build(); } /** * Gets the list a user's recent services * * @brief List user's recent catalog services * @return a list of user's recent services * @throws DatabaseException when a DB error occurs */ @GET @Path("/recent") @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public CatalogServiceList getRecentCatalogServices() throws DatabaseException { StorageOSUser user = getUserFromContext(); List<CatalogService> catalogServices = catalogServiceManager.getRecentCatalogServices(user); return toCatalogServiceList(catalogServices); } private CatalogService getCatalogServiceById(URI id, boolean checkInactive) { CatalogService catalogService = catalogServiceManager.getCatalogServiceById(id); ArgValidator.checkEntity(catalogService, id, isIdEmbeddedInURL(id), checkInactive); return catalogService; } private void validateParam(CatalogServiceCommonParam input, CatalogService existing) { ServiceDescriptor descriptor = catalogServiceManager.getServiceDescriptor(input.getBaseService()); if (descriptor == null) { throw APIException.badRequests.baseServiceNotFound(input.getBaseService()); } for (CatalogServiceFieldParam field : input.getCatalogServiceFields()) { if (!field.getOverride()) { continue; } String fieldName = field.getName(); String fieldValue = field.getValue(); ServiceField descriptorField = descriptor.getField(fieldName); if (descriptorField != null) { ValidationUtils.validateField(input.getMaxSize(), descriptorField, fieldValue); } } } /** * List data for the specified services. * * @param param POST data containing the id list. * @prereq none * @brief List data of specified services * @return list of representations. * * @throws DatabaseException When an error occurs querying the database. */ @POST @Path("/bulk") @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Override public CatalogServiceBulkRep getBulkResources(BulkIdParam param) { return (CatalogServiceBulkRep) super.getBulkResources(param); } @SuppressWarnings("unchecked") @Override public Class<CatalogService> getResourceClass() { return CatalogService.class; } @Override public CatalogServiceBulkRep queryBulkResourceReps(List<URI> ids) { return queryBulkResourceReps(ids, null); } @Override public CatalogServiceBulkRep queryFilteredBulkResourceReps(List<URI> ids) { CatalogServiceFilter filter = new CatalogServiceFilter(getUserFromContext(), _permissionsHelper, this.catalogCategoryManager); return queryBulkResourceReps(ids, filter); } private CatalogServiceBulkRep queryBulkResourceReps(List<URI> ids, CatalogServiceFilter filter) { List<CatalogServiceRestRep> catalogServiceRestReps = new ArrayList<CatalogServiceRestRep>(); List<CatalogServiceAndFields> catalogServicesWithFields = catalogServiceManager .getCatalogServicesWithFields(ids); Map<String, ServiceDescriptor> descriptors = getServiceDescriptors(); for (CatalogServiceAndFields catalogServiceAndField : catalogServicesWithFields) { if ((filter == null) || filter.isAccessible(catalogServiceAndField.getCatalogService())) { CatalogService service = catalogServiceAndField.getCatalogService(); ServiceDescriptor descriptor = descriptors.get(service.getBaseService()); List<CatalogServiceField> serviceFields = catalogServiceAndField.getCatalogServiceFields(); catalogServiceRestReps.add(map(service, descriptor, serviceFields)); } } catalogServiceRestReps = SortedIndexUtils.createSortedList(catalogServiceRestReps.iterator()); return new CatalogServiceBulkRep(catalogServiceRestReps); } }