diff --git a/src/main/java/org/etsi/osl/osom/management/AutomationCheck.java b/src/main/java/org/etsi/osl/osom/management/AutomationCheck.java index e55f373090fcbafedcd507391daf4f1540654c2e..0f5d87517edb4f2d73a2487ab040f6d7e2ed75b0 100644 --- a/src/main/java/org/etsi/osl/osom/management/AutomationCheck.java +++ b/src/main/java/org/etsi/osl/osom/management/AutomationCheck.java @@ -88,8 +88,10 @@ public class AutomationCheck implements JavaDelegate { } else if ( spec.getType().equals("ResourceFacingServiceSpecification") && ( spec.findSpecCharacteristicByName( "OSM_NSDCATALOGID" ) != null ) ) { execution.setVariable("brokeActivity", "RFS_OSM" ); } else if ( spec.getType().equals("ResourceFacingServiceSpecification") && ( spec.findSpecCharacteristicByName( "_CR_SPEC" ) != null ) ) { - execution.setVariable("brokeActivity", "RFS_CRSPEC" ); - } else if ( spec.getType().equals("ResourceFacingServiceSpecification") ) { + execution.setVariable("brokeActivity", "RFS_CRSPEC" ); + } else if ( spec.getType().equals("ResourceFacingServiceSpecification") && ( spec.findSpecCharacteristicByName( "_MT_QUERY" ) != null ) ) { + execution.setVariable("brokeActivity", "RFS_MTSPEC" ); + } else if ( spec.getType().equals("ResourceFacingServiceSpecification") ) { execution.setVariable("brokeActivity", "GRSPEC" ); } } diff --git a/src/main/java/org/etsi/osl/osom/management/MetricoOrchestrationCheckDeploymentService.java b/src/main/java/org/etsi/osl/osom/management/MetricoOrchestrationCheckDeploymentService.java new file mode 100644 index 0000000000000000000000000000000000000000..8809c08d663d564d9efca7ae97eb55250cf0f91b --- /dev/null +++ b/src/main/java/org/etsi/osl/osom/management/MetricoOrchestrationCheckDeploymentService.java @@ -0,0 +1,95 @@ +package org.etsi.osl.osom.management; + +import jakarta.validation.Valid; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.etsi.osl.tmf.common.model.service.Note; +import org.etsi.osl.tmf.common.model.service.ResourceRef; +import org.etsi.osl.tmf.common.model.service.ServiceStateType; +import org.etsi.osl.tmf.ri639.model.Resource; +import org.etsi.osl.tmf.sim638.model.Service; +import org.etsi.osl.tmf.sim638.model.ServiceUpdate; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.delegate.JavaDelegate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.util.ArrayList; +import java.util.List; + +@Component(value = "metricoOrchestrationCheckDeploymentService") +public class MetricoOrchestrationCheckDeploymentService implements JavaDelegate { + private static final transient Log logger = LogFactory.getLog(MetricoOrchestrationCheckDeploymentService.class.getName()); + + @Autowired + private ServiceOrderManager serviceOrderManager; + + + @Value("${spring.application.name}") + private String compname; + + @Override + public void execute(DelegateExecution execution) { + + logger.info( "MetricoOrchestrationCheckDeploymentService" ); + logger.info( execution.getVariableNames().toString() ); + + if ( execution.getVariable("contextServiceId") == null) { + + logger.error( "Variable contextServiceId is NULL!" ); + execution.setVariable("serviceDeploymentFinished", Boolean.TRUE ); + return; + } + Service aService = serviceOrderManager.retrieveService( (String) execution.getVariable("contextServiceId") ); + + if ( aService == null ) { + logger.info( "aService is null for contextServiceId = " +(String) execution.getVariable("contextServiceId") ); + execution.setVariable("serviceDeploymentFinished", Boolean.TRUE ); + return; + } + + execution.setVariable("serviceDeploymentFinished", Boolean.FALSE ); + ServiceUpdate supd = new ServiceUpdate(); + boolean propagateToSO = false; + + List rlist = new ArrayList(); + for (ResourceRef rref : aService.getSupportingResource()) { + Resource res = serviceOrderManager.retrieveResource(rref.getId()); + + if ( res == null ) { + supd.setState( ServiceStateType.TERMINATED); + execution.setVariable("serviceDeploymentFinished", Boolean.TRUE); + Service serviceResult = serviceOrderManager.updateService( aService.getId(), supd, propagateToSO ); + return; + } + rlist.add(res); + } + @Valid + ServiceStateType currentState = aService.getState(); + ServiceStateType nextState = aService.findNextStateBasedOnResourceList(rlist); + + if (!currentState.equals(nextState)) { + supd.setState( nextState ); + Note n = new Note(); + n.setText("Service Status Changed to: " + nextState); + n.setAuthor(compname); + n.setDate(OffsetDateTime.now(ZoneOffset.UTC).toString()); + supd.addNoteItem(n); + aService = serviceOrderManager.updateService( aService.getId(), supd, propagateToSO ); + } + + if ( aService!= null ) { + if ( aService.getState().equals(ServiceStateType.ACTIVE) + || aService.getState().equals(ServiceStateType.TERMINATED)) { + + logger.info("Deployment Status OK. Service state = " + aService.getState() ); + execution.setVariable("serviceDeploymentFinished", Boolean.TRUE); + return; + } + } + logger.info("Wait For Deployment Status. "); + } +} diff --git a/src/main/java/org/etsi/osl/osom/management/MetricoOrchestrationService.java b/src/main/java/org/etsi/osl/osom/management/MetricoOrchestrationService.java new file mode 100644 index 0000000000000000000000000000000000000000..5aeac40e7a92eb8fcc4b1b984e01b0cdc1ecc3d5 --- /dev/null +++ b/src/main/java/org/etsi/osl/osom/management/MetricoOrchestrationService.java @@ -0,0 +1,266 @@ +package org.etsi.osl.osom.management; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.camel.ProducerTemplate; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.etsi.osl.tmf.common.model.service.Characteristic; +import org.etsi.osl.tmf.common.model.service.Note; +import org.etsi.osl.tmf.common.model.service.ResourceRef; +import org.etsi.osl.tmf.common.model.service.ServiceStateType; +import org.etsi.osl.tmf.common.model.Any; +import org.etsi.osl.tmf.pm628.model.*; +import org.etsi.osl.tmf.rcm634.model.ResourceSpecificationRef; +import org.etsi.osl.tmf.ri639.model.Resource; +import org.etsi.osl.tmf.ri639.model.ResourceCreate; +import org.etsi.osl.tmf.ri639.model.ResourceStatusType; +import org.etsi.osl.tmf.scm633.model.ServiceSpecification; +import org.etsi.osl.tmf.sim638.model.Service; +import org.etsi.osl.tmf.sim638.model.ServiceUpdate; +import org.etsi.osl.tmf.so641.model.ServiceOrder; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.delegate.JavaDelegate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.ArrayList; +import java.util.List; + +@Component(value = "metricoOrchestrationService") //bean name +public class MetricoOrchestrationService implements JavaDelegate { + + private static final transient Log logger = LogFactory.getLog(MetricoOrchestrationService.class.getName()); + + + + @Value("${spring.application.name}") + private String compname; + + + @Autowired + private ServiceOrderManager serviceOrderManager; + + + @Override + public void execute(DelegateExecution execution) { + ServiceOrder sorder = serviceOrderManager.retrieveServiceOrder(execution.getVariable("orderid").toString()); + ServiceUpdate su = new ServiceUpdate();// the object to update the service + Service aService = serviceOrderManager.retrieveService((String) execution.getVariable("contextServiceId")); + logger.info("Service name:" + aService.getName()); + logger.info("Service state:" + aService.getState()); + logger.info("Request to TMF628 for Service: " + aService.getId()); + + + ServiceSpecification spec = serviceOrderManager.retrieveServiceSpec(aService.getServiceSpecificationRef().getId()); + + if (spec != null) { + + Characteristic serviceCharacteristic; + MeasurementCollectionJobFVO mcjFVO = new MeasurementCollectionJobFVO(); + mcjFVO.setCreationTime( OffsetDateTime.now()); + mcjFVO.setLastModifiedTime( OffsetDateTime.now()); + + mcjFVO.setProducingApplicationId(aService.getId()); + + serviceCharacteristic = aService.getServiceCharacteristicByName("_MT_CHARACTERISTIC_NAME"); + String characteristicName = String.valueOf(serviceCharacteristic.getValue().getValue()); + mcjFVO.setOutputFormat(characteristicName); + + serviceCharacteristic = aService.getServiceCharacteristicByName("_MT_SERVICEUUID"); + String cfs_id = String.valueOf(serviceCharacteristic.getValue().getValue()); + mcjFVO.setConsumingApplicationId(cfs_id); + + serviceCharacteristic = aService.getServiceCharacteristicByName("_MT_END_TIME"); + String endTimeString = String.valueOf(serviceCharacteristic.getValue().getValue()); + ScheduleDefinitionFVO scheduleDefinition = new ScheduleDefinitionFVO(); + if (endTimeString != null && !endTimeString.equals("")) { + OffsetDateTime endTime = convertStringToOffsetDateTime(endTimeString, DateTimeFormat.ISO.DATE_TIME ); + scheduleDefinition.setScheduleDefinitionEndTime(endTime); + } else{ + OffsetDateTime endTime = OffsetDateTime.now().plusHours(1); + scheduleDefinition.setScheduleDefinitionEndTime(endTime); + } + + serviceCharacteristic = aService.getServiceCharacteristicByName("_MT_START_TIME"); + String startTimeString = String.valueOf(serviceCharacteristic.getValue().getValue()); + if (startTimeString != null&& !startTimeString.equals("")) { + OffsetDateTime startTime = convertStringToOffsetDateTime(startTimeString, DateTimeFormat.ISO.DATE_TIME ); + scheduleDefinition.setScheduleDefinitionStartTime(startTime); + } else{ + OffsetDateTime startTime = OffsetDateTime.now(); + scheduleDefinition.setScheduleDefinitionStartTime(startTime); + } + List scheduleDefinitions = new ArrayList<>(); + scheduleDefinitions.add(scheduleDefinition); + mcjFVO.setScheduleDefinition(scheduleDefinitions); + + serviceCharacteristic = aService.getServiceCharacteristicByName("_MT_RECURRING_INTERVAL"); + String recurringIntervalString = String.valueOf(serviceCharacteristic.getValue().getValue()); + if (recurringIntervalString != null) { + if (Granularity.contains(recurringIntervalString)){ + Granularity recurringInterval = Granularity.valueOf(recurringIntervalString.toUpperCase()); + mcjFVO.setGranularity(recurringInterval); + } else { + logger.error("Invalid _MT_RECURRING_INTERVAL value. Valid values are:" + Granularity.getPossibleValues() + " It will be set to 1 minute."); + Granularity recurringInterval = Granularity.G_1MN; + mcjFVO.setGranularity(recurringInterval); + } + } else { + Granularity recurringInterval = Granularity.G_1MN; + mcjFVO.setGranularity(recurringInterval); + } + + serviceCharacteristic = aService.getServiceCharacteristicByName("_MT_TYPE"); + String monitoringType = String.valueOf(serviceCharacteristic.getValue().getValue()); + DataAccessEndpointFVO dataAccessEndpoint = new DataAccessEndpointFVO(); + dataAccessEndpoint.setApiType(monitoringType); + + serviceCharacteristic = aService.getServiceCharacteristicByName("_MT_QUERY"); + String monitoringQuery = String.valueOf(serviceCharacteristic.getValue().getValue()); + serviceCharacteristic = aService.getServiceCharacteristicByName("_MT_URL"); + String monitoringURL = String.valueOf(serviceCharacteristic.getValue().getValue()); + try { + URI monitoringURI = createUri(monitoringURL, monitoringQuery); + dataAccessEndpoint.setUri(monitoringURI); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + + List dataAccessEndpoints = new ArrayList<>(); + dataAccessEndpoints.add(dataAccessEndpoint); + mcjFVO.setDataAccessEndpoint(dataAccessEndpoints); + + MeasurementCollectionJob mcj = serviceOrderManager.addMeasurementCollectionJob(mcjFVO); + + if (mcj != null){ + + ResourceSpecificationRef resourceSpecificationRef = spec.getResourceSpecification().stream().findFirst().get(); + Resource resourceMT = createRelatedResource( resourceSpecificationRef, sorder, aService, mcj ); + ResourceRef resourceRef = new ResourceRef(); + + resourceRef.setId( resourceMT.getId() ); + resourceRef.setName( resourceMT.getName()); + resourceRef.setType( resourceMT.getType()); + su.addSupportingResourceItem( resourceRef ); + su.setState(ServiceStateType.RESERVED); + Note successNoteItem = new Note(); + successNoteItem.setText(String.format("Requesting METRICO to create a new monitoring job")); + successNoteItem.setDate(OffsetDateTime.now(ZoneOffset.UTC).toString()); + successNoteItem.setAuthor(compname); + su.addNoteItem(successNoteItem); + + } else { + logger.error("Measurement Collection Job was not created."); + su.setState(ServiceStateType.TERMINATED); + } + + Service supd = serviceOrderManager.updateService(aService.getId(), su, false); + + + + } + } + + + + + +// Methods created to use in this class + public static OffsetDateTime convertStringToOffsetDateTime(String dateTimeString, DateTimeFormat.ISO pattern) { + DateTimeFormatter formatter; + switch (pattern) { + case DATE: + formatter = DateTimeFormatter.ISO_DATE; + break; + case TIME: + formatter = DateTimeFormatter.ISO_TIME; + break; + case DATE_TIME: + formatter = DateTimeFormatter.ISO_DATE_TIME; + break; + default: + throw new IllegalArgumentException("Unsupported DateTimeFormat.ISO pattern"); + } + try { + OffsetDateTime.parse(dateTimeString, formatter); + return OffsetDateTime.parse(dateTimeString, formatter); + } catch (DateTimeParseException e) { + logger.error(e.getMessage()); + return null; + } + + } + + public static URI createUri(String url, String query) throws URISyntaxException { + return new URI(url + "?" + query); + } + + public static T toJsonObj(String content, Class valueType) throws IOException { + ObjectMapper mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + return mapper.readValue( content, valueType); + } + + public static String toJsonString(T object) { + ObjectMapper mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + try { + return mapper.writeValueAsString(object); + } catch (JsonProcessingException e) { + e.printStackTrace(); + return null; + } + } + + + + /** + * + * The resource maps the created MCJ + * @param rSpecRef + * @param sOrder + * @param aService + * @return + */ + private Resource createRelatedResource(ResourceSpecificationRef rSpecRef, ServiceOrder sOrder, Service aService, MeasurementCollectionJob mcj) { + + ResourceCreate resCreate = new ResourceCreate(); + resCreate.setName( rSpecRef.getName() + "-" + aService.getId() ); + resCreate.setStartOperatingDate( aService.getStartDate() ); + resCreate.setEndOperatingDate(aService.getEndDate()); + resCreate.setResourceStatus (ResourceStatusType.RESERVED); + + ResourceSpecificationRef rSpecRefObj = new ResourceSpecificationRef() ; + rSpecRefObj.id(rSpecRef.getId()) + .name( rSpecRef.getName()) + .setType(rSpecRef.getType()); + resCreate.setResourceSpecification(rSpecRefObj); + + org.etsi.osl.tmf.ri639.model.Characteristic resCharacteristicItem = new org.etsi.osl.tmf.ri639.model.Characteristic(); + resCharacteristicItem.setName( "_MT_MCJ_REF" ); + resCharacteristicItem.setValueType( "TEXT" ); + Any val = new Any(); + val.setValue( mcj.getUuid() ); + val.setAlias( mcj.getUuid() ); + resCharacteristicItem.setValue( val ); + resCreate.addResourceCharacteristicItem( resCharacteristicItem ); + + + // 1) need to copy the characteristics of the Resource Specification (use this instead of @param rSpecRef) and populate them with value from the aService (see GCOrchestrationService) + // 2) also need to populate the characteristic _MT_MCJ_REF with the UUID of the created MCJ / pass it as @param mcj + + return serviceOrderManager.createResource( resCreate, sOrder, rSpecRef.getId() ); + } + +} diff --git a/src/main/java/org/etsi/osl/osom/management/ServiceOrderManager.java b/src/main/java/org/etsi/osl/osom/management/ServiceOrderManager.java index 4d794094b5595c6a248cb197dd74612c8c5b45ec..54bc509931a98b683ede8b543afa2c023a7af1a4 100644 --- a/src/main/java/org/etsi/osl/osom/management/ServiceOrderManager.java +++ b/src/main/java/org/etsi/osl/osom/management/ServiceOrderManager.java @@ -35,6 +35,8 @@ import org.etsi.osl.model.nfv.DeploymentDescriptor; import org.etsi.osl.model.nfv.NetworkServiceDescriptor; import org.etsi.osl.model.nfv.ScaleDescriptor; import org.etsi.osl.osom.serviceactions.NSActionRequestPayload; +import org.etsi.osl.tmf.pm628.model.MeasurementCollectionJob; +import org.etsi.osl.tmf.pm628.model.MeasurementCollectionJobFVO; import org.etsi.osl.tmf.pm632.model.Organization; import org.etsi.osl.tmf.rcm634.model.LogicalResourceSpecification; import org.etsi.osl.tmf.rcm634.model.ResourceSpecification; @@ -194,7 +196,11 @@ public class ServiceOrderManager { @Value("${CATALOG_GET_RESOURCESPEC_BY_ID}") private String CATALOG_GET_RESOURCESPEC_BY_ID = ""; - + + @Value("${PM_MEASUREMENT_COLLECTION_JOB_ADD}") + private String PM_MEASUREMENT_COLLECTION_JOB_ADD = ""; + + @Transactional public void processOrder(ServiceOrder serviceOrder) { @@ -1141,6 +1147,27 @@ public class ServiceOrderManager { return null; } + + public MeasurementCollectionJob addMeasurementCollectionJob(MeasurementCollectionJobFVO mcjFVO) { + + logger.debug("Will create a new Measurement Collection Job"); + try { + Object response = template. + requestBody( PM_MEASUREMENT_COLLECTION_JOB_ADD, toJsonString(mcjFVO)); + if ( !(response instanceof String)) { + logger.error("Measurement Collection Job object is wrong."); + return null; + } + logger.debug("retrieveMeasurementCollectionJobById response is: " + response); + MeasurementCollectionJob mcj = toJsonObj( (String)response, MeasurementCollectionJob.class); + return mcj; + }catch (Exception e) { + logger.error("Cannot create a new Measurement Collection Job. " + e.toString()); + } + return null; +} + + diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 5e09475fc60dd13f01d96626c78ed8023d7dffd8..55f42c5636cfe3b05067d1761724e6c8d98b354e 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -124,4 +124,7 @@ CATALOG_GET_RESOURCESPEC_BY_NAME_CATEGORY: "jms:queue:CATALOG.GET.RESOURCESPEC_B #CRD ACTIONS CRD_DEPLOY_CR_REQ: "jms:queue:CRD.DEPLOY.CR_REQ" CRD_DELETE_CR_REQ: "jms:queue:CRD.DELETE.CR_REQ" -CRD_PATCH_CR_REQ: "jms:queue:CRD.PATCH.CR_REQ" \ No newline at end of file +CRD_PATCH_CR_REQ: "jms:queue:CRD.PATCH.CR_REQ" + +#TMF628 ACTIONS +PM_MEASUREMENT_COLLECTION_JOB_ADD: "jms:queue:PM.MEASUREMENTCOLLECTIONJOB.ADD" \ No newline at end of file diff --git a/src/main/resources/processes/MetricoDeploymentReq.bpmn b/src/main/resources/processes/MetricoDeploymentReq.bpmn new file mode 100644 index 0000000000000000000000000000000000000000..c931982d3438fea8d68082924fe5b76c9fa1f807 --- /dev/null +++ b/src/main/resources/processes/MetricoDeploymentReq.bpmn @@ -0,0 +1,71 @@ + + + + + + + + + + PT30S + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/processes/ServiceCreationProcess.bpmn b/src/main/resources/processes/ServiceCreationProcess.bpmn index 1fb3993f21e4fb1e28c7f3779b071cc325febaa3..c2b30e719d3a1016dfbc59817606b7472bc94954 100644 --- a/src/main/resources/processes/ServiceCreationProcess.bpmn +++ b/src/main/resources/processes/ServiceCreationProcess.bpmn @@ -85,6 +85,11 @@ + + + + + @@ -148,6 +153,9 @@ + + + @@ -164,7 +172,7 @@ - + @@ -176,7 +184,7 @@ - + @@ -192,7 +200,7 @@ - + @@ -200,7 +208,7 @@ - + @@ -208,7 +216,7 @@ - + @@ -216,7 +224,7 @@ - + @@ -228,7 +236,7 @@ - + @@ -241,7 +249,7 @@ - + @@ -264,14 +272,14 @@ - + - + @@ -284,7 +292,7 @@ - + @@ -297,7 +305,7 @@ - + @@ -309,7 +317,7 @@ - + @@ -317,6 +325,19 @@ + + + + + + + + + + + + + \ No newline at end of file