diff options
author | Stone, Avi (as206k) <as206k@att.com> | 2018-04-12 15:46:31 +0300 |
---|---|---|
committer | Stone, Avi (as206k) <as206k@att.com> | 2018-04-12 15:49:38 +0300 |
commit | 5032434b101f25fa44d2e1f8dc8393e30af1ed4f (patch) | |
tree | 2dc7d37a8048e025c7412af080640da4c9a22b65 /dcaedt_be/src/main/java/org/onap/sdc/dcae/composition | |
parent | 2205633792f95f46a02bbf8f87f0c2637265d924 (diff) |
DCAE-D be initial commit
DCAE-D be initial commit
Issue-ID: SDC-1218
Change-Id: Id18ba96c499e785aa9ac395fbaf32d57f08c281b
Signed-off-by: Stone, Avi (as206k) <as206k@att.com>
Diffstat (limited to 'dcaedt_be/src/main/java/org/onap/sdc/dcae/composition')
17 files changed, 2529 insertions, 0 deletions
diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/CompositionConfig.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/CompositionConfig.java new file mode 100644 index 0000000..ee8f5c6 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/CompositionConfig.java @@ -0,0 +1,87 @@ +package org.onap.sdc.dcae.composition; + +import java.lang.reflect.Type; +import java.util.Map; +import java.util.Set; + +import javax.annotation.PostConstruct; + +import org.onap.sdc.common.onaplog.OnapLoggerDebug; +import org.onap.sdc.common.onaplog.OnapLoggerError; +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.PropertySource; +import org.springframework.context.annotation.PropertySources; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +@Component +@PropertySources({ + @PropertySource(value="classpath:application-fe.properties", ignoreResourceNotFound=true), + @PropertySource(value="file:${jetty.base}/config/dcae-be/application.properties", ignoreResourceNotFound=true) +}) + +public class CompositionConfig { + + private static OnapLoggerError errLogger = OnapLoggerError.getInstance(); + private static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + + @Value("${compositionConfig.flowTypes}") + private String flowTypes; + @JsonIgnore + private Map<String, FlowType> flowTypesMap; + @Value("${compositionConfig.isRuleEditorActive}") + private boolean isRuleEditorActive; + + // get flowTypes as the parsed keySet + public Set<String> getFlowTypes() { + return flowTypesMap.keySet(); + } + + @JsonProperty("isRuleEditorActive") + public boolean isRuleEditorActive() { + return isRuleEditorActive; + } + + public Map<String, FlowType> getFlowTypesMap() { + return flowTypesMap; + } + + public static class FlowType { + + private String entryPointPhaseName; + private String lastPhaseName; + + public String getEntryPointPhaseName() { + return entryPointPhaseName; + } + + public void setEntryPointPhaseName(String entryPointPhaseName) { + this.entryPointPhaseName = entryPointPhaseName; + } + + public String getLastPhaseName() { + return lastPhaseName; + } + + public void setLastPhaseName(String lastPhaseName) { + this.lastPhaseName = lastPhaseName; + } + } + + + @PostConstruct + public void init() { + try { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Reading flow type definitions from configuration"); + Type map = new TypeToken<Map<String, FlowType>>(){}.getType(); + flowTypesMap = new Gson().fromJson(flowTypes, map); + } catch (Exception e) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Error – Failed to read flow type definitions"); + } + } +}
\ No newline at end of file diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/CompositionEngine.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/CompositionEngine.java new file mode 100644 index 0000000..186f3f6 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/CompositionEngine.java @@ -0,0 +1,140 @@ +package org.onap.sdc.dcae.composition; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Properties; +import java.util.jar.Attributes; +import java.util.jar.Manifest; + +import javax.servlet.ServletContext; + +import org.onap.sdc.common.onaplog.OnapLoggerDebug; +import org.onap.sdc.common.onaplog.OnapLoggerError; +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.dcae.composition.util.SystemProperties; +import org.onap.sdc.dcae.filter.LoggingFilter; +import org.onap.sdc.dcae.errormng.ErrConfMgr; +import org.onap.sdc.dcae.errormng.ErrorConfiguration; +import org.onap.sdc.dcae.errormng.ErrorConfigurationLoader; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.boot.web.support.SpringBootServletInitializer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; + +@Configuration +@EnableScheduling +@SpringBootApplication +@ComponentScan("org.onap.sdc.dcae") +@EnableAutoConfiguration +@PropertySource("file:${jetty.base}/config/dcae-be/application.properties") +public class CompositionEngine extends SpringBootServletInitializer implements CommandLineRunner{ + private static final String SPECIFICATION_VERSION = "Specification-Version"; + @Autowired + ServletContext servletContext; + private static final String MANIFEST_FILE_NAME = "/META-INF/MANIFEST.MF"; + private static String dcaeVersion; + private OnapLoggerError errLogger = OnapLoggerError.getInstance(); + private OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + + public static void main(String[] args) { + SpringApplication.run(CompositionEngine.class, args); + } + + /** + * Creates and returns a new instance of a {@link SystemProperties} class. + * + * @return New instance of {@link SystemProperties}. + */ + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { + return application.sources(CompositionEngine.class); + } + + + @Bean + public WebMvcConfigurer corsConfigurer() { + return new WebMvcConfigurerAdapter() { + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOrigins("*") + .allowedHeaders("*") + .allowedMethods("GET", "POST", "OPTIONS", "PUT") + .allowCredentials(false) + .maxAge(3600); + + } + }; + } + + @Override + public void run(String... args) throws Exception { + + ErrorConfigurationLoader errorConfigurationLoader = new ErrorConfigurationLoader(System.getProperty("jetty.base")); + ErrConfMgr instance = ErrConfMgr.INSTANCE; + InputStream inputStream = servletContext.getResourceAsStream(MANIFEST_FILE_NAME); + + //setLogbackXmlLocation(); + + String version = null; + try { + Manifest mf = new Manifest(inputStream); + Attributes atts = mf.getMainAttributes(); + version = atts.getValue(SPECIFICATION_VERSION); + if (version == null || version.isEmpty()) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "failed to read DCAE version from MANIFEST."); + } else { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "DCAE version from MANIFEST is {}", version); + dcaeVersion = version; + } + + } catch (IOException e) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "failed to read DCAE version from MANIFEST: {}", e.getMessage()); + } + + } + + private void setLogbackXmlLocation() throws Exception { + String jettyBase = System.getProperty("config.home"); + Properties props = System.getProperties(); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Current System Properties are: {}", props); + if (jettyBase == null) { + String msg = "Couldn't resolve config.home environmental variable"; + errLogger.log(LogLevel.ERROR, this.getClass().getName(), msg); + throw new Exception(msg + ". Failed to configure logback.xml location... aborting."); + } + String logbackXmlLocation = jettyBase+"/dcae-be/logback.xml"; + props.setProperty("logback.configurationFile", logbackXmlLocation); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Successfuly set the logback.xml location to {}", logbackXmlLocation); + } + + @Bean + public FilterRegistrationBean contextLifecycleFilter() { + Collection<String> urlPatterns = new ArrayList<>(); + urlPatterns.add("/*"); + + FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new LoggingFilter()); + filterRegistrationBean.setUrlPatterns(urlPatterns); + + return filterRegistrationBean; + } + + public static String getDcaeVersion() { + return dcaeVersion; + } + +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/BaseController.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/BaseController.java new file mode 100644 index 0000000..8b590ca --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/BaseController.java @@ -0,0 +1,80 @@ +package org.onap.sdc.dcae.composition.controller; + +import javax.servlet.http.HttpServletRequest; + +import org.onap.sdc.common.onaplog.OnapLoggerDebug; +import org.onap.sdc.common.onaplog.OnapLoggerError; +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.dcae.composition.impl.BaseBusinessLogic; +import org.onap.sdc.dcae.composition.restmodels.sdc.Asset; +import org.onap.sdc.dcae.composition.restmodels.sdc.ResourceDetailed; +import org.onap.sdc.dcae.composition.util.DcaeBeConstants; +import org.onap.sdc.dcae.composition.util.SystemProperties; +import org.onap.sdc.dcae.enums.AssetType; +import org.onap.sdc.dcae.enums.LifecycleOperationType; +import org.onap.sdc.dcae.errormng.ActionStatus; +import org.onap.sdc.dcae.errormng.DcaeException; +import org.onap.sdc.dcae.errormng.ErrConfMgr; +import org.onap.sdc.dcae.errormng.ErrConfMgr.ApiType; +import org.onap.sdc.dcae.errormng.ResponseFormat; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ModelAttribute; + +import com.google.gson.Gson; + +public abstract class BaseController { + + protected Gson gson = new Gson(); + + @Autowired + protected SystemProperties systemProperties; + + @Autowired + protected BaseBusinessLogic baseBusinessLogic; + + protected OnapLoggerError errLogger = OnapLoggerError.getInstance(); + protected OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + + @ModelAttribute("requestId") + public String getRequestId(HttpServletRequest request) { + return request.getAttribute("requestId").toString(); + } + + Asset checkout(String userId, String uuid, AssetType assetType, String requestId) throws Exception { + return baseBusinessLogic.getSdcRestClient().changeAssetLifecycleState(userId, uuid, LifecycleOperationType.CHECKOUT.name(), null, assetType, requestId); + } + + Asset checkin(String userId, String uuid, AssetType assetType, String requestId) throws Exception { + return baseBusinessLogic.getSdcRestClient().changeAssetLifecycleState(userId, uuid, LifecycleOperationType.CHECKIN.name(), "checking in " + assetType.name() + uuid, assetType, requestId); + } + + + boolean isNeedToCheckOut(String lifecycleState) { + return DcaeBeConstants.LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT != DcaeBeConstants.LifecycleStateEnum.findState(lifecycleState); + } + + void checkUserIfResourceCheckedOut(String userId, Asset asset) throws DcaeException { + if (DcaeBeConstants.LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT == DcaeBeConstants.LifecycleStateEnum.findState(asset.getLifecycleState())) { + String lastUpdaterUserId = asset.getLastUpdaterUserId(); + if (lastUpdaterUserId != null && !lastUpdaterUserId.equals(userId)) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "User conflicts. Operation not allowed for user {} on resource checked out by {}", userId, lastUpdaterUserId); + ResponseFormat responseFormat = ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.USER_CONFLICT, null, userId, asset.getName(), lastUpdaterUserId); + throw new DcaeException(HttpStatus.FORBIDDEN, responseFormat.getRequestError()); + } + } + } + + void checkVfcmtType(ResourceDetailed vfcmt) { + if (!"VFCMT".equals(vfcmt.getResourceType()) || !"Template".equals(vfcmt.getCategory())) { + ResponseFormat responseFormat = ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.RESOURCE_NOT_VFCMT_ERROR, null, vfcmt.getUuid()); + throw new DcaeException(HttpStatus.BAD_REQUEST, responseFormat.getRequestError()); + } + } + + ResponseEntity handleException(Exception e, ApiType apiType, String... variables){ + errLogger.log(LogLevel.ERROR, this.getClass().getName(), e.getMessage()); + return ErrConfMgr.INSTANCE.handleException(e, apiType, variables); + } +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/BlueprintController.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/BlueprintController.java new file mode 100644 index 0000000..a12c6b8 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/BlueprintController.java @@ -0,0 +1,239 @@ +package org.onap.sdc.dcae.composition.controller; + +import org.apache.commons.lang.StringUtils; +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.dcae.composition.restmodels.MessageResponse; +import org.onap.sdc.dcae.catalog.asdc.ASDC; +import org.onap.sdc.dcae.catalog.asdc.ASDCUtils; +import org.onap.sdc.dcae.catalog.asdc.Blueprinter; +import org.onap.sdc.dcae.composition.restmodels.sdc.*; +import org.onap.sdc.dcae.utils.Normalizers; +import org.onap.sdc.dcae.composition.util.DcaeBeConstants; +import org.onap.sdc.dcae.enums.ArtifactType; +import org.onap.sdc.dcae.enums.AssetType; +import org.onap.sdc.dcae.enums.LifecycleOperationType; +import org.onap.sdc.dcae.errormng.ActionStatus; +import org.onap.sdc.dcae.errormng.ErrConfMgr; +import org.onap.sdc.dcae.errormng.ErrConfMgr.ApiType; +import org.onap.sdc.dcae.utils.SdcRestClientUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.util.Base64Utils; +import org.springframework.util.CollectionUtils; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.PostConstruct; +import java.io.StringReader; +import java.net.URI; + +@RestController +@EnableAutoConfiguration +@CrossOrigin +public class BlueprintController extends BaseController{ + + @Autowired + private Blueprinter blueprinter; + + @Autowired + private ASDC asdc; + + private static final String CREATE_DESC = "creating new artifact blueprint on the service vfi"; + private static final String UPDATE_DESC = "updating artifact blueprint on the service vfi"; + + + + @PostConstruct + public void init(){ + URI sdcUri = URI.create(systemProperties.getProperties().getProperty(DcaeBeConstants.Config.URI)); + asdc.setUri(sdcUri); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "SDC uri: {}", sdcUri); + } + + /*** + * VFCMT - Resource, blueprint - as an artifact as an service. + * @param userId + * @param vfcmtUuid + * @param serviceUuid + * @param serviceInstanceName + * @param monitoringFlowType + * @return ResponseEntity + */ + @RequestMapping(value = "/createBluePrint/{VFCMTUuid}/{serviceUuid}/{instanceName}/{monitoringFlowType}", method = RequestMethod.POST) + public ResponseEntity createBluePrint(@RequestHeader("USER_ID") String userId, + @PathVariable("VFCMTUuid") String vfcmtUuid, + @PathVariable("serviceUuid") String serviceUuid, + @PathVariable("instanceName") String serviceInstanceName, + @PathVariable("monitoringFlowType") String monitoringFlowType, + @ModelAttribute("requestId") String requestId) { + try { + + ResourceDetailed vfcmt = baseBusinessLogic.getSdcRestClient().getResource(vfcmtUuid, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), vfcmt.toString()); + checkVfcmtType(vfcmt); + Artifact cdumpArtifactData = findCdumpArtifactData(vfcmt); + if (null != cdumpArtifactData) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Found the cdump (composition.yml) on top of VFCMT {}", vfcmtUuid); + String cdump = baseBusinessLogic.getSdcRestClient().getResourceArtifact(vfcmtUuid, cdumpArtifactData.getArtifactUUID(), requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "---------------------------------------------------------------CDUMP: -----------------------------------------------------------------------------"); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), cdump); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "---------------------------------------------------------------------------------------------------------------------------------------------------"); + ASDCUtils utils = new ASDCUtils(asdc, blueprinter); + + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Going to use python procedure to create a blueprint...."); + String resultBlueprintCreation; + try{ + resultBlueprintCreation = utils.buildBlueprintViaToscaLab(new StringReader(cdump)).waitForResult().waitForResult(); + }catch (Exception e){ + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.GENERATE_BLUEPRINT_ERROR, e.getMessage(), vfcmt.getName()); + } + if (StringUtils.isEmpty(resultBlueprintCreation)) { + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.GENERATE_BLUEPRINT_ERROR, "", vfcmt.getName()); + } + + // 1806 US374595 flowType in cdump + String flowTypeFromCdump = StringUtils.substringBetween(cdump,"\"flowType\":\"","\""); + if(StringUtils.isNotBlank(flowTypeFromCdump)) { + monitoringFlowType = flowTypeFromCdump; + } + // saving to serviceVfInstance + Artifact savedBluePrint = saveBluePrint(userId, serviceUuid, serviceInstanceName, resultBlueprintCreation, monitoringFlowType, vfcmt.getName(), requestId); + if(savedBluePrint!=null){ + MessageResponse response = new MessageResponse(); + response.setSuccessResponse("Blueprint build complete \n. Blueprint="+savedBluePrint.getArtifactName()); + //1806 US374593 - certify VFCMT after BP generation + certifyVfcmt(vfcmt, requestId); + return new ResponseEntity<>(response, HttpStatus.OK); + } + else{ + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.SUBMIT_BLUEPRINT_ERROR); + } + + }else{ + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.MISSING_TOSCA_FILE, "", vfcmt.getName()); + } + } catch (Exception e) { + return handleException(e, ApiType.SUBMIT_BLUEPRINT); + } + } + + + /********************* private function ********************/ + + /** + * @param userId + * @param serviceUuid + * @param resourceInstanceName + * @param bluePrint + * @param monitoringFlowType + * @param vfcmtName + * @param requestId + * @return + * @throws Exception + */ + private Artifact saveBluePrint(String userId, String serviceUuid, String resourceInstanceName, String bluePrint, String monitoringFlowType, String vfcmtName, String requestId) throws Exception { + + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "BLUEPRINT:\n{}", bluePrint); + try { + ServiceDetailed service = baseBusinessLogic.getSdcRestClient().getService(serviceUuid, requestId); + //Validations + checkUserIfResourceCheckedOut(userId, service); + ResourceInstance vfi = findVfiOnService(service, resourceInstanceName); + if(null == vfi){ + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "VF instance {} not found on service {}", resourceInstanceName, serviceUuid); + return null; + } + + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), service.toString()); + + String normalizedArtifactLabel = Normalizers.normalizeArtifactLabel("blueprint-" + monitoringFlowType); + Artifact blueprintArtifact = CollectionUtils.isEmpty(vfi.getArtifacts()) ? null : vfi.getArtifacts().stream() + .filter(p -> normalizedArtifactLabel.equals(Normalizers.normalizeArtifactLabel(p.getArtifactLabel()))) + .findAny() + .orElse(null); + + boolean isNeed2Checkout = isNeedToCheckOut(service.getLifecycleState()); + if (isNeed2Checkout) { + Asset result = checkout(userId, serviceUuid, AssetType.SERVICE, requestId); + if (result != null) { + serviceUuid = result.getUuid(); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "New service after checkout is: {}", serviceUuid); + } + } + //update mode + if (null != blueprintArtifact) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Found that service {} already consist of {} ----> updateMode", serviceUuid, normalizedArtifactLabel); + blueprintArtifact.setDescription(UPDATE_DESC); + blueprintArtifact.setPayloadData(Base64Utils.encodeToString(bluePrint.getBytes())); + blueprintArtifact = baseBusinessLogic.getSdcRestClient().updateVfInstanceArtifact(userId, serviceUuid, Normalizers.normalizeComponentInstanceName(resourceInstanceName), blueprintArtifact, requestId); + //create mode + } else { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Service {} does not consist {} ----> createMode", serviceUuid, normalizedArtifactLabel); + blueprintArtifact = SdcRestClientUtils.generateDeploymentArtifact(CREATE_DESC, generateBlueprintFileName(monitoringFlowType, vfcmtName), ArtifactType.DCAE_INVENTORY_BLUEPRINT.name(), normalizedArtifactLabel, bluePrint.getBytes()); + blueprintArtifact = baseBusinessLogic.getSdcRestClient().createVfInstanceArtifact(userId, serviceUuid, Normalizers.normalizeComponentInstanceName(resourceInstanceName), blueprintArtifact, requestId); + } + + //No need to check the service in in 1806 +// Asset blueprintAsJson = checkin(user_id, serviceUuid, AssetType.SERVICE); +// debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "service result after check-in: {}", blueprintAsJson.toString()); + + return blueprintArtifact; + + } catch (Exception e) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Error occurred while trying to save blueprint {}", e.toString()); + throw e; + } + } + + /** + * + * @param monitoringFlowType + * @param vfcmtName + * @return + */ + private String generateBlueprintFileName(String monitoringFlowType, String vfcmtName) { + StringBuffer sb = new StringBuffer(); + sb.append(monitoringFlowType); + sb.append("."); + sb.append(Normalizers.normalizeComponentName(vfcmtName)); + sb.append("."); + sb.append(DcaeBeConstants.Composition.fileNames.EVENT_PROC_BP_YAML); + return sb.toString(); + } + + private ResourceInstance findVfiOnService(ServiceDetailed service, String vfiName) { + return null == service ? null : CollectionUtils.isEmpty(service.getResources()) ? null : service.getResources().stream().filter(p -> vfiName.equals(p.getResourceInstanceName())).findAny().orElse(null); + } + + private Artifact findCdumpArtifactData(ResourceDetailed vfcmt) { + return null == vfcmt ? null : CollectionUtils.isEmpty(vfcmt.getArtifacts()) ? null : vfcmt.getArtifacts().stream() + .filter(p -> DcaeBeConstants.Composition.fileNames.COMPOSITION_YML.equals(p.getArtifactName())).findAny().orElse(null); + } + + private void certifyVfcmt(ResourceDetailed vfcmt, String requestId){ + String state = vfcmt.getLifecycleState(); + if(null == state) { + debugLogger.log(LogLevel.ERROR, this.getClass().getName(), "Couldn't read Vfcmt lifecycle state"); + return; + } + DcaeBeConstants.LifecycleStateEnum lifeCycleState = DcaeBeConstants.LifecycleStateEnum.findState(state); + if(null == lifeCycleState) { + debugLogger.log(LogLevel.ERROR, this.getClass().getName(), "Undefined lifecycle state: {}", state); + return; + } + try{ + switch (lifeCycleState){ + case NOT_CERTIFIED_CHECKOUT: + baseBusinessLogic.getSdcRestClient().changeResourceLifecycleState(vfcmt.getLastUpdaterUserId(), vfcmt.getUuid(), LifecycleOperationType.CHECKIN.name(), "check in VFCMT after blueprint successful submission", requestId); + case NOT_CERTIFIED_CHECKIN: + baseBusinessLogic.getSdcRestClient().changeResourceLifecycleState(vfcmt.getLastUpdaterUserId(), vfcmt.getUuid(), LifecycleOperationType.CERTIFY.name(), "certify VFCMT after blueprint successful submission", requestId); + } + } + catch (Exception e){ + //informative only. no message to user (TBA) + debugLogger.log(LogLevel.ERROR, this.getClass().getName(), "Error occurred during vfcmt lifecycle operation: {}", e.toString()); + } + } + +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/CompositionController.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/CompositionController.java new file mode 100644 index 0000000..5cba14f --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/CompositionController.java @@ -0,0 +1,338 @@ +package org.onap.sdc.dcae.composition.controller; + +import org.json.JSONArray; +import org.json.JSONException; +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.dcae.composition.restmodels.MessageResponse; +import org.onap.sdc.dcae.composition.restmodels.sdc.Artifact; +import org.onap.sdc.dcae.composition.restmodels.sdc.Asset; +import org.onap.sdc.dcae.composition.restmodels.sdc.ResourceDetailed; +import org.onap.sdc.dcae.catalog.Catalog; +import org.onap.sdc.dcae.catalog.Catalog.*; +import org.onap.sdc.dcae.catalog.engine.*; +import org.onap.sdc.dcae.composition.util.DcaeBeConstants; +import org.onap.sdc.dcae.enums.ArtifactType; +import org.onap.sdc.dcae.enums.LifecycleOperationType; +import org.onap.sdc.dcae.errormng.ActionStatus; +import org.onap.sdc.dcae.errormng.ErrConfMgr; +import org.onap.sdc.dcae.errormng.ErrConfMgr.ApiType; +import org.onap.sdc.dcae.utils.SdcRestClientUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.util.Base64Utils; +import org.springframework.util.CollectionUtils; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.context.request.async.DeferredResult; + +import javax.annotation.PostConstruct; +import java.net.URI; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +@RestController +@EnableAutoConfiguration +@CrossOrigin +public class CompositionController extends BaseController{ + + @Autowired + private CatalogController catalogController; + + @PostConstruct + public void init() { + catalogController.setDefaultCatalog(URI.create(systemProperties.getProperties().getProperty(DcaeBeConstants.Config.ASDC_CATALOG_URL))); + } + + @RequestMapping(value = { "/utils/clone/{assetType}/{sourceId}/{targetId}" }, method = {RequestMethod.GET }, produces = { "application/json" }) + public ResponseEntity clone(@RequestHeader("USER_ID") String userId, @PathVariable("assetType") String theAssetType, @PathVariable("sourceId") String theSourceId, @PathVariable("targetId") String theTargetId, + @ModelAttribute("requestId") String requestId) { + MessageResponse response = new MessageResponse(); + + try { + // fetch the source and assert it is a vfcmt containing clone worthy artifacts (composition + rules) + ResourceDetailed sourceVfcmt = baseBusinessLogic.getSdcRestClient().getResource(theSourceId, requestId); + checkVfcmtType(sourceVfcmt); + List<Artifact> artifactsToClone = CollectionUtils.isEmpty(sourceVfcmt.getArtifacts()) ? null : sourceVfcmt.getArtifacts().stream() + .filter(p -> DcaeBeConstants.Composition.fileNames.COMPOSITION_YML.equals(p.getArtifactName()) || p.getArtifactName().endsWith(DcaeBeConstants.Composition.fileNames.MAPPING_RULE_POSTFIX)) + .collect(Collectors.toList()); + if(CollectionUtils.isEmpty(artifactsToClone)) { + response.setSuccessResponse("Nothing to clone"); + return new ResponseEntity<>(response ,HttpStatus.NO_CONTENT); + } + + // fetch the target + ResourceDetailed vfcmt = baseBusinessLogic.getSdcRestClient().getResource(theTargetId, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), vfcmt.toString()); + checkVfcmtType(vfcmt); + checkUserIfResourceCheckedOut(userId, vfcmt); + boolean isTargetNeed2Checkout = isNeedToCheckOut(vfcmt.getLifecycleState()); + if (isTargetNeed2Checkout) { + ResourceDetailed targetVfcmt = baseBusinessLogic.getSdcRestClient().changeResourceLifecycleState(userId, theTargetId, LifecycleOperationType.CHECKOUT.name(), "checking out VFCMT before clone", requestId); + if(null == targetVfcmt){ + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.GENERAL_ERROR); + } + theTargetId = targetVfcmt.getUuid(); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "New targetVfcmt (for artifact clone) after checkout is: {}", theTargetId); + } + + Map<String, Artifact> currentArtifacts = CollectionUtils.isEmpty(vfcmt.getArtifacts()) ? new HashMap<>() : vfcmt.getArtifacts().stream() + .collect(Collectors.toMap(Artifact::getArtifactName, Function.identity())); + + //TODO target VFCMT rule artifacts should be removed + for(Artifact artifactToClone : artifactsToClone) { + String payload = baseBusinessLogic.getSdcRestClient().getResourceArtifact(theSourceId, artifactToClone.getArtifactUUID(), requestId); + baseBusinessLogic.cloneArtifactToTarget(userId, theTargetId, payload, artifactToClone, currentArtifacts.get(artifactToClone.getArtifactName()), requestId); + } + + baseBusinessLogic.getSdcRestClient().changeResourceLifecycleState(userId, theTargetId, LifecycleOperationType.CHECKIN.name(), "check in VFCMT after clone", requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Cloning {} from {} has finished successfully", theSourceId, theTargetId); + response.setSuccessResponse("Clone VFCMT complete"); + return new ResponseEntity<>(response, HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ApiType.CLONE_VFCMT); + } + } + + @RequestMapping(value = "/elements", method = { RequestMethod.POST, RequestMethod.GET }, produces = "application/json") + public DeferredResult<CatalogResponse> items(@RequestBody(required = false) ItemsRequest theRequest) { + + final ItemsRequest request = (theRequest == null) ? ItemsRequest.EMPTY_REQUEST : theRequest; + + Catalog catalog = catalogController.getCatalog(request.getCatalog()); + DeferredResult<CatalogResponse> result = new DeferredResult<CatalogResponse>(request.getTimeout()); + + catalog.rootsByLabel(request.getStartingLabel()) + .setHandler(catalogController.new CatalogHandler<Folders>(request, result) { + public CatalogResponse handleData(Folders theFolders) { + JSONArray ja = new JSONArray(); + if (theFolders != null) { + for (Folder folder : theFolders) { + ja.put(catalogController.patchData(catalog, folder.data())); + } + } + CatalogResponse response = new CatalogResponse(this.request); + try { + response.data().put("elements", ja); + } catch (JSONException e) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "JSONException putting json elements to response {}", e); + } + return response; + } + }); + return result; + } + + @RequestMapping(value = "/{theItemId}/elements", method = { RequestMethod.POST, RequestMethod.GET }, produces = "application/json") + public DeferredResult<CatalogResponse> items(@RequestBody(required = false) ItemsRequest theRequest, @PathVariable String theItemId) { + + final ItemsRequest request = (theRequest == null) ? ItemsRequest.EMPTY_REQUEST : theRequest; + + Catalog catalog = catalogController.getCatalog(request.getCatalog()); + DeferredResult<CatalogResponse> result = new DeferredResult<CatalogResponse>(request.getTimeout()); + + catalog + // .fetchFolderByItemId(theItemId) + .folder(theItemId).withParts().withPartAnnotations().withItems().withItemAnnotations().withItemModels() + .execute().setHandler(catalogController.new CatalogHandler<Folder>(request, result) { + public CatalogResponse handleData(Folder theFolder) { + CatalogResponse response = new CatalogResponse(this.request); + if (theFolder == null) { + return response; + } + + try { + Elements folders = theFolder.elements("parts", Folders.class); + if (folders != null) { + for (Object folder : folders) { + catalogController.patchData(catalog, ((Element) folder).data()); + // lots of ephemere proxies created here .. + Elements annotations = ((Element) folder).elements("annotations", + Annotations.class); + if (annotations != null) { + for (Object a : annotations) { + catalogController.patchData(catalog, ((Annotation) a).data()); + } + } + } + } + Elements items = theFolder.elements("items", Items.class); + if (items != null) { + for (Object i : items) { + catalogController.patchData(catalog, ((Element) i).data()); + // lots of ephemere proxies created here .. + Elements annotations = ((Element) i).elements("annotations", Annotations.class); + if (annotations != null) { + for (Object a : annotations) { + catalogController.patchData(catalog, ((Annotation) a).data()); + } + } + } + } + } catch (Exception x) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Exception processing catalog {}", x); + return new CatalogError(this.request, "", x); + } + + try { + response.data().put("element", theFolder.data()); + } catch (JSONException e) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "JSONException putting element to response {}", e); + } + return response; + } + }); + + return result; + } + + @RequestMapping(value = "/{theItemId}/model", method = { RequestMethod.POST,RequestMethod.GET }, produces = "application/json") + public DeferredResult model(@RequestBody(required = false) ElementRequest theRequest, + @PathVariable String theItemId) { + final ElementRequest request = (theRequest == null) ? ElementRequest.EMPTY_REQUEST : theRequest; + + Catalog catalog = catalogController.getCatalog(request.getCatalog()); + DeferredResult<CatalogResponse> result = new DeferredResult<>(request.getTimeout()); + + catalog + .item(theItemId).withModels().execute() + .setHandler(catalogController.new CatalogHandler<Item>(request, result) { + public CatalogResponse handleData(Item theItem) { + if (theItem == null) { + return new CatalogError(this.request, "No such item"); + } + Templates models = null; + try { + models = (Templates) theItem.elements("models", Templates.class); + if (models == null || models.isEmpty()) { + return new CatalogError(this.request, "Item has no models"); + } + if (models.size() > 1) { + return new CatalogError(this.request, "Item has more than one model !?"); + } + catalog.template(models.get(0).id()).withInputs().withOutputs().withNodes() + .withNodeProperties().withNodePropertiesAssignments().withNodeRequirements() + .withNodeCapabilities().withNodeCapabilityProperties() + .withNodeCapabilityPropertyAssignments().withPolicies().withPolicyProperties() + .withPolicyPropertiesAssignments().execute().setHandler( + catalogController.new CatalogHandler<Template>(this.request, this.result) { + public CatalogResponse handleData(Template theTemplate) { + CatalogResponse response = new CatalogResponse(this.request); + if (theTemplate != null) { + try { + response.data().put("model", catalogController + .patchData(catalog, theTemplate.data())); + } catch (JSONException e) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "JSONException putting model to response {}", e); + } + } + return response; + } + }); + } catch (Exception e) { + handleException(e, ApiType.GET_MODEL, models.get(0).name()); + } + return null; + } + }); + + return result; + } + + @RequestMapping(value = "/{theItemId}/type/{theTypeName}", method = { RequestMethod.POST, RequestMethod.GET }, produces = "application/json") + public DeferredResult<CatalogResponse> model(@RequestBody(required = false) ElementRequest theRequest, @PathVariable String theItemId, @PathVariable String theTypeName) { + final ElementRequest request = (theRequest == null) ? ElementRequest.EMPTY_REQUEST : theRequest; + + Catalog catalog = catalogController.getCatalog(request.getCatalog()); + DeferredResult<CatalogResponse> result = new DeferredResult<CatalogResponse>(request.getTimeout()); + + catalog.type(theItemId, theTypeName).withHierarchy().withCapabilities().withRequirements().execute() + .setHandler(catalogController.new CatalogHandler<Type>(request, result) { + public CatalogResponse handleData(Type theType) { + CatalogResponse response = new CatalogResponse(this.request); + if (theType != null) { + try { + response.data().put("type", catalogController.patchData(catalog, theType.data())); + } catch (JSONException e) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Exception processing catalog {}", e); + } + } + return response; + } + }); + + return result; + } + + @RequestMapping(value = { "/getComposition/{vfcmtUuid}" }, method = { RequestMethod.GET }, produces = {"application/json" }) + public ResponseEntity getComposition(@PathVariable("vfcmtUuid") String vfcmtUuid, @ModelAttribute("requestId") String requestId) { + MessageResponse response = new MessageResponse(); + try { + ResourceDetailed vfcmt = baseBusinessLogic.getSdcRestClient().getResource(vfcmtUuid, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), vfcmt.toString()); + checkVfcmtType(vfcmt); + + Artifact compositionArtifact = CollectionUtils.isEmpty(vfcmt.getArtifacts()) ? null : vfcmt.getArtifacts().stream().filter(a -> DcaeBeConstants.Composition.fileNames.COMPOSITION_YML.equals(a.getArtifactName())).findAny().orElse(null); + + if(null == compositionArtifact){ + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Couldn't find {} in VFCMT artifacts", DcaeBeConstants.Composition.fileNames.COMPOSITION_YML); + response.setErrorResponse("No Artifacts"); + return new ResponseEntity<>(response, HttpStatus.NO_CONTENT); + } + + String artifact = baseBusinessLogic.getSdcRestClient().getResourceArtifact(vfcmtUuid, compositionArtifact.getArtifactUUID(), requestId); + + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "ARTIFACT: {}", artifact); + response.setSuccessResponse(artifact); + return new ResponseEntity<>(response, HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ApiType.GET_CDUMP); + } + } + + @RequestMapping(value = "/saveComposition/{vfcmtUuid}", method = RequestMethod.POST) + public ResponseEntity saveComposition(@RequestHeader("USER_ID") String userId, @RequestBody String theCdump, @PathVariable("vfcmtUuid") String vfcmtUuid, @ModelAttribute("requestId") String requestId) { + + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "ARTIFACT CDUMP: {}", theCdump); + + try { + + ResourceDetailed vfcmt = baseBusinessLogic.getSdcRestClient().getResource(vfcmtUuid, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "VFCMT: {}", vfcmt); + + checkVfcmtType(vfcmt); + checkUserIfResourceCheckedOut(userId, vfcmt); + boolean isNeed2Checkout = isNeedToCheckOut(vfcmt.getLifecycleState()); + Artifact compositionArtifact = CollectionUtils.isEmpty(vfcmt.getArtifacts()) ? null : vfcmt.getArtifacts().stream().filter(a -> DcaeBeConstants.Composition.fileNames.COMPOSITION_YML.equals(a.getArtifactName())).findAny().orElse(null); + String resourceUuid = vfcmtUuid; // by default the resource is the original vfcmtId unless a checkout will be done + if (isNeed2Checkout) { + vfcmt = baseBusinessLogic.getSdcRestClient().changeResourceLifecycleState(userId, resourceUuid, LifecycleOperationType.CHECKOUT.name(), null, requestId); + if (vfcmt != null) { + resourceUuid = vfcmt.getUuid(); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "New resource after checkout is: {}", resourceUuid); + } + } + boolean isUpdateMode = null != compositionArtifact; + if (isUpdateMode) { + compositionArtifact.setDescription("updating composition file"); + compositionArtifact.setPayloadData(Base64Utils.encodeToString(theCdump.getBytes())); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "VFCMT {} does consist {} ----> updateMode", resourceUuid, DcaeBeConstants.Composition.fileNames.COMPOSITION_YML); + baseBusinessLogic.getSdcRestClient().updateResourceArtifact(userId, resourceUuid, compositionArtifact, requestId); + + } else { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "VFCMT {} does not consist {} ----> createMode", resourceUuid, DcaeBeConstants.Composition.fileNames.COMPOSITION_YML); + compositionArtifact = SdcRestClientUtils.generateDeploymentArtifact("creating composition file", DcaeBeConstants.Composition.fileNames.COMPOSITION_YML, ArtifactType.DCAE_TOSCA.name(), "composition", theCdump.getBytes()); + baseBusinessLogic.getSdcRestClient().createResourceArtifact(userId, resourceUuid, compositionArtifact, requestId); + } + Asset result = checkin(userId, resourceUuid, org.onap.sdc.dcae.enums.AssetType.RESOURCE, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "vfcmt check-in result: {}", result); + + return new ResponseEntity<>(result, HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ApiType.SAVE_CDUMP); + } + } +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/ConfigurationController.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/ConfigurationController.java new file mode 100644 index 0000000..4f083ca --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/ConfigurationController.java @@ -0,0 +1,63 @@ +package org.onap.sdc.dcae.composition.controller; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.dcae.composition.CompositionConfig; +import org.onap.sdc.dcae.errormng.ActionStatus; +import org.onap.sdc.dcae.errormng.ErrConfMgr; +import org.onap.sdc.dcae.ves.VesStructureLoader; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; + +@RestController +@EnableAutoConfiguration +@CrossOrigin +@RequestMapping("/conf") +public class ConfigurationController extends BaseController{ + + @Autowired + private CompositionConfig compositionConfig; + + @ApiOperation(value = "Get a list of available flow types", response = CompositionConfig.class) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Successfully retrieved available flow types list"), + @ApiResponse(code = 500, message = "Flow types couldn't be fetched due to internal error")}) + @RequestMapping(value = "/composition", method = RequestMethod.GET) + public ResponseEntity getCompositionConfig() { + try { + return new ResponseEntity<>(compositionConfig, HttpStatus.OK); + }catch (Exception e) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(),"Exception:{}",e); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.FLOW_TYPES_CONFIGURATION_ERROR); + } + } + + @RequestMapping(value = "/ves/schemaversions", method = RequestMethod.GET) + public ResponseEntity getCommonEventFormatVersion() { + try { + Set<String> availableVersionsSet = VesStructureLoader.getAvailableVersionsList(); + List<String> availableVersionsList = new ArrayList<>(availableVersionsSet.size()); + availableVersionsList.addAll(availableVersionsSet); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Got a request to return available ves schema versions: {}", availableVersionsSet); + return new ResponseEntity<>(availableVersionsList, HttpStatus.OK); + }catch (Exception e) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(),"Exception:{}",e); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.VES_SCHEMA_NOT_FOUND); + } + } + + +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/LifecycleController.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/LifecycleController.java new file mode 100644 index 0000000..3007335 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/LifecycleController.java @@ -0,0 +1,84 @@ +package org.onap.sdc.dcae.composition.controller; + +import org.onap.sdc.dcae.composition.restmodels.sdc.Asset; +import org.onap.sdc.dcae.composition.restmodels.sdc.ResourceDetailed; +import org.onap.sdc.dcae.enums.AssetType; +import org.onap.sdc.dcae.enums.LifecycleOperationType; +import org.onap.sdc.dcae.errormng.ErrConfMgr; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.UUID; + +@RestController +@EnableAutoConfiguration +@CrossOrigin +public class LifecycleController extends BaseController { + + private static final String VFCMT = "vfcmt"; + + @RequestMapping(value={"/checkin/{assetType}/{uuid}"}, method={RequestMethod.PUT}, produces={"application/json"}) + public ResponseEntity putCheckin( + @PathVariable("assetType") String assetType, + @PathVariable("uuid") UUID uuid, + @RequestHeader("USER_ID") String user_id, + @ModelAttribute("requestId") String requestId) { + + try { + switch (assetType) { + case VFCMT: + Asset res_checkin = checkin(user_id, uuid.toString(), AssetType.RESOURCE, requestId); + return new ResponseEntity<>(res_checkin, HttpStatus.OK); + + default: + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + } catch (Exception e) { + return handleException(e, ErrConfMgr.ApiType.CHECK_IN_RESOURCE); + } + } + + @RequestMapping(value={"/checkout/{assetType}/{uuid}"}, method={RequestMethod.PUT}, produces={"application/json"}) + public ResponseEntity putCheckout( + @PathVariable("assetType") String assetType, + @PathVariable("uuid") UUID uuid, + @RequestHeader("USER_ID") String user_id, + @ModelAttribute("requestId") String requestId) { + + try { + switch (assetType) { + case VFCMT: + Asset asset = checkout(user_id, uuid.toString(), AssetType.RESOURCE, requestId); + return new ResponseEntity<>(asset, HttpStatus.OK); + + default: + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + } catch (Exception e) { + return handleException(e, ErrConfMgr.ApiType.CHECK_OUT_RESOURCE); + } + } + + @RequestMapping(value={"/certify/{assetType}/{uuid}"}, method={RequestMethod.PUT}, produces={"application/json"}) + public ResponseEntity putCertify( + @PathVariable("assetType") String assetType, + @PathVariable("uuid") String uuid, + @RequestHeader("USER_ID") String user_id, + @ModelAttribute("requestId") String requestId) { + + try { + switch (assetType) { + case VFCMT: + ResourceDetailed vfcmt = baseBusinessLogic.getSdcRestClient().changeResourceLifecycleState(user_id, uuid, LifecycleOperationType.CERTIFY.name(), "certifying VFCMT", requestId); + return new ResponseEntity<>(vfcmt, HttpStatus.OK); + + default: + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); + } + } catch (Exception e) { + return handleException(e, ErrConfMgr.ApiType.CHECK_OUT_RESOURCE); + } + } +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/RuleEditorController.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/RuleEditorController.java new file mode 100644 index 0000000..3f5ff1a --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/RuleEditorController.java @@ -0,0 +1,453 @@ +package org.onap.sdc.dcae.composition.controller; + +import com.google.gson.JsonParseException; +import org.apache.commons.collections.ListUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.dcae.composition.restmodels.sdc.Artifact; +import org.onap.sdc.dcae.composition.restmodels.sdc.Asset; +import org.onap.sdc.dcae.composition.restmodels.sdc.ResourceDetailed; +import org.onap.sdc.dcae.composition.CompositionConfig; +import org.onap.sdc.dcae.utils.Normalizers; +import org.onap.sdc.dcae.composition.restmodels.ruleeditor.*; +import org.onap.sdc.dcae.composition.util.DcaeBeConstants; +import org.onap.sdc.dcae.enums.ArtifactType; +import org.onap.sdc.dcae.enums.AssetType; +import org.onap.sdc.dcae.errormng.ActionStatus; +import org.onap.sdc.dcae.errormng.ErrConfMgr; +import org.onap.sdc.dcae.errormng.ErrConfMgr.ApiType; +import org.onap.sdc.dcae.errormng.ServiceException; +import org.onap.sdc.dcae.rule.editor.impl.RulesBusinessLogic; +import org.onap.sdc.dcae.rule.editor.utils.RulesPayloadUtils; +import org.onap.sdc.dcae.utils.SdcRestClientUtils; +import org.onap.sdc.dcae.ves.VesDataItemsDefinition; +import org.onap.sdc.dcae.ves.VesDataTypeDefinition; +import org.onap.sdc.dcae.ves.VesSimpleTypesEnum; +import org.onap.sdc.dcae.ves.VesStructureLoader; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.util.Base64Utils; +import org.springframework.util.CollectionUtils; +import org.springframework.web.bind.annotation.*; + +import java.util.*; +import java.util.Map.Entry; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@RestController +@EnableAutoConfiguration +@CrossOrigin +@RequestMapping("/rule-editor") +public class RuleEditorController extends BaseController { + + private static final String EXCEPTION = "Exception {}"; + @Autowired + private CompositionConfig compositionConfig; + + @Autowired + private RulesBusinessLogic rulesBusinessLogic; + + @RequestMapping(value = "/list-events-by-versions", method = RequestMethod.GET) + public ResponseEntity getEventsByVersion() { + try { + + Map<String, Set<String>> eventsByVersions = VesStructureLoader.getAvailableVersionsAndEventTypes(); + + List<EventTypesByVersionUI> resBody = eventsByVersions.entrySet().stream().map(entry -> { + Set<String> events = entry.getValue().stream().filter(event -> !EventTypesByVersionUI.DEFAULT_EVENTS.contains(event)).collect(Collectors.toSet()); + return new EventTypesByVersionUI(entry.getKey(), events); + }).collect(Collectors.toList()); + + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Got a request to return all ves event types by versions {}", eventsByVersions); + return new ResponseEntity<>(resBody, HttpStatus.OK); + + } catch (Exception e) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), EXCEPTION, e); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.VES_SCHEMA_NOT_FOUND); + } + } + + @RequestMapping(value = { "/definition/{version:.*}/{eventType}" }, method = { RequestMethod.GET }, produces = { "application/json" }) + public ResponseEntity getDefinition(@PathVariable("version") String version, + @PathVariable("eventType") String eventType) { + + try { + List<EventTypeDefinitionUI> result = getEventTypeDefinitionUIs(version, eventType); + + return new ResponseEntity<>(result, HttpStatus.OK); + + } catch (Exception e) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), EXCEPTION, e); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.VES_SCHEMA_NOT_FOUND); + } + } + + /** + * This endpoint functions as a 'create/update' service for the rule editor UI + * + * @param json - json representing the saved rule + * @param vfcmtUuid - VFCMT that the rule editor ui is saved in + * @param dcaeCompLabel - the name of the DCAE Component which the rule is applied to + * @param nid - A unique id of the DCAE Component which the rule is applied to - exists also in the cdump + * @param configParam - the name of the DCAE Component configuration property the rule is linked to + * @return json representing the rule editor UI + * Validations: + * 1. That the user is able to edit the VFCMT + * 2. That the cdump holds a dcae component with such nid (to avoid orphan rules) + * 3. Check that the fetched VFCMT is actually a VFCMT and not a regular VF + */ + @RequestMapping(value = "/rule/{vfcmtUuid}/{dcaeCompLabel}/{nid}/{configParam}", method = { RequestMethod.POST }, produces = "application/json") + public ResponseEntity saveRule(@RequestBody String json, @ModelAttribute("requestId") String requestId, + @RequestHeader("USER_ID") String userId, + @PathVariable("vfcmtUuid") String vfcmtUuid, + @PathVariable("dcaeCompLabel") String dcaeCompLabel, + @PathVariable("nid") String nid, + @PathVariable("configParam") String configParam) { + try { + Rule rule = RulesPayloadUtils.parsePayloadToRule(json); + if (null == rule) { + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.INVALID_RULE_FORMAT); + } + + List<ServiceException> errors = rulesBusinessLogic.validateRule(rule); + if(!errors.isEmpty()){ + return ErrConfMgr.INSTANCE.buildErrorArrayResponse(errors); + } + + ResourceDetailed vfcmt = baseBusinessLogic.getSdcRestClient().getResource(vfcmtUuid, requestId); + checkVfcmtType(vfcmt); + + if (CollectionUtils.isEmpty(vfcmt.getArtifacts())) { + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.SAVE_RULE_FAILED); + } + + String artifactLabel = Normalizers.normalizeArtifactLabel(dcaeCompLabel + nid + configParam); + + // check for MappingRules artifact in existing artifacts + Artifact artifactFound = vfcmt.getArtifacts().stream() + .filter(a -> artifactLabel.equals(Normalizers.normalizeArtifactLabel(a.getArtifactLabel()))) + .findAny().orElse(null); + + // exception thrown if vfcmt is checked out and current user is not its owner + // performs vfcmt checkout if required + String vfcmtId = assertOwnershipOfVfcmtId(userId, vfcmt, requestId); + // new mappingRules artifact, validate nid exists in composition before creating new artifact + if (null == artifactFound) { + if(cdumpContainsNid(vfcmt, nid, requestId)) { + return saveNewRulesArtifact(rule, vfcmtId, generateMappingRulesFileName(dcaeCompLabel, nid, configParam), artifactLabel , userId, requestId); + } + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.NODE_NOT_FOUND, "", dcaeCompLabel); + } + + //update artifact flow - append new rule or edit existing rule + return addOrEditRuleInArtifact(rule, vfcmtId, userId, artifactFound, requestId); + + } catch (JsonParseException je) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Error: Rule format is invalid: {}", je); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.INVALID_RULE_FORMAT, "", je.getMessage()); + } catch (Exception e) { + return handleException(e, ErrConfMgr.ApiType.SAVE_RULE_ARTIFACT); + } + + } + + + /** + * This endpoint functions as a 'fetch' service for the rule editor UI + * + * @param vfcmtUuid - VFCMT that the rule editor ui is saved in + * @param dcaeCompLabel - the name of the DCAE Component which the rule is applied to + * @param nid - A unique id of the DCAE Component which the rule is applied to - exists also in the cdump + * @param configParam - the name of the DCAE Component configuration property the rule is linked to + * @return json representing the rule editor UI + */ + @RequestMapping(value = "/rule/{vfcmtUuid}/{dcaeCompLabel}/{nid}/{configParam}", method = { RequestMethod.GET }, produces = "application/json") + public ResponseEntity getRules( + @PathVariable("vfcmtUuid") String vfcmtUuid, + @PathVariable("dcaeCompLabel") String dcaeCompLabel, + @PathVariable("nid") String nid, + @PathVariable("configParam") String configParam, + @ModelAttribute("requestId") String requestId) { + + try { + ResourceDetailed vfcmt = baseBusinessLogic.getSdcRestClient().getResource(vfcmtUuid, requestId); + if (CollectionUtils.isEmpty(vfcmt.getArtifacts())) { + return new ResponseEntity<>("{}", HttpStatus.OK); + } + String artifactLabel = Normalizers.normalizeArtifactLabel(dcaeCompLabel + nid + configParam); + + // check for MappingRules artifact in existing artifacts + Artifact artifactListed = vfcmt.getArtifacts().stream().filter(a -> artifactLabel.equals(Normalizers.normalizeArtifactLabel(a.getArtifactLabel()))).findAny().orElse(null); + if (null == artifactListed) { + return new ResponseEntity<>("{}", HttpStatus.OK); + } + String ruleFile = baseBusinessLogic.getSdcRestClient().getResourceArtifact(vfcmtUuid, artifactListed.getArtifactUUID(), requestId); + + // To avoid opening the file for reading we search for the eventType and SchemaVer from the artifact metadata's description + SchemaInfo schemainfo = RulesPayloadUtils.extractInfoFromDescription(artifactListed); + List<EventTypeDefinitionUI> schema = null == schemainfo? new ArrayList<>() : getEventTypeDefinitionUIs(schemainfo.getVersion(), schemainfo.getEventType()); + return new ResponseEntity<>(RulesPayloadUtils.buildSchemaAndRulesResponse(ruleFile, schema), HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ApiType.GET_RULE_ARTIFACT); + } + + } + + /** + * This endpoint functions as a 'delete' service for the rule editor UI + * + * @param vfcmtUuid - VFCMT that the rule editor ui is saved in + * @param dcaeCompLabel - the name of the DCAE Component which the rule is applied to + * @param nid - A unique id of the DCAE Component which the rule is applied to - exists also in the cdump + * @param configParam - the name of the DCAE Component configuration property the rule is linked to + * @param ruleUid - the unique id of the rule to delete + * @return operation result + */ + @RequestMapping(value = "/rule/{vfcmtUuid}/{dcaeCompLabel}/{nid}/{configParam}/{ruleUid}", method = { RequestMethod.DELETE }, produces = "application/json") + public ResponseEntity deleteRule( + @RequestHeader("USER_ID") String userId, + @PathVariable("vfcmtUuid") String vfcmtUuid, + @PathVariable("dcaeCompLabel") String dcaeCompLabel, + @PathVariable("nid") String nid, + @PathVariable("configParam") String configParam, + @PathVariable("ruleUid") String ruleUid, + @ModelAttribute("requestId") String requestId){ + + try { + ResourceDetailed vfcmt = baseBusinessLogic.getSdcRestClient().getResource(vfcmtUuid, requestId); + if (null == vfcmt.getArtifacts()) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "VFCMT {} doesn't have artifacts", vfcmtUuid); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.DELETE_RULE_FAILED); + } + String artifactLabel = Normalizers.normalizeArtifactLabel(dcaeCompLabel + nid + configParam); + + // check for MappingRules artifact in existing artifacts + Artifact mappingRuleFile = vfcmt.getArtifacts().stream() + .filter(a -> artifactLabel.equals(Normalizers.normalizeArtifactLabel(a.getArtifactLabel()))) + .findAny().orElse(null); + + if (null == mappingRuleFile) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "{} doesn't exist for VFCMT {}", artifactLabel, vfcmtUuid); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.DELETE_RULE_FAILED); + } + + String vfcmtId = assertOwnershipOfVfcmtId(userId, vfcmt, requestId); + String payload = baseBusinessLogic.getSdcRestClient().getResourceArtifact(vfcmtId, mappingRuleFile.getArtifactUUID(), requestId); + MappingRules rules = RulesPayloadUtils.parseMappingRulesArtifactPayload(payload); + Rule removedRule = rulesBusinessLogic.deleteRule(rules, ruleUid); + if(null == removedRule){ + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Rule {} not found.", ruleUid); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.DELETE_RULE_FAILED); + } + if(rules.isEmpty()){ // if file doesn't contain any rules after last deletion -> let's delete the file + baseBusinessLogic.getSdcRestClient().deleteResourceArtifact(userId, vfcmtId, mappingRuleFile.getArtifactUUID(), requestId); + } else { + updateRulesArtifact(vfcmtId, userId, mappingRuleFile, rules, requestId); + } + return checkInAndReturnSaveArtifactResult(removedRule, vfcmtId, userId, requestId); + } catch (Exception e) { + return handleException(e, ApiType.SAVE_RULE_ARTIFACT); + } + + } + + /** + * This endpoint functions as a 'translate' service for the rule editor UI + * + * @param vfcmtUuid - VFCMT that the rule editor ui is saved in + * @param dcaeCompLabel - the name of the DCAE Component which the rule is applied to + * @param nid - A unique id of the DCAE Component which the rule is applied to - exists also in the cdump + * @param configParam - the name of the DCAE Component configuration property the rule is linked to + * @param flowType - the mapping rules flow type (SNMP,Syslog,FOI) + * @return translateJson representing the translated Rules + * Validations: + * 1. That the user is able to edit the VFCMT + * 2. That the cdump holds a dcae component with such nid (to avoid orphan rules) + * 3. Check that the fetched VFCMT is actually a VFCMT and not a regular VF + * @throws Exception + */ + @RequestMapping(value = "/rule/translate/{vfcmtUuid}/{dcaeCompLabel}/{nid}/{configParam}", method = { RequestMethod.GET }, produces = "application/json") + public ResponseEntity translateRules(@PathVariable("vfcmtUuid") String vfcmtUuid, @ModelAttribute("requestId") String requestId, + @PathVariable("dcaeCompLabel") String dcaeCompLabel, + @PathVariable("nid") String nid, + @PathVariable("configParam") String configParam, + @RequestParam("flowType") String flowType) throws Exception { + + try { + + if (StringUtils.isBlank(flowType) || MapUtils.isEmpty(compositionConfig.getFlowTypesMap()) || null == compositionConfig.getFlowTypesMap().get(flowType)) { + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.TRANSLATE_FAILED, "", "Flow type " + flowType + " not found"); + } + + // extract entry phase name and last phase name from configuration: + String entryPointPhaseName = compositionConfig.getFlowTypesMap().get(flowType).getEntryPointPhaseName(); + String lastPhaseName = compositionConfig.getFlowTypesMap().get(flowType).getLastPhaseName(); + + ResourceDetailed vfcmt = baseBusinessLogic.getSdcRestClient().getResource(vfcmtUuid, requestId); + checkVfcmtType(vfcmt); + + if (CollectionUtils.isEmpty(vfcmt.getArtifacts())) { + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.TRANSLATE_FAILED, "", "No rules found on VFCMT " + vfcmtUuid); + } + String artifactLabel = Normalizers.normalizeArtifactLabel(dcaeCompLabel + nid + configParam); + + // check for MappingRules artifact in existing artifacts + Artifact rulesArtifact = vfcmt.getArtifacts().stream().filter(a -> artifactLabel.equals(Normalizers.normalizeArtifactLabel(a.getArtifactLabel()))).findAny().orElse(null); + + if (rulesArtifact == null) { + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.TRANSLATE_FAILED, "", artifactLabel + " doesn't exist on VFCMT " + vfcmtUuid); + } + + String payload = baseBusinessLogic.getSdcRestClient().getResourceArtifact(vfcmtUuid, rulesArtifact.getArtifactUUID(), requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Retrieved mapping rules artifact {}, start parsing rules...", artifactLabel); + MappingRules rules = RulesPayloadUtils.parseMappingRulesArtifactPayload(payload); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Finished parsing rules, calling validator..."); + List<ServiceException> errors = rulesBusinessLogic.validateRules(rules); + if (!errors.isEmpty()) { + return ErrConfMgr.INSTANCE.buildErrorArrayResponse(errors); + } + + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Validation completed successfully, calling translator..."); + String translateJson = rulesBusinessLogic.translateRules(rules, entryPointPhaseName, lastPhaseName, vfcmt.getName()); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Translation completed successfully"); + return new ResponseEntity<>(translateJson, HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ApiType.SAVE_RULE_ARTIFACT); + } + } + + + ///////////////////PRIVATE METHODS//////////////////////////////////////////////////////////////////////// + + private String assertOwnershipOfVfcmtId(String userId, ResourceDetailed vfcmt, String requestId) throws Exception { + checkUserIfResourceCheckedOut(userId, vfcmt); + String newVfcmtId = vfcmt.getUuid(); // may change after checking out a certified vfcmt + if (isNeedToCheckOut(vfcmt.getLifecycleState())) { + Asset result = checkout(userId, newVfcmtId, AssetType.RESOURCE, requestId); + if (result != null) { + newVfcmtId = result.getUuid(); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "New resource after checkout is: {}", newVfcmtId); + } + } + return newVfcmtId; + } + + + + // called after validating vfcmt.getArtifacts() is not null + private boolean cdumpContainsNid(ResourceDetailed vfcmt, String nid, String requestId) { + Artifact cdump = vfcmt.getArtifacts().stream() + .filter(a -> DcaeBeConstants.Composition.fileNames.COMPOSITION_YML.equalsIgnoreCase(a.getArtifactName())) + .findAny().orElse(null); + if (null == cdump || null == cdump.getArtifactUUID()) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "No {} found on vfcmt {}", DcaeBeConstants.Composition.fileNames.COMPOSITION_YML, vfcmt.getUuid()); + return false; + } + try { + String artifact = baseBusinessLogic.getSdcRestClient().getResourceArtifact(vfcmt.getUuid(), cdump.getArtifactUUID(), requestId); + if (!artifact.contains("\"nid\":\""+nid)) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "{} doesn't contain nid {}. Cannot save mapping rule file", DcaeBeConstants.Composition.fileNames.COMPOSITION_YML, nid); + return false; + } + } catch (Exception e) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), EXCEPTION, e); + return false; + } + return true; + } + + private ResponseEntity<String> saveNewRulesArtifact(Rule rule, String vfcmtUuid, String artifactFileName, String artifactLabel, String userId, String requestId) throws Exception { + MappingRules body = new MappingRules(rule); + Artifact artifact = SdcRestClientUtils.generateDeploymentArtifact(body.describe(), artifactFileName, ArtifactType.OTHER.name(), artifactLabel, body.convertToPayload()); + baseBusinessLogic.getSdcRestClient().createResourceArtifact(userId, vfcmtUuid, artifact, requestId); + return checkInAndReturnSaveArtifactResult(rule, vfcmtUuid, userId, requestId); + } + + private ResponseEntity addOrEditRuleInArtifact(Rule rule, String vfcmtUuid, String userId, Artifact rulesArtifact, String requestId) throws Exception { + String payload = baseBusinessLogic.getSdcRestClient().getResourceArtifact(vfcmtUuid, rulesArtifact.getArtifactUUID(), requestId); + MappingRules rules = RulesPayloadUtils.parseMappingRulesArtifactPayload(payload); + + // in case the rule id is passed but the rule doesn't exist on the mapping rule file: + if(!rulesBusinessLogic.addOrEditRule(rules, rule)) { + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.SAVE_RULE_FAILED); + } + updateRulesArtifact(vfcmtUuid, userId, rulesArtifact, rules, requestId); + return checkInAndReturnSaveArtifactResult(rule, vfcmtUuid, userId, requestId); + } + + // regardless of check in result, return save artifact success + private ResponseEntity<String> checkInAndReturnSaveArtifactResult(Rule rule, String vfcmtUuid, String userId, String requestId) { + try { + checkin(userId, vfcmtUuid, AssetType.RESOURCE, requestId); + } catch (Exception e) { + // swallowing the exception intentionally since it is on the check in action + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Error occurred while performing check in on VFCMT {}:{}", vfcmtUuid, e); + } + return new ResponseEntity<>(rule.toJson(), HttpStatus.OK); + } + + private void updateRulesArtifact(String vfcmtUuid, String userId, Artifact artifactInfo, MappingRules rules, String requestId) throws Exception { + artifactInfo.setPayloadData(Base64Utils.encodeToString(rules.convertToPayload())); + // POST must contain 'description' while GET returns 'artifactDescription' + artifactInfo.setDescription(artifactInfo.getArtifactDescription()); + baseBusinessLogic.getSdcRestClient().updateResourceArtifact(userId, vfcmtUuid, artifactInfo, requestId); + } + + + /** + * @param eventMapStream + * @param parent + * @param path + * @return + */ + private List<EventTypeDefinitionUI> convertToEventTypeDefinition(Stream<Entry<String, VesDataTypeDefinition>> eventMapStream, VesDataTypeDefinition parent, String path) { + + return eventMapStream.map(entry -> { + Map<String, VesDataTypeDefinition> properties = entry.getValue().getProperties(); + VesDataItemsDefinition items = entry.getValue().getItems(); + String newPath = path + "." + entry.getKey(); + List<EventTypeDefinitionUI> children = (properties == null) ? null : convertToEventTypeDefinition(properties.entrySet().stream(), entry.getValue(), newPath); + if(VesSimpleTypesEnum.ARRAY.getType().equals(entry.getValue().getType())) { + newPath += "[]"; + if(innerTypeIsComplex(items)) { + children = convertComplexArrayType(items, newPath); + } else if(innerTypeIsArray(items)) { + newPath += "[]"; + } + } + + boolean isRequired = (parent != null) ? parent.getRequired().contains(entry.getKey()) : false; + return new EventTypeDefinitionUI(entry.getKey(), children, isRequired, newPath); + }).collect(Collectors.toList()); + } + + private boolean innerTypeIsComplex(VesDataItemsDefinition items){ + return items != null && items.stream().anyMatch(p -> p.getProperties() != null); + } + + private boolean innerTypeIsArray(VesDataItemsDefinition items){ + return items != null && items.stream().anyMatch(p -> p.getItems() != null); + } + + private List<EventTypeDefinitionUI> convertComplexArrayType(VesDataItemsDefinition items, String path){ + return items.stream().map(item -> item.getProperties() != null ? convertToEventTypeDefinition(item.getProperties().entrySet().stream(), item, path) : new ArrayList<EventTypeDefinitionUI>()) + .flatMap(List::stream).collect(Collectors.toList()); + } + + + private String generateMappingRulesFileName(String dcaeCompLabel, String nid, String configParam) { + return dcaeCompLabel + "_" + nid + "_" + configParam + DcaeBeConstants.Composition.fileNames.MAPPING_RULE_POSTFIX; + } + + private List<EventTypeDefinitionUI> getEventTypeDefinitionUIs(String version, String eventType) { + List<String> eventNamesToReturn = ListUtils.union(EventTypesByVersionUI.DEFAULT_EVENTS, Arrays.asList(eventType)); + Map<String, VesDataTypeDefinition> eventDefs = VesStructureLoader.getEventListenerDefinitionByVersion(version); + Stream<Entry<String, VesDataTypeDefinition>> filteredEvents = eventDefs.entrySet().stream().filter(entry -> eventNamesToReturn.contains(entry.getKey())); + + return convertToEventTypeDefinition(filteredEvents, null, "event"); + } +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/ServicesController.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/ServicesController.java new file mode 100644 index 0000000..257d1a9 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/ServicesController.java @@ -0,0 +1,230 @@ +package org.onap.sdc.dcae.composition.controller; + +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.dcae.composition.restmodels.AttachVFCMTServiceRequest; +import org.onap.sdc.dcae.composition.restmodels.DcaeMinimizedService; +import org.onap.sdc.dcae.composition.restmodels.MessageResponse; +import org.onap.sdc.dcae.composition.restmodels.sdc.*; +import org.onap.sdc.dcae.composition.util.DcaeBeConstants; +import org.onap.sdc.dcae.composition.util.DcaeBeConstants.LifecycleStateEnum; +import org.onap.sdc.dcae.enums.ArtifactType; +import org.onap.sdc.dcae.enums.LifecycleOperationType; +import org.onap.sdc.dcae.errormng.ActionStatus; +import org.onap.sdc.dcae.errormng.DcaeException; +import org.onap.sdc.dcae.errormng.ErrConfMgr; +import org.onap.sdc.dcae.errormng.ResponseFormat; +import org.onap.sdc.dcae.utils.SdcRestClientUtils; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.util.Base64Utils; +import org.springframework.util.CollectionUtils; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.stream.Collectors; + +@RestController +@EnableAutoConfiguration +@CrossOrigin +public class ServicesController extends BaseController { + + /*** + * GET services list by VFCMT + * @param userId + * @param vfcmtUuid + * @return ResponseEntity + */ + @RequestMapping(value = { "/services/{vfcmtUuid}" }, method = { RequestMethod.GET }, produces = {"application/json" }) + public ResponseEntity services(@RequestHeader("USER_ID") String userId, @PathVariable String vfcmtUuid, @ModelAttribute("requestId") String requestId) { + try { + ResourceDetailed vfcmt = baseBusinessLogic.getSdcRestClient().getResource(vfcmtUuid, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "GET ({}) Vfcmt form SDC: {}", vfcmtUuid, vfcmt); + checkVfcmtType(vfcmt); + checkUserIfResourceCheckedOut(userId, vfcmt); + + List<Service> services = baseBusinessLogic.getSdcRestClient().getServices(requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "GET services data from SDC: {}", services); + List<Service> uuids = filterServicesByUser(services, userId); + return new ResponseEntity<>(uuids, HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ErrConfMgr.ApiType.GET_SERVICE); + } + } + + /*** + * GET a single service + * @param theServiceId + * @return ResponseEntity + */ + @RequestMapping(value = { "/service/{theServiceId}" }, method = { RequestMethod.GET }, produces = {"application/json" }) + public ResponseEntity service(@PathVariable String theServiceId, @ModelAttribute("requestId") String requestId) { + try { + ServiceDetailed service = baseBusinessLogic.getSdcRestClient().getService(theServiceId, requestId); + if (service != null) { + if(service.getResources()!=null){ + List<ResourceInstance> vfResourcesOnly = service.getResources().stream().filter(vfi -> vfi.getResoucreType().equals("VF")).collect(Collectors.toList()); + service.setResources(vfResourcesOnly); + }else{ + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Service {} doesn't have any resources (e.g VFi's)", theServiceId); + } + } else { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Couldn't fetch service with uuid {} from SDC", theServiceId); + } + return new ResponseEntity<>(service, HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ErrConfMgr.ApiType.GET_SERVICE); + } + } + + + /*** + * Attach service and service instance to VFCMT + * @param userId + * @param request + * @return ResponseEntity + */ + @RequestMapping(value = "/{vfcmtUuid}/attachment", method = RequestMethod.POST, produces = {"application/json" }) + public ResponseEntity attachService( + @PathVariable("vfcmtUuid") String vfcmtUuid, + @RequestHeader("USER_ID") String userId, + @RequestBody AttachVFCMTServiceRequest request, + @ModelAttribute("requestId") String requestId) { + + String serviceUuid = request.getServiceUuid(); + String vfiName = request.getInstanceName(); + String resourceUuid = vfcmtUuid; + MessageResponse response = new MessageResponse(); + + try { + ResourceDetailed vfcmt = baseBusinessLogic.getSdcRestClient().getResource(vfcmtUuid, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), vfcmt.toString()); + + checkVfcmtType(vfcmt); + verifyVfiExists(serviceUuid, vfiName, requestId); + + boolean isUpdateMode = false; + Artifact artifactObj = null; + + String reference = serviceUuid + "/resources/" + vfiName; + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "*****************************************"); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Reference between service and vfi {}", reference); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "*****************************************"); + + if(!CollectionUtils.isEmpty(vfcmt.getArtifacts())){ + artifactObj = vfcmt.getArtifacts().stream().filter(a -> DcaeBeConstants.Composition.fileNames.SVC_REF.equals(a.getArtifactName())).findAny().orElse(null); + isUpdateMode = null != artifactObj; + } + + if (isNeedToCheckOut(vfcmt.getLifecycleState())) { + vfcmt = baseBusinessLogic.getSdcRestClient().changeResourceLifecycleState(userId, vfcmtUuid, LifecycleOperationType.CHECKOUT.name(), null, requestId); + if (vfcmt != null) { + resourceUuid = vfcmt.getUuid(); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "New vfcmt uuid after checkout is: {}", resourceUuid); + } + } + + if(isUpdateMode){ + updateReferenceArtifact(userId, resourceUuid, artifactObj, reference, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Artifact {} updated with content: {}", reference, DcaeBeConstants.Composition.fileNames.SVC_REF, reference); + }else{ + Artifact artifact = SdcRestClientUtils.generateDeploymentArtifact("createReferenceArtifact", DcaeBeConstants.Composition.fileNames.SVC_REF, ArtifactType.DCAE_TOSCA.name(), "servicereference", reference.getBytes()); + baseBusinessLogic.getSdcRestClient().createResourceArtifact(userId, resourceUuid, artifact, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Artifact {} created with content: {}", DcaeBeConstants.Composition.fileNames.SVC_REF, reference); + } + checkin(userId, resourceUuid, org.onap.sdc.dcae.enums.AssetType.RESOURCE, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Attachment of reference={} in VFCMT {} has finished successfully", reference, resourceUuid); + + response.setSuccessResponse("Artifact updated"); + return new ResponseEntity<>(response, HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ErrConfMgr.ApiType.ATTACH_TO_SERVICE); + } + } + + @RequestMapping(value = { "/{vfcmtUuid}/attachment" }, method = { RequestMethod.GET }, produces = {"application/json" }) + public ResponseEntity getAttachedService(@PathVariable("vfcmtUuid") String vfcmtUuid, @ModelAttribute("requestId") String requestId) { + + MessageResponse response = new MessageResponse(); + + try { + ResourceDetailed vfcmt = baseBusinessLogic.getSdcRestClient().getResource(vfcmtUuid, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), vfcmt.toString()); + checkVfcmtType(vfcmt); + String artifact = "No Artifacts"; + + if (!CollectionUtils.isEmpty(vfcmt.getArtifacts())) { + Artifact artifactObj = vfcmt.getArtifacts().stream().filter(a -> DcaeBeConstants.Composition.fileNames.SVC_REF.equals(a.getArtifactName())).findAny().orElse(null); + if (null != artifactObj) + artifact = baseBusinessLogic.getSdcRestClient().getResourceArtifact(vfcmtUuid, artifactObj.getArtifactUUID(), requestId); + } + response.setSuccessResponse(artifact); + return new ResponseEntity<>(response, HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ErrConfMgr.ApiType.GET_VFCMT); + } + } + + /**** PRIVATE METHODS ****/ + + private void updateReferenceArtifact(String userId, String VFCMTUuid, Artifact artifactObj, String reference, String requestId) throws Exception { + artifactObj.setDescription("updateReferenceArtifact"); + artifactObj.setPayloadData(Base64Utils.encodeToString(reference.getBytes())); + baseBusinessLogic.getSdcRestClient().updateResourceArtifact(userId, VFCMTUuid, artifactObj, requestId); + } + + + /** + * + * @param lastUpdaterUserId + * @param services + * @param userId + * @return + */ + + //TODO move method to ci tests + public List<DcaeMinimizedService> parseAndFilterServicesByUser(String lastUpdaterUserId, List<LinkedHashMap<String, String>> services, String userId) { + List<DcaeMinimizedService> uuids = null; + if (services != null) { + //services.stream().filter(predicate) + uuids = services.stream() + .map(x -> new DcaeMinimizedService(x.get("uuid"), x.get("name"), x.get("lastUpdaterUserId"), x.get("lifecycleState"), x.get("version"), x.get("invariantUUID"))) + .collect(Collectors.groupingBy(DcaeMinimizedService::getInvariantUUID)).values().stream() + .map(p -> p.stream() + .sorted(Comparator.comparing(DcaeMinimizedService::getVersionAsFloat).reversed())).map(p -> p.collect(Collectors.toList())).map(p -> p.get(0)) + .filter(x -> (!(!x.getLastUpdaterUserId().equals(userId) && x.getLifeCycleState().equals(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name())))) + .sorted(Comparator.comparing(DcaeMinimizedService::getName)).collect(Collectors.toList()); + } + return uuids; + } + + private List<Service> filterServicesByUser(List<Service> services, String userId) { + return CollectionUtils.isEmpty(services) ? new ArrayList<>() : services.stream() + .collect(Collectors.groupingBy(Service::getInvariantUUID)).values().stream() + .map(p -> p.stream() + .sorted(Comparator.comparing(Service::versionAsFloat).reversed())).map(p -> p.collect(Collectors.toList())).map(p -> p.get(0)) + .filter(x -> (!(!x.getLastUpdaterUserId().equals(userId) && x.getLifecycleState().equals(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT.name())))) + .sorted(Comparator.comparing(Service::getName)).collect(Collectors.toList()); + } + + /** + * + * @param serviceUuid + * @param vfiName + * @param requestId + * @throws Exception + */ + private void verifyVfiExists(String serviceUuid, String vfiName, String requestId) throws Exception { + ServiceDetailed service = baseBusinessLogic.getSdcRestClient().getService(serviceUuid, requestId); + boolean isServiceContainsVfi = null != service && !CollectionUtils.isEmpty(service.getResources()) && service.getResources().stream() + .filter(vfi -> "VF".equals(vfi.getResoucreType())) + .anyMatch(vfi -> vfiName.equals(vfi.getResourceInstanceName())); + if (!isServiceContainsVfi) { + ResponseFormat responseFormat = ErrConfMgr.INSTANCE.getResponseFormat(ActionStatus.VFI_FETCH_ERROR, null, serviceUuid, vfiName); + throw new DcaeException(HttpStatus.NOT_FOUND, responseFormat.getRequestError()); + } + } +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/VfcmtController.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/VfcmtController.java new file mode 100644 index 0000000..0e1b209 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/VfcmtController.java @@ -0,0 +1,183 @@ +package org.onap.sdc.dcae.composition.controller; + +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.dcae.composition.impl.ReferenceBusinessLogic; +import org.onap.sdc.dcae.composition.impl.VfcmtBusinessLogic; +import org.onap.sdc.dcae.composition.restmodels.CreateVFCMTRequest; +import org.onap.sdc.dcae.composition.restmodels.ImportVFCMTRequest; +import org.onap.sdc.dcae.composition.restmodels.sdc.ExternalReferencesMap; +import org.onap.sdc.dcae.composition.restmodels.sdc.Resource; +import org.onap.sdc.dcae.composition.restmodels.sdc.ResourceDetailed; +import org.onap.sdc.dcae.errormng.ErrConfMgr.ApiType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@EnableAutoConfiguration +@CrossOrigin +public class VfcmtController extends BaseController{ + + + @Autowired + private VfcmtBusinessLogic vfcmtBusinessLogic; + @Autowired + private ReferenceBusinessLogic referenceBusinessLogic; + + private static final String VFCMT = "VFCMT"; + private static final String TEMPLATE = "Template"; + private static final String BASE_MONITORING_TEMPLATE = "Base Monitoring Template"; + + + + /*** + * Get one resource information + * @param theResourceId retrieved resource id + * @return ResponseEntity + */ + @RequestMapping(value = { "/resource/{theResourceId}" }, method = { RequestMethod.GET }, produces = {"application/json" }) + public ResponseEntity resource(@PathVariable String theResourceId, @ModelAttribute("requestId") String requestId) { + try { + ResourceDetailed resource = baseBusinessLogic.getSdcRestClient().getResource(theResourceId, requestId); + return new ResponseEntity<>(resource, HttpStatus.OK); + }catch (Exception e) { + return handleException(e, ApiType.GET_VFCMT); + } + } + + /*** + * Get All resources + * @return ResponseEntity + */ + @RequestMapping(value = { "/getResourcesByCategory" }, method = { RequestMethod.GET }, produces = {"application/json" }) + public ResponseEntity getResourcesByCategory(@ModelAttribute("requestId") String requestId) { + try { + List<Resource> resources = baseBusinessLogic.getSdcRestClient().getResources(VFCMT, null, null, requestId); + return new ResponseEntity<>(resources, HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ApiType.GET_ALL_VFCMTS); + } + } + + /*** + * Get All resources by Service + * @return ResponseEntity + */ + + @RequestMapping(value = { "/{contextType}/{uuid}/{version}/getVfcmtsForMigration" }, method = { RequestMethod.GET }, produces = {"application/json" }) + public ResponseEntity getVfcmtsForMigration(@RequestHeader("USER_ID") String userId, + @PathVariable String contextType, + @PathVariable String uuid, + @PathVariable String version, + @ModelAttribute("requestId") String requestId){ + + return vfcmtBusinessLogic.getVfcmtsForMigration(userId, contextType, uuid, version, requestId); + } + + /*** + * Get All resources by Monitoring Template Category + * @return ResponseEntity + */ + @RequestMapping(value = { "/getResourcesByMonitoringTemplateCategory" }, method = { RequestMethod.GET }, produces = {"application/json" }) + public ResponseEntity getResourcesByMonitoringTemplateCategory(@ModelAttribute("requestId") String requestId) { + try { + List<Resource> resources = baseBusinessLogic.getSdcRestClient().getResources(VFCMT, TEMPLATE, BASE_MONITORING_TEMPLATE, requestId); + return new ResponseEntity<>(resources, HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ApiType.GET_ALL_VFCMTS); + } + } + + /*** + * Create new Vfcmt + * @param userId retrieved user ID + * @param request retrieved request + * @return ResponseEntity + */ + @RequestMapping(value = "/createVFCMT", method = RequestMethod.POST, produces = {"application/json" }) + public ResponseEntity createVFCMT(@RequestHeader("USER_ID") String userId, @RequestBody CreateVFCMTRequest request, @ModelAttribute("requestId") String requestId) { + vfcmtBusinessLogic.addSdcMandatoryFields(request, userId); + try { + ResourceDetailed response = baseBusinessLogic.getSdcRestClient().createResource(userId, request, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "createVFCMT after post: {}", response); + return new ResponseEntity<>(response, HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ApiType.CREATE_NEW_VFCMT); + } + } + + /*** + * Create new Vfcmt from general screen + * @param userId retrieved user ID + * @param request retrieved request + * @return ResponseEntity + */ + @RequestMapping(value = "/createMC", method = RequestMethod.POST, produces = {"application/json" }) + public ResponseEntity createMC(@RequestHeader("USER_ID") String userId, @RequestBody CreateVFCMTRequest request, @ModelAttribute("requestId") String requestId) { + return vfcmtBusinessLogic.createMcFromTemplate(userId, request, requestId); + } + + + /*** + * Clone or import existing VFCMT and attach to selected service/resource + * @param userId + * @param request + * @return ResponseEntity + */ + @RequestMapping(value = "/importMC", method = RequestMethod.POST, produces = {"application/json" }) + public ResponseEntity importMC(@RequestHeader("USER_ID") String userId, @RequestBody ImportVFCMTRequest request, @ModelAttribute("requestId") String requestId) { + return vfcmtBusinessLogic.importMC(userId, request, requestId); + } + + /*** + * GET a list of Monitoring Components of a service by uuid and version + * @param context the context type of this request + * @param uuid the uuid of the type requested + * @param version the version of the entity requested + * @return ResponseEntity + */ + @RequestMapping(value = { "/{context}/{uuid}/{version}/monitoringComponents" }, method = { RequestMethod.GET }, produces = {"application/json" }) + public ResponseEntity getMonitoringComponents(@PathVariable String context, @PathVariable String uuid, @PathVariable String version, @ModelAttribute("requestId") String requestId) { + try { + ExternalReferencesMap mcRefs = baseBusinessLogic.getSdcRestClient().getMonitoringReferences(context, uuid, version, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Got monitoring references map from SDC: {}", mcRefs.values()); + return new ResponseEntity<>(referenceBusinessLogic.fetchMonitoringComponents(mcRefs, requestId), HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ApiType.GET_SERVICE); + } + } + + @RequestMapping(value = { "/{context}/{serviceUuid}/{vfiName}/{vfcmtUuid}/deleteVfcmtReference" }, method = { RequestMethod.DELETE }, produces = {"application/json" }) + public ResponseEntity deleteVfcmtReference(@RequestHeader("USER_ID") String userId, @PathVariable String context, @PathVariable String serviceUuid, @PathVariable String vfiName, @PathVariable String vfcmtUuid, @ModelAttribute String requestId) { + try { + referenceBusinessLogic.deleteVfcmtReference(userId, context, serviceUuid, vfiName, vfcmtUuid, requestId); + return new ResponseEntity<>(HttpStatus.OK); + } catch (Exception e) { + return handleException(e, ApiType.DELETE_VFCMT_REFERENCE); + } + } + + @RequestMapping(value = { "/{context}/{monitoringComponentName}/{serviceUuid}/{vfiName}/{vfcmtUuid}/deleteVfcmtReference" }, method = { RequestMethod.DELETE }, produces = {"application/json" }) + public ResponseEntity deleteVfcmtReferenceWithBlueprint(@RequestHeader("USER_ID") String userId, @PathVariable String context, @PathVariable String monitoringComponentName, @PathVariable String serviceUuid, @PathVariable String vfiName, @PathVariable String vfcmtUuid, @ModelAttribute String requestId) { + try { + referenceBusinessLogic.deleteVfcmtReference(userId, context, serviceUuid, vfiName, vfcmtUuid, requestId); + } catch (Exception e) { + return handleException(e, ApiType.DELETE_VFCMT_REFERENCE); + } + return referenceBusinessLogic.deleteVfcmtReferenceBlueprint(userId, context, monitoringComponentName, serviceUuid, vfiName, vfcmtUuid, requestId); + } + + @RequestMapping(value = { "/getVfcmtReferenceData/{vfcmtUuid}" }, method = { RequestMethod.GET }, produces = {"application/json" }) + public ResponseEntity getVfcmtReferenceData(@PathVariable String vfcmtUuid, @ModelAttribute String requestId) { + try { + return vfcmtBusinessLogic.getVfcmtReferenceData(vfcmtUuid, requestId); + } catch (Exception e) { + return handleException(e, ApiType.GET_VFCMT); + } + } + +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/health/HealthController.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/health/HealthController.java new file mode 100644 index 0000000..eaad1b0 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/health/HealthController.java @@ -0,0 +1,77 @@ +package org.onap.sdc.dcae.composition.controller.health; + +import java.util.ArrayList; +import java.util.List; + +import org.onap.sdc.common.onaplog.OnapLoggerDebug; +import org.onap.sdc.common.onaplog.OnapLoggerError; +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.dcae.composition.restmodels.health.ComponentsInfo; +import org.onap.sdc.dcae.composition.restmodels.health.HealthResponse; +import org.onap.sdc.dcae.composition.CompositionEngine; +import org.onap.sdc.dcae.composition.util.DcaeBeConstants; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import com.google.gson.Gson; + +@RestController +@EnableAutoConfiguration +@CrossOrigin +public class HealthController { + private static OnapLoggerError errLogger = OnapLoggerError.getInstance(); + private static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + Gson gson = new Gson(); + + @Autowired + ToscaLabHealthState toscaLabHealthState; + + @RequestMapping(value = "/healthCheck", method = RequestMethod.GET) + public ResponseEntity<String> healthCheck() { + HttpStatus httpSts = HttpStatus.OK; + try{ + HealthResponse healthResponse = new HealthResponse(); + healthResponse.setHealthCheckComponent(DcaeBeConstants.Health.APP_NAME); + healthResponse.setHealthCheckStatus(DcaeBeConstants.Health.UP); + healthResponse.setSdcVersion(CompositionEngine.getDcaeVersion()); + healthResponse.setDescription(DcaeBeConstants.Health.OK); + + List<ComponentsInfo> componentsInfoList = new ArrayList<ComponentsInfo>(); + ComponentsInfo componentsInfo = new ComponentsInfo(); + componentsInfo.setHealthCheckComponent(DcaeBeConstants.Health.BE); + componentsInfo.setHealthCheckStatus(DcaeBeConstants.Health.UP); + componentsInfo.setVersion(CompositionEngine.getDcaeVersion()); + componentsInfo.setDescription(DcaeBeConstants.Health.OK); + componentsInfoList.add(componentsInfo); + + ComponentsInfo toscaLab = new ComponentsInfo(); + ComponentsInfo toscaLabHealthRes = toscaLabHealthState.getToscaLabHealthResponse(); + if(toscaLabHealthRes.getHealthCheckStatus().equals(DcaeBeConstants.Health.DOWN)){ + healthResponse.setHealthCheckStatus(DcaeBeConstants.Health.DOWN); + healthResponse.setDescription(toscaLabHealthRes.getHealthCheckComponent()+" is down"); + httpSts = HttpStatus.INTERNAL_SERVER_ERROR; + } + toscaLab.setHealthCheckComponent(toscaLabHealthRes.getHealthCheckComponent()); + toscaLab.setHealthCheckStatus(toscaLabHealthRes.getHealthCheckStatus()); + toscaLab.setVersion(toscaLabHealthRes.getVersion()); + toscaLab.setDescription(toscaLabHealthRes.getDescription()); + componentsInfoList.add(toscaLab); + + healthResponse.setComponentsInfo(componentsInfoList); + String json = gson.toJson(healthResponse, HealthResponse.class); + + return new ResponseEntity<String>(json, httpSts); + } + catch(Exception e){ + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Error occured while performing HealthCheck: {}", e.getLocalizedMessage()); + return new ResponseEntity<String>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + } + } + +}
\ No newline at end of file diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/health/HealthPoller.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/health/HealthPoller.java new file mode 100644 index 0000000..609480d --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/health/HealthPoller.java @@ -0,0 +1,97 @@ +package org.onap.sdc.dcae.composition.controller.health; + +import java.net.URI; +import java.util.Collections; + +import org.onap.sdc.common.onaplog.OnapLoggerDebug; +import org.onap.sdc.common.onaplog.OnapLoggerError; +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.dcae.composition.restmodels.health.ComponentsInfo; +import org.onap.sdc.dcae.catalog.commons.Future; +import org.onap.sdc.dcae.catalog.commons.Http; +import org.onap.sdc.dcae.composition.util.DcaeBeConstants; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; + +import com.google.gson.Gson; + +@Configuration +@EnableAsync +@EnableScheduling +@ConfigurationProperties(prefix="blueprinter") +public class HealthPoller { + private URI hcuri; + private String hcretrynum; + private Gson gson; + + private OnapLoggerError errLogger = OnapLoggerError.getInstance(); + private OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + + @Autowired + private ToscaLabHealthState toscaLabHealthState; + + public HealthPoller() { + super(); + gson = new Gson(); + } + + @Scheduled(fixedDelayString="${healthpoller.fixedDelay}") + public void pollToscaLabHealth() { + ComponentsInfo toscaLabHealthRes = null; + ResponseEntity<String> healthRes = null; + try { + for(int i=0; i<Integer.valueOf(hcretrynum); i++){ // 3 tries + healthRes = sendHealthCheck(); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Try #{}: {}", i, healthRes); + if(healthRes.getStatusCode()==HttpStatus.OK){ + String result = (String) healthRes.getBody(); + toscaLabHealthRes = gson.fromJson(result, ComponentsInfo.class); + break; + } + } + } catch (Exception e) { + toscaLabHealthRes = getNegativeHealth(e.getMessage()); + } + if(toscaLabHealthRes == null){ + toscaLabHealthRes = getNegativeHealth(healthRes.getBody() + "-" + healthRes.getStatusCode()); + } + toscaLabHealthState.setToscaLabHealthResponse(toscaLabHealthRes); + } + + private ComponentsInfo getNegativeHealth(String msg) { + ComponentsInfo toscaLabHealthRes = new ComponentsInfo(); + String description = "DCAE-D BE failed while trying to fetch Tosca_Lab healthcheck. Exception: " +msg; + toscaLabHealthRes.setDescription(description); + toscaLabHealthRes.setHealthCheckComponent(DcaeBeConstants.Health.TOSCA_LAB); + toscaLabHealthRes.setHealthCheckStatus(DcaeBeConstants.Health.DOWN); + errLogger.log(LogLevel.ERROR, this.getClass().getName(), description); + return toscaLabHealthRes; + } + + public ResponseEntity<String> sendHealthCheck() { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); + HttpEntity<String> entity = new HttpEntity<String>(headers); + return Http.exchangeSync(hcuri.toString(), HttpMethod.GET, entity, String.class, 5000); + } + + public void setHcuri(URI hcuri) { + this.hcuri = hcuri; + } + + public void setHcretrynum(String hcretrynum) { + this.hcretrynum = hcretrynum; + } + +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/health/ToscaLabHealthState.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/health/ToscaLabHealthState.java new file mode 100644 index 0000000..6fe469f --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/health/ToscaLabHealthState.java @@ -0,0 +1,29 @@ +package org.onap.sdc.dcae.composition.controller.health; + +import org.onap.sdc.dcae.composition.restmodels.health.ComponentsInfo; +import org.onap.sdc.dcae.composition.util.DcaeBeConstants; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +@Scope(value = "singleton") +@Component +public class ToscaLabHealthState { + private ComponentsInfo toscaLabHealthResponse; + + public ToscaLabHealthState() { + super(); + toscaLabHealthResponse = new ComponentsInfo(); + toscaLabHealthResponse.setDescription("Not up yet"); + toscaLabHealthResponse.setHealthCheckComponent(DcaeBeConstants.Health.TOSCA_LAB); + toscaLabHealthResponse.setHealthCheckStatus(DcaeBeConstants.Health.DOWN); + } + + public ComponentsInfo getToscaLabHealthResponse() { + return toscaLabHealthResponse; + } + + public void setToscaLabHealthResponse(ComponentsInfo toscaLabHealthResponse) { + this.toscaLabHealthResponse = toscaLabHealthResponse; + } + +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/swagger/SwaggerConfig.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/swagger/SwaggerConfig.java new file mode 100644 index 0000000..48c7153 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/controller/swagger/SwaggerConfig.java @@ -0,0 +1,23 @@ +package org.onap.sdc.dcae.composition.controller.swagger; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +@Configuration +@EnableSwagger2 +public class SwaggerConfig { + @Bean + public Docket productApi() { + return new Docket(DocumentationType.SWAGGER_2) + .select() + .apis(RequestHandlerSelectors.basePackage("org.onap.sdc.dcae.composition.controller")) + .paths(PathSelectors.regex("/*.*")) + .build(); + } +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/BaseBusinessLogic.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/BaseBusinessLogic.java new file mode 100644 index 0000000..f26c885 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/BaseBusinessLogic.java @@ -0,0 +1,49 @@ +package org.onap.sdc.dcae.composition.impl; + +import org.onap.sdc.common.onaplog.OnapLoggerDebug; +import org.onap.sdc.common.onaplog.OnapLoggerError; +import org.onap.sdc.dcae.client.ISdcClient; +import org.onap.sdc.dcae.composition.restmodels.sdc.Artifact; +import org.onap.sdc.dcae.composition.restmodels.sdc.ResourceDetailed; +import org.onap.sdc.dcae.utils.SdcRestClientUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.Base64Utils; +import org.springframework.util.CollectionUtils; + +@Component +public class BaseBusinessLogic { + @Autowired + protected ISdcClient sdcRestClient; + + protected static OnapLoggerError errLogger = OnapLoggerError.getInstance(); + protected static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + + public ISdcClient getSdcRestClient() { + return sdcRestClient; + } + + void setSdcRestClient(ISdcClient sdcRestClient) { + this.sdcRestClient = sdcRestClient; + } + + Artifact cloneArtifactToTarget(String userId, String targetId, String payload, Artifact artifactToClone, String requestId) throws Exception { + Artifact cloned = SdcRestClientUtils.generateDeploymentArtifact(artifactToClone.getArtifactDescription(), artifactToClone.getArtifactName(), artifactToClone.getArtifactType(), artifactToClone.getArtifactLabel(), payload.getBytes()); + return sdcRestClient.createResourceArtifact(userId, targetId, cloned, requestId); + } + + public void cloneArtifactToTarget(String userId, String targetId, String payload, Artifact artifactToClone, Artifact artifactToOverride, String requestId) throws Exception{ + if (null != artifactToOverride) { + artifactToOverride.setDescription(artifactToOverride.getArtifactDescription()); + artifactToOverride.setPayloadData(Base64Utils.encodeToString(payload.getBytes())); + sdcRestClient.updateResourceArtifact(userId, targetId, artifactToOverride, requestId); + } else { + cloneArtifactToTarget(userId, targetId, payload, artifactToClone, requestId); + } + } + + Artifact findArtifactDataByArtifactName(ResourceDetailed vfcmt, String artifactName) { + return null == vfcmt ? null : CollectionUtils.isEmpty(vfcmt.getArtifacts()) ? null : vfcmt.getArtifacts().stream() + .filter(p -> artifactName.equals(p.getArtifactName())).findAny().orElse(null); + } +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/ReferenceBusinessLogic.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/ReferenceBusinessLogic.java new file mode 100644 index 0000000..d229b67 --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/ReferenceBusinessLogic.java @@ -0,0 +1,74 @@ +package org.onap.sdc.dcae.composition.impl; + +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.dcae.composition.restmodels.MonitoringComponent; +import org.onap.sdc.dcae.composition.restmodels.sdc.Artifact; +import org.onap.sdc.dcae.composition.restmodels.sdc.ExternalReferencesMap; +import org.onap.sdc.dcae.composition.restmodels.sdc.ResourceInstance; +import org.onap.sdc.dcae.composition.restmodels.sdc.ServiceDetailed; +import org.onap.sdc.dcae.errormng.ActionStatus; +import org.onap.sdc.dcae.errormng.ErrConfMgr; +import org.onap.sdc.dcae.utils.Normalizers; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; + +import java.util.*; + +import static org.springframework.util.CollectionUtils.isEmpty; + +@Component +public class ReferenceBusinessLogic extends BaseBusinessLogic { + + public ResponseEntity deleteVfcmtReferenceBlueprint(String userId, String context, String monitoringComponentName, String serviceUuid, String vfiName, String vfcmtUuid, String requestId) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Going to delete blueprint, monitoringComponentName = {}, vfiName = {}", monitoringComponentName, vfiName); + try { + String normalizedVfiName = Normalizers.normalizeComponentInstanceName(vfiName); + ServiceDetailed serviceDetailed = sdcRestClient.getService(serviceUuid, requestId); + Optional<ResourceInstance> resourceInstance = serviceDetailed.getResources().stream().filter(item -> item.getResourceInstanceName().equalsIgnoreCase(vfiName)).findAny(); + if (resourceInstance.isPresent() && resourceInstance.get().getArtifacts() != null) { + Optional<Artifact> artifact = resourceInstance.get().getArtifacts().stream().filter(item -> item.getArtifactName().contains(monitoringComponentName)).findAny(); + artifact.ifPresent(artifact1 -> sdcRestClient.deleteInstanceResourceArtifact(userId, context, serviceUuid, normalizedVfiName, artifact1.getArtifactUUID(), requestId)); + } + } catch (Exception e) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(),"Failed to delete blueprint with serviceUuid {}, vfcmtUuid . message: {} ", serviceUuid, vfcmtUuid, e); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.DELETE_BLUEPRINT_FAILED); + } + return new ResponseEntity<>(HttpStatus.OK); + } + + public void deleteVfcmtReference(String userId, String context, String serviceUuid, String vfiName, String vfcmtUuid, String requestId) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Going to delete vfcmt reference, vfiName = {}", vfiName); + String normalizedVfiName = Normalizers.normalizeComponentInstanceName(vfiName); + sdcRestClient.deleteExternalMonitoringReference(userId, context, serviceUuid, normalizedVfiName, vfcmtUuid, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Finished to delete vfcmt reference. serviceUuid {}, vfcmtUuid {}", serviceUuid, vfcmtUuid); + } + + // 1806 US381853 Return a list of monitoring components by external reference id. Support partial success + public Map<String, List<MonitoringComponent>> fetchMonitoringComponents(ExternalReferencesMap mcRefs, String requestId) { + + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Going to fetch monitoring components metadata for vfis {}", mcRefs.keySet()); + Map<String, List<MonitoringComponent>> result = new LinkedHashMap<>(); + List<MonitoringComponent> monitoringComponents = Collections.synchronizedList(new ArrayList<>()); + List<MonitoringComponent> unavailable = Collections.synchronizedList(new ArrayList<>()); + mcRefs.entrySet().parallelStream().forEach(entry -> + entry.getValue().parallelStream().forEach(id -> { + try{ + monitoringComponents.add(new MonitoringComponent(getSdcRestClient().getResource(id, requestId), entry.getKey())); + } catch (Exception e) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(),"Failed to fetch monitoring component with uuid {}. message: {} ", id, e); + unavailable.add(new MonitoringComponent(id, entry.getKey(), "unavailable")); + } + + }) + ); + result.put("monitoringComponents", monitoringComponents); + if(!isEmpty(unavailable)) { + result.put("unavailable", unavailable); + } + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Finished fetching monitoring components metadata for vfis {}", mcRefs.keySet()); + return result; + } + + +} diff --git a/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/VfcmtBusinessLogic.java b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/VfcmtBusinessLogic.java new file mode 100644 index 0000000..e68a8ee --- /dev/null +++ b/dcaedt_be/src/main/java/org/onap/sdc/dcae/composition/impl/VfcmtBusinessLogic.java @@ -0,0 +1,283 @@ +package org.onap.sdc.dcae.composition.impl; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.lang.StringUtils; +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.dcae.composition.restmodels.*; +import org.onap.sdc.dcae.composition.restmodels.sdc.Artifact; +import org.onap.sdc.dcae.composition.restmodels.sdc.ExternalReferencesMap; +import org.onap.sdc.dcae.composition.restmodels.sdc.Resource; +import org.onap.sdc.dcae.composition.restmodels.sdc.ResourceDetailed; +import org.onap.sdc.dcae.composition.util.DcaeBeConstants; +import org.onap.sdc.dcae.enums.ArtifactType; +import org.onap.sdc.dcae.enums.LifecycleOperationType; +import org.onap.sdc.dcae.errormng.ActionStatus; +import org.onap.sdc.dcae.errormng.ErrConfMgr; +import org.onap.sdc.dcae.utils.SdcRestClientUtils; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.util.Base64Utils; + +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.onap.sdc.dcae.composition.util.DcaeBeConstants.LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT; +import static org.onap.sdc.dcae.composition.util.DcaeBeConstants.LifecycleStateEnum.findState; + +@Component +public class VfcmtBusinessLogic extends BaseBusinessLogic { + + private static final String VFCMT = "VFCMT"; + private static final String TEMPLATE = "Template"; + private static final String MONITORING_TEMPLATE = "Monitoring Template"; + private static final String DEFAULTICON = "defaulticon"; + private static final String VENDOR_NAME = "vendorName"; + private static final String VENDOR_RELEASE = "vendorRelease"; + + public ResponseEntity createMcFromTemplate(String userId, CreateVFCMTRequest request, String requestId) { + if(!validateMCRequestFields(request)) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Missing information"); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.INVALID_CONTENT); + } + return cloneMcAndAddServiceReference(userId, request, requestId); + } + + //1806 US388513 collect existing VFCMT data - flowType from cdump artifact and external reference from svc_reference artifact. If cdump not found - return error + + public ResponseEntity getVfcmtReferenceData(String vfcmtUuid, String requestId) throws Exception { + ResourceDetailed vfcmt = sdcRestClient.getResource(vfcmtUuid, requestId); + Artifact artifactData = findCdumpArtifactData(vfcmt); + if(null == artifactData) { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(),"No composition found on vfcmt {}", vfcmtUuid); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.MISSING_TOSCA_FILE, "", vfcmt.getName()); + } + VfcmtData vfcmtData = new VfcmtData(vfcmt); + //fetch cdump payload + String payload = getSdcRestClient().getResourceArtifact(vfcmtUuid, artifactData.getArtifactUUID(), requestId); + //extract and set flowType from cdump payload + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(),"Looking for flowType definition in cdump"); + vfcmtData.setFlowType(StringUtils.substringBetween(payload,"\"flowType\":\"","\"")); + //find svc_reference + artifactData = findArtifactDataByArtifactName(vfcmt, DcaeBeConstants.Composition.fileNames.SVC_REF); + if(null != artifactData) { + //fetch svc_reference payload + payload = getSdcRestClient().getResourceArtifact(vfcmtUuid, artifactData.getArtifactUUID(), requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(),"Looking for attached service and vfi info in svc_reference"); + //extract and set serviceUuid from svc_reference payload + vfcmtData.setServiceUuid(StringUtils.substringBefore(payload, "/")); + //extract and set vfiName from svc_reference payload + vfcmtData.setVfiName(StringUtils.substringAfterLast(payload, "/")); + } + return new ResponseEntity<>(vfcmtData, HttpStatus.OK); + } + + + //1806 US388525 import or clone VFCMT - always pass the flowType - update will only take place if missing from cdump + public ResponseEntity importMC(String userId, ImportVFCMTRequest request, String requestId) { + if(!validateMCRequestFields(request)) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "Missing information"); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.INVALID_CONTENT); + } + // option 1 - clone + if(request.isCloneVFCMT()) { + return cloneMcAndAddServiceReference(userId, request, requestId); + } + + ResourceDetailed vfcmt = null; + boolean undoCheckoutOnFailure = false; + // fetch vfcmt and cdump + try { + vfcmt = sdcRestClient.getResource(request.getTemplateUuid(), requestId); + Artifact cdumpArtifactData = fetchCdumpAndSetFlowType(vfcmt, request.getFlowType(), requestId); + if (null == cdumpArtifactData) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "No cdump found for monitoring component {}", vfcmt.getUuid()); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.MISSING_TOSCA_FILE, "", vfcmt.getName()); + } + String cdumpPayload = cdumpArtifactData.getPayloadData(); + + // option 2 - edit original cdump - requires check out + if(request.isUpdateFlowType()) { + if(DcaeBeConstants.LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT != DcaeBeConstants.LifecycleStateEnum.findState(vfcmt.getLifecycleState())) { + vfcmt = sdcRestClient.changeResourceLifecycleState(userId, vfcmt.getUuid(), LifecycleOperationType.CHECKOUT.name(), "checking out VFCMT", requestId); + undoCheckoutOnFailure = true; + } + cdumpArtifactData.setDescription("updating flowType on cdump"); + cdumpArtifactData.setPayloadData(Base64Utils.encodeToString(cdumpPayload.getBytes())); + sdcRestClient.updateResourceArtifact(userId, vfcmt.getUuid(), cdumpArtifactData, requestId); + } + // option 3 - update service reference only + updateReferenceToService(userId, request, vfcmt.getUuid(), requestId); + if(DcaeBeConstants.LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT == DcaeBeConstants.LifecycleStateEnum.findState(vfcmt.getLifecycleState())) { + // this will not throw an exception + checkinVfcmtAfterClone(userId, vfcmt, requestId); + } + return new ResponseEntity<>(buildVfcmtAndCdumpResponse(vfcmt, request.getVfiName(), request.getFlowType(), cdumpPayload), HttpStatus.OK); + } catch (Exception e) { + errLogger.log(LogLevel.ERROR,this.getClass().getName(),"Failed updating Monitoring Component:{}", e.getMessage()); + if(undoCheckoutOnFailure) { + rollBack(userId, vfcmt, requestId); + } + return ErrConfMgr.INSTANCE.handleException(e, ErrConfMgr.ApiType.CREATE_NEW_VFCMT); + } + + } + + private boolean validateMCRequestFields(CreateVFCMTRequest request) { + return Stream.of(request.getFlowType(), request.getTemplateUuid(), request.getName(), request.getDescription(), request.getContextType(), request.getServiceUuid(), request.getVfiName()) + .allMatch(StringUtils::isNotBlank); + } + + private void updateReferenceToService(String userId, CreateVFCMTRequest request, String newVfcmtUuid, String requestId) { + String serviceUuid = request.getServiceUuid(); + String vfiName = request.getVfiName(); + + debugLogger.log(LogLevel.INFO, this.getClass().getName(),"About to update service {}/{} to monitoring component {} ", serviceUuid, vfiName, request.getName()); + + sdcRestClient.addExternalMonitoringReference(userId, request, new ReferenceUUID(newVfcmtUuid), requestId); + + } + + private void rollBack(String userId, ResourceDetailed newVfcmt, String requestId) { + if (null != newVfcmt) { + try { + getSdcRestClient().changeResourceLifecycleState(userId, newVfcmt.getUuid(), LifecycleOperationType.UNDO_CHECKOUT.getValue(), "DCAE rollback", requestId); + } catch (Exception e) { + errLogger.log(LogLevel.ERROR,this.getClass().getName(),"Failed rolling back Monitoring Component. ID:{}", newVfcmt.getUuid()); + debugLogger.log(LogLevel.ERROR,this.getClass().getName(),"Failed rolling back Monitoring Component:{}", e); + } + } + } + + private ResponseEntity cloneMcAndAddServiceReference(String userId, CreateVFCMTRequest request, String requestId) { + addSdcMandatoryFields(request, userId); + ResourceDetailed newVfcmt = null; + try { + // Retrieve the Template VFCMT from SDC - use the template UUID provided from UI + ResourceDetailed templateMC = sdcRestClient.getResource(request.getTemplateUuid(), requestId); + // Download the CDUMP file from the template VFCMT + Artifact cdumpArtifactData = fetchCdumpAndSetFlowType(templateMC, request.getFlowType(), requestId); + if (null == cdumpArtifactData) { + errLogger.log(LogLevel.ERROR,this.getClass().getName(),"No cdump found for template {} while creating monitoring component", templateMC.getUuid()); + return ErrConfMgr.INSTANCE.buildErrorResponse(ActionStatus.MISSING_TOSCA_FILE, "", templateMC.getName()); + } + newVfcmt = sdcRestClient.createResource(userId, request, requestId); + // The cdump has the original template id. we need to replace it with the new vfcmt id + String newVfcmtUuid = newVfcmt.getUuid(); + String cdumpPayload = cdumpArtifactData.getPayloadData().replaceAll(templateMC.getUuid(), newVfcmtUuid); + + // Upload it to newly created VFCMT + cloneArtifactToTarget(userId, newVfcmtUuid, cdumpPayload, cdumpArtifactData, requestId); + cloneRuleArtifacts(userId, templateMC, newVfcmtUuid, requestId); + createReferenceArtifact(userId, request, newVfcmtUuid, requestId); + updateReferenceToService(userId, request, newVfcmtUuid, requestId); + + // this will not throw an exception + checkinVfcmtAfterClone(userId, newVfcmt, requestId); + return new ResponseEntity<>(buildVfcmtAndCdumpResponse(newVfcmt, request.getVfiName(), request.getFlowType(), cdumpPayload), HttpStatus.OK); + } catch (Exception e) { + errLogger.log(LogLevel.ERROR,this.getClass().getName(),"Failed creating Monitoring Component:{}", e.getMessage()); + rollBack(userId, newVfcmt, requestId); + return ErrConfMgr.INSTANCE.handleException(e, ErrConfMgr.ApiType.CREATE_NEW_VFCMT); + } + } + + private CreateMcResponse buildVfcmtAndCdumpResponse(ResourceDetailed vfcmt, String vfiName, String flowType, String cdumpPayload) throws IOException { + return new CreateMcResponse(new VfcmtData(vfcmt, vfiName, flowType), new ObjectMapper().readValue(cdumpPayload, Object.class)); + } + + private void checkinVfcmtAfterClone(String userId, ResourceDetailed vfcmt, String requestId) { + try { + vfcmt = sdcRestClient.changeResourceLifecycleState(userId, vfcmt.getUuid(), LifecycleOperationType.CHECKIN.getValue(), "check in after clone", requestId); + } catch (Exception e) { + errLogger.log(LogLevel.ERROR,this.getClass().getName(),"Failed to check in Monitoring Component: {}. message: {}", vfcmt.getUuid(), e); + } + } + + + private Artifact findCdumpArtifactData(ResourceDetailed vfcmt) { + return findArtifactDataByArtifactName(vfcmt, DcaeBeConstants.Composition.fileNames.COMPOSITION_YML); + } + + private void cloneRuleArtifacts(String userId, ResourceDetailed templateMC, String newVfcmtUuid, String requestId) throws Exception { + // handle rule artifacts using java 7 for-loop - exception propagation to calling method + for(Artifact artifact : templateMC.getArtifacts()) { + if(artifact.getArtifactName().endsWith(DcaeBeConstants.Composition.fileNames.MAPPING_RULE_POSTFIX)) { + cloneArtifactToTarget(userId, newVfcmtUuid, sdcRestClient.getResourceArtifact(templateMC.getUuid(), artifact.getArtifactUUID(), requestId), artifact, requestId); + } + } + } + + // fetch the vfcmt cdump artifact payload and insert the flowType. Return the artifact with updated payload or null (artifact doesn't exist) + private Artifact fetchCdumpAndSetFlowType(ResourceDetailed vfcmt, String flowType, String requestId) throws Exception { + Artifact cdumpArtifactData = findCdumpArtifactData(vfcmt); + if (null != cdumpArtifactData) { + String cdumpPayload = sdcRestClient.getResourceArtifact(vfcmt.getUuid(), cdumpArtifactData.getArtifactUUID(), requestId); + // Add flowType data to cdump if provided + if(!cdumpPayload.contains("\"flowType\":\"") && StringUtils.isNotBlank(flowType)) { + cdumpPayload = cdumpPayload.replaceFirst("\\{", "{\"flowType\":\"" + flowType + "\","); + } + cdumpArtifactData.setPayloadData(cdumpPayload); + } + return cdumpArtifactData; + } + + // backward compatibility (very backward) + private void createReferenceArtifact(String userId, CreateVFCMTRequest request, String newVfcmtUuid, String requestId) throws Exception { + String referencePayload = request.getServiceUuid() + "/resources/" + request.getVfiName(); + Artifact refArtifact = SdcRestClientUtils.generateDeploymentArtifact("createReferenceArtifact", DcaeBeConstants.Composition.fileNames.SVC_REF, ArtifactType.DCAE_TOSCA.name(), "servicereference", referencePayload.getBytes()); + sdcRestClient.createResourceArtifact(userId, newVfcmtUuid, refArtifact, requestId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Artifact {} created with content: {}", DcaeBeConstants.Composition.fileNames.SVC_REF, referencePayload); + } + + public ResponseEntity getVfcmtsForMigration(String userId, String contextType, String uuid, String version, + String requestId) { + List<Resource> resources; + ExternalReferencesMap connectedVfcmts; + try { + connectedVfcmts = getSdcRestClient().getMonitoringReferences(contextType, uuid, version, requestId); + resources = getSdcRestClient().getResources(VFCMT, TEMPLATE, MONITORING_TEMPLATE, requestId); + } catch (Exception e) { + errLogger.log(LogLevel.ERROR,this.getClass().getName(),"Exception getVfcmtsForMigration {}", e); + debugLogger.log(LogLevel.DEBUG,this.getClass().getName(),"Exception getVfcmtsForMigration {}", e); + return ErrConfMgr.INSTANCE.handleException(e, ErrConfMgr.ApiType.GET_ALL_VFCMTS); + } + + List<Resource> vfcmts = resources.stream() + .filter(resource -> notCheckedOutOrMine(userId, resource)) + .filter(resource -> !connected(resource, connectedVfcmts)) + .collect(Collectors.toList()); + return new ResponseEntity<>(vfcmts, HttpStatus.OK); + } + + private boolean connected(Resource resource, ExternalReferencesMap connectedVfcmts){ + return connectedVfcmts.values().stream().anyMatch(p -> p.contains(resource.getUuid())); + } + + private boolean notCheckedOutOrMine(String userId, Resource resource) { + // if the resource belongs to this user then it is kosher + // or if it doesn't belong to the user check the lifecycle state is checked out + + return resource.getLastUpdaterUserId().equalsIgnoreCase(userId) || + NOT_CERTIFIED_CHECKOUT != findState(resource.getLifecycleState()); + } + + + public void addSdcMandatoryFields(CreateVFCMTRequest createRequest, String user) { + createRequest.setContactId(user); + createRequest.setIcon(DEFAULTICON); + createRequest.setResourceType(VFCMT); + createRequest.setVendorName(VENDOR_NAME); + createRequest.setVendorRelease(VENDOR_RELEASE); + if (StringUtils.isBlank(createRequest.getCategory())) { + createRequest.setCategory(TEMPLATE); + } + if (StringUtils.isBlank(createRequest.getSubcategory())) { + createRequest.setSubcategory(MONITORING_TEMPLATE); + } + createRequest.setTags(new String[]{createRequest.getName()}); + } + +} |