398 lines
14 KiB
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>();
|
|
}
|
|
}
|