/* * Copyright (c) 2015 EMC Corporation * All Rights Reserved */ package com.emc.storageos.api.service.impl.resource; import static com.emc.storageos.api.mapper.HostMapper.map; import static com.emc.storageos.api.mapper.TaskMapper.toTask; import java.net.URI; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.UUID; 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 org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import com.emc.storageos.api.mapper.HostMapper; import com.emc.storageos.api.mapper.functions.MapIpInterface; import com.emc.storageos.api.service.authorization.PermissionsHelper; import com.emc.storageos.api.service.impl.response.BulkList; import com.emc.storageos.api.service.impl.response.FilterIterator; import com.emc.storageos.api.service.impl.response.ResRepFilter; import com.emc.storageos.api.service.impl.response.SearchedResRepList; import com.emc.storageos.computesystemcontroller.ComputeSystemController; import com.emc.storageos.computesystemcontroller.impl.ComputeSystemHelper; import com.emc.storageos.db.client.constraint.AlternateIdConstraint; import com.emc.storageos.db.client.model.DiscoveredDataObject.RegistrationStatus; import com.emc.storageos.db.client.model.FileExport; import com.emc.storageos.db.client.model.Host; import com.emc.storageos.db.client.model.IpInterface; import com.emc.storageos.db.client.model.Operation; import com.emc.storageos.db.client.util.EndpointUtility; import com.emc.storageos.db.exceptions.DatabaseException; import com.emc.storageos.model.BulkIdParam; import com.emc.storageos.model.RelatedResourceRep; import com.emc.storageos.model.ResourceOperationTypeEnum; import com.emc.storageos.model.ResourceTypeEnum; import com.emc.storageos.model.TaskResourceRep; import com.emc.storageos.model.host.IpInterfaceBulkRep; import com.emc.storageos.model.host.IpInterfaceRestRep; import com.emc.storageos.model.host.IpInterfaceUpdateParam; import com.emc.storageos.model.search.SearchResultResourceRep; import com.emc.storageos.model.search.SearchResults; import com.emc.storageos.model.valid.Endpoint.EndpointType; 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; /** * Service providing APIs for host ipinterfaces. */ @Path("/compute/ip-interfaces") @DefaultPermissions(readRoles = { Role.TENANT_ADMIN, Role.SYSTEM_MONITOR, Role.SYSTEM_ADMIN }, writeRoles = { Role.TENANT_ADMIN }, readAcls = { ACL.OWN, ACL.ALL }) public class IpInterfaceService extends TaskResourceService { private static Logger _log = LoggerFactory.getLogger(IpInterfaceService.class); private static final String EVENT_SERVICE_TYPE = "ip-interface"; public String getServiceType() { return EVENT_SERVICE_TYPE; } @Autowired private HostService _hostService; @Override protected URI getTenantOwner(URI id) { IpInterface ipInterface = queryObject(IpInterface.class, id, false); Host host = queryObject(Host.class, ipInterface.getHost(), false); return host.getTenant(); } @Override protected IpInterface queryResource(URI id) { return queryObject(IpInterface.class, id, false); } /** * Shows the data for an IP interface * * @param id the URN of a ViPR IP interface * * @prereq none * @brief Show IP interface * @return A IpInterfaceRestRep reference specifying the data for the * IP interface with the passed id. */ @GET @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}") @CheckPermission(roles = { Role.SYSTEM_MONITOR, Role.SYSTEM_ADMIN, Role.TENANT_ADMIN }, acls = { ACL.ANY }) public IpInterfaceRestRep getIpInterface(@PathParam("id") URI id) { IpInterface ipInterface = queryResource(id); // verify permissions verifyUserPermisions(ipInterface); return HostMapper.map(ipInterface); } /** * Deactivate an IP interface. * * @param id the URN of a ViPR IP interface * @prereq The IP interface must not have active exports * @brief Delete IP interface * @return OK if deactivation completed successfully * @throws DatabaseException */ @POST @Path("/{id}/deactivate") @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @CheckPermission(roles = { Role.TENANT_ADMIN }) public TaskResourceRep deactivateIpInterface(@PathParam("id") URI id) throws DatabaseException { IpInterface ipInterface = queryResource(id); ArgValidator.checkEntity(ipInterface, id, isIdEmbeddedInURL(id)); if (ipInterface.getIsManualCreation() != null && !ipInterface.getIsManualCreation()) { throw APIException.badRequests.ipInterfaceNotCreatedManuallyAndCannotBeDeleted(); } String taskId = UUID.randomUUID().toString(); Operation op = _dbClient.createTaskOpStatus(IpInterface.class, ipInterface.getId(), taskId, ResourceOperationTypeEnum.DELETE_HOST_IPINTERFACE); // Clean up File Export if host is in use if (ComputeSystemHelper.isHostIpInterfacesInUse(_dbClient, Collections.singletonList(ipInterface.getIpAddress()), ipInterface.getHost())) { ComputeSystemController controller = getController(ComputeSystemController.class, null); controller.removeIpInterfaceFromFileShare(ipInterface.getHost(), ipInterface.getId(), taskId); } else { _dbClient.ready(IpInterface.class, ipInterface.getId(), taskId); _dbClient.markForDeletion(ipInterface); } auditOp(OperationTypeEnum.DELETE_HOST_IPINTERFACE, true, null, ipInterface.auditParameters()); return toTask(ipInterface, taskId, op); } /** * Update a host IP interface. * * @param id the URN of a ViPR IP interface * @param updateParam the parameter containing the new attributes * @prereq none * @brief Update IP interface * @return the details of the updated host interface. * @throws DatabaseException when a DB error occurs */ @PUT @Path("/{id}") @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @CheckPermission(roles = { Role.TENANT_ADMIN }) public IpInterfaceRestRep updateIpInterface(@PathParam("id") URI id, IpInterfaceUpdateParam updateParam) throws DatabaseException { IpInterface ipInterface = queryObject(IpInterface.class, id, true); _hostService.validateIpInterfaceData(updateParam, ipInterface); _hostService.populateIpInterface(updateParam, ipInterface); _dbClient.persistObject(ipInterface); auditOp(OperationTypeEnum.UPDATE_HOST_IPINTERFACE, true, null, ipInterface.auditParameters()); return map(queryObject(IpInterface.class, id, false)); } /** * List data of specified IP interfaces. * * @param param POST data containing the id list. * @prereq none * @brief List data for IP interfaces * @return list of representations. */ @POST @Path("/bulk") @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Override public IpInterfaceBulkRep getBulkResources(BulkIdParam param) { return (IpInterfaceBulkRep) super.getBulkResources(param); } /** * Allows the user to deregister a registered IP interface so that it is no * longer used by the system. This simply sets the registration_status of * the IP interface to UNREGISTERED. * * @param id the URN of a ViPR IP interface * * @brief Unregister IP interface * @return Status response indicating success or failure */ @POST @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Path("/{id}/deregister") @CheckPermission(roles = { Role.TENANT_ADMIN }) public IpInterfaceRestRep deregisterIpInterface(@PathParam("id") URI id) { IpInterface ipInterface = queryResource(id); ArgValidator.checkEntity(ipInterface, id, isIdEmbeddedInURL(id)); if (ComputeSystemHelper.isHostIpInterfacesInUse(_dbClient, Collections.singletonList(ipInterface.getIpAddress()), ipInterface.getHost())) { throw APIException.badRequests.resourceHasActiveReferencesWithType(IpInterface.class.getSimpleName(), ipInterface.getId(), FileExport.class.getSimpleName()); } if (RegistrationStatus.REGISTERED.toString().equalsIgnoreCase( ipInterface.getRegistrationStatus())) { ipInterface.setRegistrationStatus(RegistrationStatus.UNREGISTERED.toString()); _dbClient.persistObject(ipInterface); auditOp(OperationTypeEnum.DEREGISTER_HOST_IPINTERFACE, true, null, ipInterface.getLabel(), ipInterface.getId().toString()); } return map(ipInterface); } /** * Manually register the IP interface with the passed id. * * @param id the URN of a ViPR IP interface * * @brief Register IP interface * @return A reference to an IpInterfaceRestRep specifying the data for the * IP interface. */ @POST @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @CheckPermission(roles = { Role.TENANT_ADMIN }) @Path("/{id}/register") public IpInterfaceRestRep registerIpInterface(@PathParam("id") URI id) { ArgValidator.checkFieldUriType(id, IpInterface.class, "id"); IpInterface ipInterface = _dbClient.queryObject(IpInterface.class, id); ArgValidator.checkEntity(ipInterface, id, isIdEmbeddedInURL(id)); if (RegistrationStatus.UNREGISTERED.toString().equalsIgnoreCase( ipInterface.getRegistrationStatus())) { ipInterface.setRegistrationStatus(RegistrationStatus.REGISTERED.toString()); _dbClient.persistObject(ipInterface); auditOp(OperationTypeEnum.REGISTER_HOST_IPINTERFACE, true, null, ipInterface.getId().toString()); } return map(ipInterface); } @SuppressWarnings("unchecked") @Override public Class<IpInterface> getResourceClass() { return IpInterface.class; } @Override public IpInterfaceBulkRep queryBulkResourceReps(List<URI> ids) { Iterator<IpInterface> _dbIterator = _dbClient.queryIterativeObjects(getResourceClass(), ids); return new IpInterfaceBulkRep(BulkList.wrapping(_dbIterator, MapIpInterface.getInstance())); } @Override public IpInterfaceBulkRep queryFilteredBulkResourceReps(List<URI> ids) { Iterator<IpInterface> _dbIterator = _dbClient.queryIterativeObjects(getResourceClass(), ids); BulkList.ResourceFilter filter = new BulkList.HostInterfaceFilter(getUserFromContext(), _permissionsHelper); return new IpInterfaceBulkRep(BulkList.wrapping(_dbIterator, MapIpInterface.getInstance(), filter)); } @Override protected ResourceTypeEnum getResourceType() { return ResourceTypeEnum.IPINTERFACE; } @Override protected boolean isZoneLevelResource() { return false; } @Override protected boolean isSysAdminReadableResource() { return true; } public static class IpInterfaceResRepFilter<E extends RelatedResourceRep> extends ResRepFilter<E> { public IpInterfaceResRepFilter(StorageOSUser user, PermissionsHelper permissionsHelper) { super(user, permissionsHelper); } @Override public boolean isAccessible(E resrep) { boolean ret = false; URI id = resrep.getId(); IpInterface ipif = _permissionsHelper.getObjectById(id, IpInterface.class); if (ipif == null || ipif.getHost() == null) { return false; } Host obj = _permissionsHelper.getObjectById(ipif.getHost(), Host.class); if (obj == null) { return false; } if (obj.getTenant().toString().equals(_user.getTenantId())) { return true; } ret = isTenantAccessible(obj.getTenant()); return ret; } } /** * Get object specific permissions filter */ @Override public ResRepFilter<? extends RelatedResourceRep> getPermissionFilter(StorageOSUser user, PermissionsHelper permissionsHelper) { return new IpInterfaceResRepFilter(user, permissionsHelper); } /** * Verify the user has read permission to the IP interface * * @param ipInterface the IP interface to be verified */ private void verifyUserPermisions(IpInterface ipInterface) { // check the user permissions for the tenant org Host host = queryObject(Host.class, ipInterface.getHost(), false); verifyAuthorizedInTenantOrg(host.getTenant(), getUserFromContext()); } /** * * parameter: 'ip_address' The ip address of the ipInterface * * @return Return a list of ipinterfaces that contains the ip address specified * or an empty list if no match was found. */ @Override protected SearchResults getOtherSearchResults(Map<String, List<String>> parameters, boolean authorized) { SearchResults result = new SearchResults(); if (!parameters.containsKey("ip_address")) { throw APIException.badRequests.invalidParameterSearchMissingParameter(getResourceClass().getName(), "ip_address"); } for (Map.Entry<String, List<String>> entry : parameters.entrySet()) { if (!entry.getKey().equals("ip_address")) { throw APIException.badRequests.parameterForSearchCouldNotBeCombinedWithAnyOtherParameter(getResourceClass().getName(), "ip_address", entry.getKey()); } } String ip = parameters.get("ip_address").get(0); // Validate that the ip_address value is not empty ArgValidator.checkFieldNotEmpty(ip, "ip_address"); // Validate the format of the initiator port. if (!EndpointUtility.isValidEndpoint(ip, EndpointType.IP)) { throw APIException.badRequests.invalidParameterInvalidIP("ip_address", ip); } SearchedResRepList resRepList = new SearchedResRepList(getResourceType()); // Finds the IpInterface that includes the ip address specified, if any. _dbClient.queryByConstraint(AlternateIdConstraint.Factory.getIpInterfaceIpAddressConstraint(ip), resRepList); // Filter list based on permission if (!authorized) { Iterator<SearchResultResourceRep> _queryResultIterator = resRepList.iterator(); ResRepFilter<SearchResultResourceRep> resRepFilter = (ResRepFilter<SearchResultResourceRep>) getPermissionFilter(getUserFromContext(), _permissionsHelper); SearchedResRepList filteredResRepList = new SearchedResRepList(); filteredResRepList.setResult( new FilterIterator<SearchResultResourceRep>(_queryResultIterator, resRepFilter)); result.setResource(filteredResRepList); } else { result.setResource(resRepList); } return result; } }