resource-manager-gcore/src/org/gcube/vremanagement/resourcemanager/impl/resources/ScopedDeployedService.java

398 lines
14 KiB
Java

package org.gcube.vremanagement.resourcemanager.impl.resources;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.gcube.common.core.resources.GCUBEService;
import org.gcube.common.core.scope.GCUBEScope;
import org.gcube.common.vremanagement.deployer.stubs.common.PackageInfo;
import org.gcube.vremanagement.resourcemanager.impl.deployment.SoftwareRepositoryRequest;
import org.gcube.vremanagement.resourcemanager.impl.deployment.VirtualNode;
import org.gcube.vremanagement.resourcemanager.impl.deployment.resources.Dependency;
import org.gcube.vremanagement.resourcemanager.impl.deployment.resources.Service;
import org.gcube.vremanagement.resourcemanager.impl.operators.Operator.ACTION;
/**
*
* Models a scoped {@link GCUBEService}
*
* @author Manuele Simi (ISTI-CNR)
*
*/
public final class ScopedDeployedService extends ScopedResource {
public static final String TYPE = GCUBEService.TYPE;
/** Target port-type name. */
protected static final String REPOSITORY_ENDPOINT = "gcube/vremanagement/softwarerepository/SoftwareRepository";
/** Target service name. */
protected static final String REPOSITORY_NAME = "SoftwareRepository";
/** Target service class. */
protected static final String REPOSITORY_CLASS = "VREManagement";
/** Timeout in millisecs for the channel with the Software Repository instance */
protected static final int TIMEOUT = 600000;
/** resolved dependencies */
private List<Dependency> resolved = new ArrayList<Dependency>();
/** missing dependency */
private List<Dependency> missing = new ArrayList<Dependency>();
/** the packages deployed for this service*/
private Map <String, List<Dependency>> node2packages = new HashMap<String, List<Dependency>>();
/** the packages deployed for this service*/
private Map <String, List<Dependency>> node2missing = new HashMap<String, List<Dependency>>();
private Service service;
private String lastActivityOnGHN;
//the target ghn(s)
private List<VirtualNode> virtualNodes = new ArrayList<VirtualNode>();
/** maps node with the scope used when deploying there */
private Map<String, String> node2scope = new HashMap<String, String>();
/** maps RI id with the ghn id (where the instance is deployed on*/
private Map<String, String> ri2ghn = new HashMap<String, String>();
protected ScopedDeployedService(String id, GCUBEScope scope) {
super(id, TYPE, scope);
}
public void setSourceServiceName(Service service) {
this.service = service;
}
public Service getSourceService() {
return this.service;
}
/**
* Gets the list of resolved dependencies when the deployment was performed
* on a specific node
*
* @param ghnid the ID of the node
* @return the resolved dependencies
*/
public List<Dependency> getResolvedDependencies(String ghnid) {
if (node2packages.get(ghnid) == null)
return Collections.emptyList();
return Collections.unmodifiableList(node2packages.get(ghnid));
}
/**
* Gets the list of resolved dependencies to be used in the next deployment
*
* @return the resolved dependencies
*/
public List<Dependency> getLastResolvedDependencies() {
return this.resolved;
}
/**
* Sets the list of resolved dependencies to be used in the next deployment
*
* @param dependencies the resolved dependencies
*/
public void setResolvedDependencies(List<Dependency> dependencies) {
this.resolved = dependencies;
}
/**
* Gets the list of missing dependencies when the deployment was performed
* on a specific node
*
* @param ghnid the ID of the node
* @return the missing dependencies
*/
public List<Dependency> getMissingDependencies(String ghnid) {
if (node2missing.get(ghnid) == null)
return Collections.emptyList();
return Collections.unmodifiableList(node2missing.get(ghnid));
}
/**
* Gets the list of missing dependencies for the last (failed) deployment
*
* @return the missing dependencies
*/
public List<Dependency> getLastMissingDependencies() {
return this.missing;
}
/**
* Sets the list of missing dependencies for the next deployment
*
* @param dependencies the missign dependencies
*/
public void setMissingDependencies(List<Dependency> dependencies) {
///this.getLogger().trace("Setting missing deps " + dependencies.size());
missing= dependencies;
}
@Override
protected void find() throws Exception {
//looks for the service and its deps in the Software Repository
SoftwareRepositoryRequest request = new SoftwareRepositoryRequest();
request.addService(this);
this.setErrorMessage(""); //empty any previous message
try {
request.send();
if (this.resolved.size() == 0) {
this.success = false;
this.setErrorMessage("Invalid list of dependecies retrieved from the Software Repository");
} else if (this.missing.size() > 0) {//ops, some deps are missing!
this.success = false;
this.setErrorMessage("The service cannot be deployed due to one or more missing dependencies: " + this.missing);
} else {
this.success = true;
}
} catch (Exception e) {
this.success= false;
this.setErrorMessage("Unable to resolve the list of dependencies for this service " + e.getMessage());
getLogger().error("Unable to resolve the list of deps for " + this.service, e);
throw new Exception("Unable to resolve the list of dependencies for " + this.service, e);
}
}
@Override
protected void addToScope() throws ResourceNotFound, Exception {
logger.trace("This service belongs to " + this.scope);
if (!this.isSuccess()) {
this.noHopeForMe(this.getErrorMessage(),new Exception());
}
if ((this.lastActivityOnGHN == null) || (this.lastActivityOnGHN.compareTo("")==0)) {
this.noHopeForMe("Unable to find a suitable target gHN where to deploy the service",new Exception());
}
this.action = ACTION.ADD;
this.setErrorMessage(""); //empty any previous message
Exception lastException = null;
//deploy the service
List<VirtualNode> nodesToRemove = new ArrayList<VirtualNode>();
for (VirtualNode node : this.virtualNodes) {
try {
node.deploy(this.getScope());
//store packages for future undeployment and reporting purposes
List<Dependency> resolvedPackages = new ArrayList<Dependency>();
for (Dependency dep : this.resolved)
resolvedPackages.add(dep);
node2packages.put(node.getID(), resolvedPackages);
//store missing packages for reporting purposes
List<Dependency> missingPackages = new ArrayList<Dependency>();
for (Dependency dep : this.missing)
missingPackages.add(dep);
if (node2missing == null) {
logger.trace("node2missing is null");
node2missing = new HashMap<String, List<Dependency>>(); // this is here for backwards compatibility
}
node2missing.put(node.getID(), missingPackages);
} catch (Exception e) {
nodesToRemove.add(node);
logger.error("Failed to deploy on " + node.getID(), e);
logger.info("Virtual Node " + node.toString() + " will be removed from the queue");
lastException=e;
}
}
this.missing.clear();
this.resolved.clear();
if (nodesToRemove.size() > 0 ) {
this.virtualNodes.removeAll(nodesToRemove);
this.noHopeForMe("Unable to contact the target gHN ("+ this.lastActivityOnGHN +") where to deploy the service",lastException);
}
}
@Override
protected void removeFromScope() throws ResourceNotFound, Exception {
logger.trace("This service belongs to " + this.scope);
if (!this.isSuccess()) {
//TODO: could we undeploy static packages here?
this.noHopeForMe(this.getErrorMessage(),new Exception());
}
if ((this.lastActivityOnGHN == null) || (this.lastActivityOnGHN.compareTo("")==0)) {
this.noHopeForMe("Unable to find a valid target gHN where to undeploy the service", new Exception());
}
this.setErrorMessage(""); //empty any previous message
//undeploy the service from all the virtual nodes where it was deployed (if any)
this.action = ACTION.REMOVE;
try {
for (VirtualNode node : this.virtualNodes) {
try {
if (node2scope.containsKey(node.getID()))
node.undeploy(GCUBEScope.getScope(node2scope.get(node.getID())));
else
node.undeploy(this.getScope()); //try the service's scope
} catch (Exception e) {
this.noHopeForMe("Failed to undeploy from "+ node ,e);
}
}
this.virtualNodes.clear();
} catch (Exception e) {
this.noHopeForMe("Unable to contact the target gHN ("+ this.lastActivityOnGHN +") where to undeploy the service, deployer says" + e.getMessage() ,e);
}
}
/**
* Schedules the undeployment of all the instances of this service from scope
*
* @throws Exception if the operation fails
*/
public void scheduleUndeploy() {
for (VirtualNode node : this.virtualNodes)
scheduleUndeploy(node);
}
/**
* Schedules the undeployment of an instance of this service from the node
*
* @param node the node from where to undeploy the service
* @throws Exception if the operation fails
*/
public void scheduleUndeploy(VirtualNode node) {
getLogger().info("Scheduling undeployment of service "+ this.service+ " from GHN " + this.lastActivityOnGHN);
//notify the node to operate in the scope previously used for the deployment
this.checkNode2Scope();
if (node2scope.containsKey(node.getID())) //it has to be in, but it couldn't if the service was deployed from a previous (version < 1.1)RM instance
node.setWorkingScope(GCUBEScope.getScope(node2scope.get(node.getID())));
//prepare the input list of packagesToAdd for that GHN
List<Dependency> deps = node2packages.get(node.getID());
if (deps == null)
return;
Set<PackageInfo> packages = new HashSet<PackageInfo>();
for (int i = 0; i < deps.size(); i++) {
PackageInfo p = new PackageInfo();
p.setServiceName(deps.get(i).getService().getName());
p.setServiceClass(deps.get(i).getService().getClazz());
p.setServiceVersion(deps.get(i).getService().getVersion());
p.setVersion(deps.get(i).getVersion());
p.setName(deps.get(i).getName());
getLogger().trace("Adding Package to undeployment request: " + deps.get(i));
packages.add(p);
}
node.setPackagesToRemove(packages);
this.lastActivityOnGHN = node.getID();
}
/**
* Undeploys any instances of this service from the given gHN
*
* @param lastActivityOnGHN the id of the gHN from where to undeploy the service
* @throws Exception
*/
public void removeFromScope(String ghnID) throws VirtualNode.NoGHNFoundException, Exception {
logger.trace("This service belongs to " + this.scope);
this.action = ACTION.REMOVE;
for (VirtualNode node : this.virtualNodes)
if (node.getID().compareToIgnoreCase(ghnID) == 0) {
checkNode2Scope();
if (node2scope.containsKey(ghnID))
node.undeploy(GCUBEScope.getScope(node2scope.get(ghnID)));
else
node.undeploy(this.getScope()); //try the service's scope
this.virtualNodes.remove(node);
return;
}
this.noHopeForMe("Unable to find the gHN with id " + this.lastActivityOnGHN +
" to undeploy the instance of the " + this.service, new VirtualNode.NoGHNFoundException(""));
}
/**
* Sets the GHN where the service will be deployed
*
* @param node the target GHN
*/
public void setTargetGHN(VirtualNode node) {
getLogger().info("Using GHN " + node.getID() + " for " + this);
Set<PackageInfo> packages = new HashSet<PackageInfo>();
//prepare the input list of packagesToAdd for that GHN
List<Dependency> deps = this.resolved;
for (int i = 0; i < deps.size(); i++) {
PackageInfo p = new PackageInfo();
p.setServiceName(deps.get(i).getService().getName());
p.setServiceClass(deps.get(i).getService().getClazz());
p.setServiceVersion(deps.get(i).getService().getVersion());
p.setVersion(deps.get(i).getVersion());
p.setName(deps.get(i).getName()); //packageName
getLogger().trace("Adding Package to deployment request: " + deps.get(i));
packages.add(p);
}
node.setPackagesToAdd(packages);
this.checkNode2Scope();//for backward compatibility (version <= 1.1)
node2scope.put(node.getID(), node.getWorkingScope().toString());
this.virtualNodes.add(node);
this.lastActivityOnGHN = node.getID();
}
/**
* Gets the ID of the target gHN
* @return the ID of the target gHN
*/
public String getTargetGHNID() {
return lastActivityOnGHN; //this.virtualNodes.size() > 0 ? this.virtualNodes.get(0).getID() : "";
}
/**
* Gets the ID of the target gHN
* @return the ID of the target gHN
*/
public String getTargetGHN() {
return this.virtualNodes.size() > 0 ? this.virtualNodes.get(0).getID() : "";
}
public void setRIonGHN(String ri, String ghn) {
this.ri2ghn.put(ri, ghn);
}
/**
* Sets the callback ID from now on for all the service's operations
* @param id the callback ID
*/
public void setCallbackID(String id) {
for (VirtualNode node : this.virtualNodes)
node.setCallbackID(id);
}
/**
* Gets the list of {@link VirtualNode}s where the service is actually deployed within this scope
* @return the list of {@link VirtualNode}s
*/
public List<VirtualNode> getNodes() {
return this.virtualNodes;
}
/**
* Number of times the resource is searched in the IS before to declare it lost
* @return the number of attempts to do
*/
@Override
protected int getMaxFindAttempts(){
return 3;
}
private void checkNode2Scope(){
//this is for backward compatibility, if the obj is loaded from an old serialization
//node2scope could not be initialized
if (this.node2scope == null)
this.node2scope = new HashMap<String, String>();
}
}