package io.eguan.vold.rest.resources; /* * #%L * Project eguan * %% * Copyright (C) 2012 - 2017 Oodrive * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ import io.eguan.vold.model.SnapshotMXBean; import io.eguan.vold.model.VvrMXBean; import io.eguan.vold.model.VvrObjectNameFactory; import io.eguan.vold.rest.errors.ClientErrorFactory; import io.eguan.vold.rest.errors.CustomResourceException; import io.eguan.vold.rest.errors.ServerErrorFactory; import io.eguan.vold.rest.generated.model.VersionedVolumeRepository; import io.eguan.vold.rest.generated.resources.DevicesResource; import io.eguan.vold.rest.generated.resources.RootSnapshotResource; import io.eguan.vold.rest.generated.resources.SnapshotsResource; import io.eguan.vold.rest.generated.resources.VvrResource; import io.eguan.vold.rest.generated.resources.VvrStartResource; import io.eguan.vold.rest.generated.resources.VvrStopResource; import io.eguan.vold.rest.generated.resources.VvrTasksResource; import io.eguan.vold.rest.util.InputValidation; import io.eguan.vold.rest.util.ResourcePath; import java.io.IOException; import java.net.URI; import java.util.Objects; import java.util.Set; import java.util.UUID; import javax.management.JMX; import javax.management.MBeanServerConnection; import javax.management.ObjectName; import javax.management.Query; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.UriBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * {@link VvrResource} implementation for JMX backend. * * @author oodrive * @author pwehrle * @author ebredzinski * */ public final class VvrResourceJmxImpl extends AbstractResource implements VvrResource { private static final Logger LOGGER = LoggerFactory.getLogger(VvrsResourceJmxImpl.class); private final VvrMXBean vvrInstance; private VvrsResourceJmxImpl parentResource; private final URI resourceUri; private final String tasksResourcePath; VvrResourceJmxImpl(final VvrMXBean vvrProxy, final URI resourceUri) { this.vvrInstance = vvrProxy; this.resourceUri = resourceUri; this.tasksResourcePath = ResourcePath.extractPathForSubResourceLocator(this.getClass(), VvrTasksResource.class); } public final class VvrStartResourceJmxImpl implements VvrStartResource { @Override public final Response start(final String ownerId) { final VvrsTasksResourceJmxImpl tasksResource = getParentResource().getVvrsTasksResource(); final String taskId; try { taskId = vvrInstance.startNoWait(); } catch (final Exception e) { throw ServerErrorFactory.newInternalErrorException("failed to start the vvr", "Exception start failed", e); } final URI taskUri = tasksResource.constructTaskUri(taskId); return Response.status(Status.ACCEPTED).location(taskUri).build(); } } public final class VvrStopResourceJmxImpl implements VvrStopResource { @Override public final Response stop(final String ownerId) { final VvrsTasksResourceJmxImpl tasksResource = getParentResource().getVvrsTasksResource(); final String taskId; try { taskId = vvrInstance.stopNoWait(); } catch (final IllegalStateException e) { throw ClientErrorFactory.newForbiddenException(e.getMessage(), "Illegal state to stop vvr"); } catch (final Exception e) { throw ServerErrorFactory.newInternalErrorException("Failed to stop vvr", "Exception stop vvr", e); } final URI taskUri = tasksResource.constructTaskUri(taskId); return Response.status(Status.ACCEPTED).location(taskUri).build(); } } @Override public final VersionedVolumeRepository getVvr(final String ownerId) { return VvrsResourceJmxImpl.getVvrPojoFromMbeanProxy(vvrInstance); } @Override public final VersionedVolumeRepository postVvr(final String ownerId, final VersionedVolumeRepository vvr) throws CustomResourceException { Objects.requireNonNull(vvr); if (LOGGER.isDebugEnabled()) { LOGGER.debug("POST on VVR " + vvrInstance.getUuid() + "; argument=" + vvr.toString()); } boolean readOnlyChanged = false; readOnlyChanged |= !vvrInstance.getUuid().equals(vvr.getUuid()); readOnlyChanged |= !vvrInstance.getOwnerUuid().equals(ownerId); if (readOnlyChanged) { LOGGER.warn("Detected read-only attribute change on VVR " + vvrInstance.getUuid()); throw ClientErrorFactory.newForbiddenException("Read-only attribute(s) changed", "Read-only attribute(s) change request on VVR " + vvrInstance.getUuid()); } vvrInstance.setName(vvr.getName()); vvrInstance.setDescription(vvr.getDescription()); // FIXME: persist quota and instanceCount or remove them // vvrInstance.setQuota(vvr.getQuota()); // vvrInstance.setInstanceCount(vvr.getInstanceCount()); return VvrsResourceJmxImpl.getVvrPojoFromMbeanProxy(vvrInstance); } @Override public final Response deleteVvr(final String ownerId) { final UUID ownerUuid = InputValidation.getUuidFromString(ownerId); final VvrsTasksResourceJmxImpl taskResource = getParentResource().getVvrsTasksResource(); final String vvrUuid = vvrInstance.getUuid(); final String taskId; try { taskId = getParentResource().newVvrManagerProxy(ownerUuid).deleteNoWait(vvrUuid); } catch (final IllegalArgumentException e) { throw ClientErrorFactory.newBadRequestException(e.getMessage(), "Illegal argument to delete vvr", e); } catch (final Exception e) { throw ServerErrorFactory.newInternalErrorException("Failed to delete vvr", "Exception delete vvr", e); } final URI taskUri = taskResource.constructTaskUri(taskId); return Response.status(Status.ACCEPTED).location(taskUri).build(); } @Override public final RootSnapshotResource getRootSnapshotResource(final String ownerId) throws CustomResourceException { final UUID ownerUuid = InputValidation.getUuidFromString(ownerId); final UUID vvrUuid = UUID.fromString(vvrInstance.getUuid()); final MBeanServerConnection jmxConnection = getParentResource().getConnection(); final ObjectName rootSnapName; try { final Set<ObjectName> foundNames = jmxConnection.queryNames( VvrObjectNameFactory.newSnapshotQueryListObjectName(ownerUuid, vvrUuid), Query.eq(Query.attr("Uuid"), Query.attr("Parent"))); if (foundNames.isEmpty()) { return null; } rootSnapName = foundNames.iterator().next(); } catch (final IOException e) { LOGGER.error("Failed to query server for root snapshot", e); throw ServerErrorFactory.newInternalErrorException("Internal communication error", "Exception querying root snapshot", e); } final URI rootSnapshotResUri = UriBuilder.fromUri(resourceUri) .path(ResourcePath.extractPathForNewSubResource(uriInfo)).build(); return new RootSnapshotResourceJmxImpl(JMX.newMBeanProxy(jmxConnection, rootSnapName, SnapshotMXBean.class), this, rootSnapshotResUri); } @Override public final SnapshotsResource getSnapshotsResource() { final URI snapshotsResUri = UriBuilder.fromUri(getResourceUri()) .path(ResourcePath.extractPathForNewSubResource(uriInfo)).build(); final SnapshotsResourceJmxImpl result = new SnapshotsResourceJmxImpl(getParentResource(), snapshotsResUri); ResourcePath.injectUriInfoContext(uriInfo, result); return result; } @Override public final DevicesResource getDevicesResource() { final URI devicesResUri = UriBuilder.fromUri(getResourceUri()) .path(ResourcePath.extractPathForNewSubResource(uriInfo)).build(); final DevicesResourceJmxImpl result = new DevicesResourceJmxImpl(getParentResource(), devicesResUri); ResourcePath.injectUriInfoContext(uriInfo, result); return result; } @Override public final VvrStartResource getVvrStartResource(final String ownerId) { return new VvrStartResourceJmxImpl(); } @Override public final VvrStopResource getVvrStopResource(final String ownerId) { return new VvrStopResourceJmxImpl(); } @Override public final VvrTasksResourceJmxImpl getVvrTasksResource() { final URI taskResUri = UriBuilder.fromUri(resourceUri).path(tasksResourcePath).build(); final VvrTasksResourceJmxImpl vvrTasksRes = new VvrTasksResourceJmxImpl(taskResUri, getParentResource(), resourceUri, vvrInstance); return vvrTasksRes; } @Override protected final URI getResourceUri() { return resourceUri; } /** * @return the parentResource */ final VvrsResourceJmxImpl getParentResource() { if (parentResource == null) { parentResource = ResourcePath.extractAncestorFromMatchedResources(uriInfo, VvrsResourceJmxImpl.class); } return parentResource; } final String getVvrUuid() { return vvrInstance.getUuid(); } }