package org.ovirt.engine.api.restapi.resource; import java.util.List; import java.util.Set; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; import org.ovirt.engine.api.common.util.DetailHelper; import org.ovirt.engine.api.common.util.DetailHelper.Detail; import org.ovirt.engine.api.common.util.LinkHelper; import org.ovirt.engine.api.model.Action; import org.ovirt.engine.api.model.CdRom; import org.ovirt.engine.api.model.CdRoms; import org.ovirt.engine.api.model.Disk; import org.ovirt.engine.api.model.Disks; import org.ovirt.engine.api.model.NIC; import org.ovirt.engine.api.model.Nics; import org.ovirt.engine.api.model.Statistic; import org.ovirt.engine.api.model.Statistics; import org.ovirt.engine.api.model.Ticket; import org.ovirt.engine.api.model.VM; import org.ovirt.engine.core.common.VdcObjectType; import org.ovirt.engine.api.resource.ActionResource; import org.ovirt.engine.api.resource.AssignedPermissionsResource; import org.ovirt.engine.api.resource.AssignedTagsResource; import org.ovirt.engine.api.resource.CreationResource; import org.ovirt.engine.api.resource.DevicesResource; import org.ovirt.engine.api.resource.SnapshotsResource; import org.ovirt.engine.api.resource.StatisticsResource; import org.ovirt.engine.api.resource.VmResource; import org.ovirt.engine.api.restapi.resource.AbstractBackendResource.EntityIdResolver; import org.ovirt.engine.api.restapi.resource.AbstractBackendResource.QueryIdResolver; import org.ovirt.engine.core.common.action.ChangeVMClusterParameters; import org.ovirt.engine.core.common.action.HibernateVmParameters; import org.ovirt.engine.core.common.action.MigrateVmParameters; import org.ovirt.engine.core.common.action.MigrateVmToServerParameters; import org.ovirt.engine.core.common.action.MoveVmParameters; import org.ovirt.engine.core.common.action.RemoveVmFromPoolParameters; import org.ovirt.engine.core.common.action.RunVmOnceParams; import org.ovirt.engine.core.common.action.SetVmTicketParameters; import org.ovirt.engine.core.common.action.ShutdownVmParameters; import org.ovirt.engine.core.common.action.StopVmParameters; import org.ovirt.engine.core.common.action.StopVmTypeEnum; import org.ovirt.engine.core.common.action.VdcActionParametersBase; import org.ovirt.engine.core.common.action.VdcActionType; import org.ovirt.engine.core.common.action.VmManagementParametersBase; import org.ovirt.engine.core.common.action.VmOperationParameterBase; import org.ovirt.engine.core.common.businessentities.VDS; import org.ovirt.engine.core.common.businessentities.VDSGroup; import org.ovirt.engine.core.common.businessentities.storage_domains; import org.ovirt.engine.core.common.businessentities.VmStatic; import org.ovirt.engine.core.common.interfaces.SearchType; import org.ovirt.engine.core.common.queries.GetAllDisksByVmIdParameters; import org.ovirt.engine.core.common.queries.GetPermissionsForObjectParameters; import org.ovirt.engine.core.common.queries.GetVmByVmIdParameters; import org.ovirt.engine.core.common.queries.VdcQueryType; import org.ovirt.engine.core.compat.Guid; import static org.ovirt.engine.core.utils.Ticketing.GenerateOTP; import static org.ovirt.engine.api.restapi.resource.BackendVmsResource.SUB_COLLECTIONS; public class BackendVmResource extends AbstractBackendActionableResource<VM, org.ovirt.engine.core.common.businessentities.VM> implements VmResource { private static final long DEFAULT_TICKET_EXPIRY = 120 * 60; // 2 hours private BackendVmsResource parent; public BackendVmResource(String id, BackendVmsResource parent) { super(id, VM.class, org.ovirt.engine.core.common.businessentities.VM.class, SUB_COLLECTIONS); this.parent = parent; } @Override public VM get() { return performGet(VdcQueryType.GetVmByVmId, new GetVmByVmIdParameters(guid)); } @Override public VM update(VM incoming) { if (incoming.isSetCluster() && (incoming.getCluster().isSetId() || incoming.getCluster().isSetName())) { Guid clusterId = lookupClusterId(incoming); if(!clusterId.toString().equals(get().getCluster().getId())){ performAction(VdcActionType.ChangeVMCluster, new ChangeVMClusterParameters(clusterId, guid)); } } //if the user updated the host within placement-policy, but supplied host-name rather than the host-id (legal) - //resolve the host's ID, because it will be needed down the line if (incoming.isSetPlacementPolicy() && incoming.getPlacementPolicy().isSetHost() && incoming.getPlacementPolicy().getHost().isSetName() && !incoming.getPlacementPolicy().getHost().isSetId()) { incoming.getPlacementPolicy().getHost().setId(getHostId(incoming.getPlacementPolicy().getHost().getName())); } return performUpdate(incoming, new QueryIdResolver(VdcQueryType.GetVmByVmId, GetVmByVmIdParameters.class), VdcActionType.UpdateVm, new UpdateParametersProvider()); } private String getHostId(String hostName) { return getEntity(VDS.class, SearchType.VDS, "Hosts: name=" + hostName).getvds_id().toString(); } protected Guid lookupClusterId(VM vm) { return vm.getCluster().isSetId() ? asGuid(vm.getCluster().getId()) : getEntity(VDSGroup.class, SearchType.Cluster, "Cluster: name=" + vm.getCluster().getName()).getID(); } @Override public DevicesResource<CdRom, CdRoms> getCdRomsResource() { return inject(new BackendCdRomsResource(guid, VdcQueryType.GetVmByVmId, new GetVmByVmIdParameters(guid))); } @Override public DevicesResource<Disk, Disks> getDisksResource() { return inject(new BackendDisksResource(guid, VdcQueryType.GetAllDisksByVmId, new GetAllDisksByVmIdParameters(guid))); } @Override public DevicesResource<NIC, Nics> getNicsResource() { return inject(new BackendVmNicsResource(guid)); } @Override public SnapshotsResource getSnapshotsResource() { return inject(new BackendSnapshotsResource(guid)); } @Override public AssignedTagsResource getTagsResource() { return inject(new BackendVmTagsResource(id)); } @Override public AssignedPermissionsResource getPermissionsResource() { return inject(new BackendAssignedPermissionsResource(guid, VdcQueryType.GetPermissionsForObject, new GetPermissionsForObjectParameters(guid), VM.class, VdcObjectType.VM)); } @Override public CreationResource getCreationSubresource(String ids) { return inject(new BackendCreationResource(ids)); } @Override public ActionResource getActionSubresource(String action, String ids) { return inject(new BackendActionResource(action, ids)); } @Override public StatisticsResource getStatisticsResource() { EntityIdResolver resolver = new QueryIdResolver(VdcQueryType.GetVmByVmId, GetVmByVmIdParameters.class); VmStatisticalQuery query = new VmStatisticalQuery(resolver, newModel(id)); return inject(new BackendStatisticsResource<VM, org.ovirt.engine.core.common.businessentities.VM>(entityType, guid, query)); } @Override public Response migrate(Action action) { boolean forceMigration = action.isSetForce() ? action.isForce() : false; if (!action.isSetHost()) { return doAction(VdcActionType.MigrateVm, new MigrateVmParameters(forceMigration, guid), action); } else { return doAction(VdcActionType.MigrateVmToServer, new MigrateVmToServerParameters(forceMigration, guid, getHostId(action)), action); } } @Override public Response shutdown(Action action) { // REVISIT add waitBeforeShutdown Action paramater // to api schema before next sub-milestone return doAction(VdcActionType.ShutdownVm, new ShutdownVmParameters(guid, true), action); } @Override public Response start(Action action) { RunVmOnceParams params = new RunVmOnceParams(guid); if (action.isSetPause() && action.isPause()) { params.setRunAndPause(true); } if (action.isSetVm()) { VM vm = action.getVm(); if (vm.isSetPlacementPolicy() && vm.getPlacementPolicy().isSetHost()) { validateParameters(vm.getPlacementPolicy(), "host.id|name"); params.setDestinationVdsId(getHostId(vm.getPlacementPolicy().getHost())); } params = map(vm, params); } return doAction(VdcActionType.RunVmOnce, setReinitializeSysPrep(params), action); } private VdcActionParametersBase setReinitializeSysPrep(RunVmOnceParams params) { //REVISE when BE supports default val. for RunVmOnceParams.privateReinitialize org.ovirt.engine.core.common.businessentities.VM vm = getEntity(org.ovirt.engine.core.common.businessentities.VM.class, VdcQueryType.GetVmByVmId, new GetVmByVmIdParameters(guid), "VM"); if(vm.getvm_os().isWindows() && vm.getIsFirstRun()) { params.setReinitialize(true); } return params; } @Override public Response stop(Action action) { return doAction(VdcActionType.StopVm, new StopVmParameters(guid, StopVmTypeEnum.NORMAL), action); } @Override public Response suspend(Action action) { return doAction(VdcActionType.HibernateVm, new HibernateVmParameters(guid), action); } @Override public Response detach(Action action) { return doAction(VdcActionType.RemoveVmFromPool, new RemoveVmFromPoolParameters(guid), action); } @Override public Response export(Action action) { validateParameters(action, "storageDomain.id|name"); MoveVmParameters params = new MoveVmParameters(guid, getStorageDomainId(action)); if (action.isSetExclusive() && action.isExclusive()) { params.setForceOverride(true); } if (action.isSetDiscardSnapshots() && action.isDiscardSnapshots()) { params.setCopyCollapse(true); } return doAction(VdcActionType.ExportVm, params, action); } @Override public Response move(Action action) { validateParameters(action, "storageDomain.id|name"); return doAction(VdcActionType.MoveVm, new MoveVmParameters(guid, getStorageDomainId(action)), action); } protected Guid getStorageDomainId(Action action) { if (action.getStorageDomain().isSetId()) { return asGuid(action.getStorageDomain().getId()); } else { return lookupStorageDomainIdByName(action.getStorageDomain().getName()); } } protected Guid lookupStorageDomainIdByName(String name) { return getEntity(storage_domains.class, SearchType.StorageDomain, "Storage: name=" + name).getid(); } @Override public Response ticket(Action action) { return doAction(VdcActionType.SetVmTicket, new SetVmTicketParameters(guid, getTicketValue(action), getTicketExpiry(action)), action); } protected String getTicketValue(Action action) { if (!ensureTicket(action).isSetValue()) { action.getTicket().setValue(GenerateOTP()); } return action.getTicket().getValue(); } protected int getTicketExpiry(Action action) { if (!ensureTicket(action).isSetExpiry()) { action.getTicket().setExpiry(DEFAULT_TICKET_EXPIRY); } return action.getTicket().getExpiry().intValue(); } protected Ticket ensureTicket(Action action) { if (!action.isSetTicket()) { action.setTicket(new Ticket()); } return action.getTicket(); } protected RunVmOnceParams map(VM vm, RunVmOnceParams params) { return getMapper(VM.class, RunVmOnceParams.class).map(vm, params); } @Override protected VM populate(VM model, org.ovirt.engine.core.common.businessentities.VM entity) { Set<Detail> details = DetailHelper.getDetails(getHttpHeaders()); parent.addInlineDetails(details, model); addStatistics(model, entity, uriInfo, httpHeaders); return model; } VM addStatistics(VM model, org.ovirt.engine.core.common.businessentities.VM entity, UriInfo ui, HttpHeaders httpHeaders) { if (DetailHelper.include(httpHeaders, "statistics")) { model.setStatistics(new Statistics()); VmStatisticalQuery query = new VmStatisticalQuery(newModel(model.getId())); List<Statistic> statistics = query.getStatistics(entity); for (Statistic statistic : statistics) { LinkHelper.addLinks(ui, statistic, query.getParentType()); } model.getStatistics().getStatistics().addAll(statistics); } return model; } protected class UpdateParametersProvider implements ParametersProvider<VM, org.ovirt.engine.core.common.businessentities.VM> { @Override public VdcActionParametersBase getParameters(VM incoming, org.ovirt.engine.core.common.businessentities.VM entity) { VmStatic updated = getMapper(modelType, VmStatic.class).map(incoming, entity.getStaticData()); return new VmManagementParametersBase(updated); } } @Override public Response cancelMigration(Action action) { return doAction(VdcActionType.CancelMigrateVm, new VmOperationParameterBase(guid), action); } }