/** * @param deployment the deployment from which create the jobs * @param jobgraph the graph of the jobs * @param templateTopologicalOrderIterator the topological order iterator of the jobs * @param client the Chronos client to use * @return <tt>true</tt> if the currently checked node is ready, <tt>false</tt> if still in * progress. * @throws DeploymentException if the currently node failed. */ protected boolean checkJobsOnChronosIteratively( Deployment deployment, Map<String, IndigoJob> jobgraph, TemplateTopologicalOrderIterator templateTopologicalOrderIterator, Chronos client) throws DeploymentException { // Get current job Resource currentNode = templateTopologicalOrderIterator.getCurrent(); IndigoJob job = jobgraph.get(currentNode.getToscaNodeName()); String jobName = job.getChronosJob().getName(); Job updatedJob = getJobStatus(client, jobName); if (updatedJob == null) { String errorMsg = String.format( "Failed to deploy deployment <%s>. Chronos job <%s> (id: <%s>) does not exist", deployment.getId(), job.getToscaNodeName(), jobName); LOG.error(errorMsg); // Update job status updateResource(deployment, job, NodeStates.ERROR); throw new DeploymentException(errorMsg); } JobState jobState = getLastState(updatedJob); LOG.debug( "Status of Chronos job <{}> for deployment <{}> is <{}> ({}/{})", jobName, deployment.getId(), jobState, templateTopologicalOrderIterator.getPosition() + 1, templateTopologicalOrderIterator.getNodeSize()); // Go ahead only if the job succeeded if (jobState != JobState.SUCCESS) { if (jobState != JobState.FAILURE) { // Job still in progress LOG.debug("Polling again job <{}> for deployment <{}>", jobName, deployment.getId()); return false; } else { // Job failed -> Deployment failed! String errorMsg = String.format( "Failed to deploy deployment <%s>. Chronos job <%s> (id: <%s>) status is <%s>", deployment.getId(), job.getToscaNodeName(), jobName, jobState); LOG.error(errorMsg); // Update job status updateResource(deployment, job, NodeStates.ERROR); currentNode.setState(NodeStates.ERROR); throw new DeploymentException(errorMsg); } } else { // Job finished -> Update job status updateResource(deployment, job, NodeStates.STARTED); currentNode.setState(NodeStates.STARTED); return true; } }
private void updateResource(Deployment deployment, IndigoJob job, NodeStates state) { // Find the Resource from DB Resource resource = resourceRepository.findByToscaNodeNameAndDeployment_id( job.getToscaNodeName(), deployment.getId()); resource.setState(state); // resourceRepository.save(resource); }
/** * Deletes all the jobs from Chronos. * * @param jobgraph the job graph. * @param client the {@link Chronos} client. * @param failAtFirst if <tt>true</tt> throws an exception at the first job deletion error, * otherwise it tries to delete every other job. * @return <tt>true</tt> if all jobs have been deleted, <tt>false</tt> otherwise. */ protected boolean deleteJobsOnChronosIteratively( Deployment deployment, Map<String, IndigoJob> jobgraph, TemplateTopologicalOrderIterator templateTopologicalOrderIterator, Chronos client, boolean failAtFirst) { Resource currentNode = templateTopologicalOrderIterator.getCurrent(); if (currentNode == null) { return false; } IndigoJob currentJob = jobgraph.get(currentNode.getToscaNodeName()); boolean failed = false; // Delete current job (all jobs iteratively) try { try { updateResource(deployment, currentJob, NodeStates.DELETING); currentNode.setState(NodeStates.DELETING); String jobName = currentJob.getChronosJob().getName(); client.deleteJob(jobName); LOG.debug( "Deleted Chronos job <{}> for deployment <{}> ({}/{})", jobName, deployment.getId(), templateTopologicalOrderIterator.getPosition() + 1, templateTopologicalOrderIterator.getNodeSize()); } catch (ChronosException ce) { // Chronos API hack (to avoid error 400 if the job to delete does not exist) if (ce.getStatus() != 400 && ce.getStatus() != 404) { throw new RuntimeException(String.format("Status Code: <%s>", ce.getStatus())); } } } catch (Exception ex) { // Just log the error String errorMsg = String.format("Failed to delete job <%s> on Chronos: %s", ex.getMessage()); LOG.error(errorMsg); failed = true; // Update job status updateResource(deployment, currentJob, NodeStates.ERROR); currentNode.setState(NodeStates.ERROR); // Only throw exception if required if (failAtFirst) { // TODO use a custom exception ? throw new RuntimeException(errorMsg); } } return !failed; }
/** * @param deployment the deployment from which create the jobs * @param jobgraph the graph of the jobs * @param templateTopologicalOrderIterator the topological order iterator of the jobs * @param client the Chronos client to use * @return <tt>true</tt> if there are more nodes to create, <tt>false</tt> otherwise. */ protected boolean createJobsOnChronosIteratively( Deployment deployment, Map<String, IndigoJob> jobgraph, TemplateTopologicalOrderIterator templateTopologicalOrderIterator, Chronos client) { // Create Jobs in the required order on Chronos Resource currentNode = templateTopologicalOrderIterator.getCurrent(); if (currentNode == null) { return false; } IndigoJob currentJob = jobgraph.get(currentNode.getToscaNodeName()); // Create jobs based on the topological order try { String nodeTypeMsg; if (currentJob.getParents().isEmpty()) { // Scheduled job (not dependent) nodeTypeMsg = "scheduled"; client.createJob(currentJob.getChronosJob()); } else { // Dependent job nodeTypeMsg = String.format("parents <%s>", currentJob.getChronosJob().getParents()); client.createDependentJob(currentJob.getChronosJob()); } LOG.debug( "Created job for deployment <{}> on Chronos: name <{}>, {} ({}/{})", deployment.getId(), currentJob.getChronosJob().getName(), nodeTypeMsg, templateTopologicalOrderIterator.getPosition() + 1, templateTopologicalOrderIterator.getNodeSize()); // Update job status updateResource(deployment, currentJob, NodeStates.CREATED); // The node in the iterator is not actually an entity (serialization issues) currentNode.setState(NodeStates.CREATED); } catch (ChronosException exception) { // Chronos job launch error // Update job status updateResource(deployment, currentJob, NodeStates.ERROR); currentNode.setState(NodeStates.ERROR); // TODO use a custom exception ? throw new RuntimeException( String.format( "Failed to launch job <%s> on Chronos. Status Code: <%s>", currentJob.getChronosJob().getName(), exception.getStatus())); } return templateTopologicalOrderIterator.getNext() != null; }
protected Job createJob( Map<String, NodeTemplate> nodes, String deploymentId, String nodeName, NodeTemplate nodeTemplate, Map<String, Resource> resources) { try { Job chronosJob = new Job(); // Init job infos // Get the generated UUID for the node (in DB resource ?) // FIXME This is just for prototyping... Otherwise is madness!! Resource resourceJob = resources.get(nodeName); chronosJob.setName(resourceJob.getId()); // TODO Validation chronosJob.setRetries( Integer.parseInt( (String) toscaService.getNodePropertyValueByName(nodeTemplate, "retries").getValue())); chronosJob.setCommand( (String) toscaService.getNodePropertyValueByName(nodeTemplate, "command").getValue()); // TODO Enable epsilon setting in TOSCA tplt ? chronosJob.setEpsilon("PT10S"); ListPropertyValue inputUris = (ListPropertyValue) toscaService.getNodePropertyValueByName(nodeTemplate, "uris"); if (inputUris != null && !inputUris.getValue().isEmpty()) { // Convert List<Object> to List<String> chronosJob.setUris( inputUris .getValue() .stream() .map(e -> ((PropertyValue<?>) e).getValue().toString()) .collect(Collectors.toList())); } List<EnvironmentVariable> envs = new ArrayList<>(); ComplexPropertyValue inputEnvVars = ((ComplexPropertyValue) toscaService.getNodePropertyValueByName(nodeTemplate, "environment_variables")); if (inputEnvVars != null) { for (Map.Entry<String, Object> var : inputEnvVars.getValue().entrySet()) { EnvironmentVariable envVar = new EnvironmentVariable(); envVar.setName(var.getKey()); envVar.setValue(((PropertyValue<?>) var.getValue()).getValue().toString()); envs.add(envVar); } chronosJob.setEnvironmentVariables(envs); } // Docker image // TODO Remove hard-coded? String supportedType = "tosca.artifacts.Deployment.Image.Container.Docker"; DeploymentArtifact image; // <image> artifact available if (nodeTemplate.getArtifacts() == null || (image = nodeTemplate.getArtifacts().get("image")) == null) { throw new IllegalArgumentException( String.format( "<image> artifact not found in node <%s> of type <%s>", nodeName, nodeTemplate.getType())); } // <image> artifact type check if (!image.getArtifactType().equals(supportedType)) { throw new IllegalArgumentException( String.format( "Unsupported artifact type for <image> artifact in node <%s> of type <%s>. " + "Given <%s>, supported <%s>", nodeName, nodeTemplate.getType(), nodeTemplate.getArtifacts().get("image").getArtifactType(), supportedType)); } // Requirements // Get Docker host dependency String dockerCapabilityName = "host"; Map<String, NodeTemplate> dockerRelationships = toscaService.getAssociatedNodesByCapability(nodes, nodeTemplate, dockerCapabilityName); Double dockerNumCpus = null; Double dockerMemSize = null; if (!dockerRelationships.isEmpty()) { /* * WARNING: The TOSCA validation should already check the limits (currently Alien4Cloud does * not...) */ NodeTemplate dockerNode = dockerRelationships.values().iterator().next(); Capability dockerCapability = dockerNode.getCapabilities().get(dockerCapabilityName); dockerNumCpus = Double.parseDouble( (String) toscaService .getCapabilityPropertyValueByName(dockerCapability, "num_cpus") .getValue()); // Converting Memory Size (as TOSCA scalar-unit.size) SizeType tmp = new SizeType(); String memSizeRaw = (String) toscaService .getCapabilityPropertyValueByName(dockerCapability, "mem_size") .getValue(); dockerMemSize = tmp.parse(memSizeRaw).convert("MB"); // Chronos wants MB } Container container = new Container(); container.setType("DOCKER"); // Run the container in Privileged Mode Parameters param = new Parameters(); param.setKey("privileged"); param.setValue("true"); Collection<Parameters> parameters = new ArrayList<Parameters>(); parameters.add(param); container.setParameters(parameters); // FIXME ForcePullImage must be parametrizable by tosca template container.setForcePullImage(true); //////////////////////////////////////////////////////////////// container.setImage( (String) ((PropertyValue<?>) nodeTemplate.getArtifacts().get("image").getFile()).getValue()); if (dockerNumCpus != null) { chronosJob.setCpus(dockerNumCpus); } if (dockerMemSize != null) { chronosJob.setMem(dockerMemSize); } chronosJob.setContainer(container); return chronosJob; } catch (Exception ex) { throw new RuntimeException( String.format( "Failed to parse node <%s> of type <%s>: %s", nodeName, nodeTemplate.getType(), ex.getMessage()), ex); } }