From: Stone, Avi (as206k) Date: Thu, 12 Apr 2018 12:46:31 +0000 (+0300) Subject: DCAE-D be initial commit X-Git-Tag: 2.0.0-ONAP~23 X-Git-Url: https://gerrit.onap.org/r/gitweb?a=commitdiff_plain;h=5032434b101f25fa44d2e1f8dc8393e30af1ed4f;p=sdc%2Fdcae-d%2Fdt-be-main.git DCAE-D be initial commit DCAE-D be initial commit Issue-ID: SDC-1218 Change-Id: Id18ba96c499e785aa9ac395fbaf32d57f08c281b Signed-off-by: Stone, Avi (as206k) --- diff --git a/dcaedt_be/.gitignore b/dcaedt_be/.gitignore new file mode 100644 index 0000000..e6bf4f8 --- /dev/null +++ b/dcaedt_be/.gitignore @@ -0,0 +1,30 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +nbproject/private/ +build/ +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ +/compositiondb* + +bin/ + +### testng ### +test-output/ + diff --git a/dcaedt_be/pom.xml b/dcaedt_be/pom.xml new file mode 100644 index 0000000..b236858 --- /dev/null +++ b/dcaedt_be/pom.xml @@ -0,0 +1,193 @@ + + + 4.0.0 + org.onap.sdc.dcae.composition + dcae_dt_be + war + DCAE DT BE + + org.onap.sdc.dcae + dcae_dt_be_main + 1806.0.1-SNAPSHOT + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-tomcat + + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.apache.commons + commons-lang3 + 3.5 + + + commons-net + commons-net + 3.3 + + + com.jcraft + jsch + 0.1.54 + + + com.google.code.gson + gson + 2.8.0 + + + org.json + json + 20160810 + + + org.onap.sdc.dcae + DCAE-DT-Catalog-ASDC + ${project.version} + + + org.onap.sdc.dcae + DCAE-DT-Catalog-API + ${project.version} + + + org.onap.sdc.dcae + DCAE-DT-Catalog-Commons + ${project.version} + + + org.onap.sdc.dcae + DCAE-DT-Catalog-DB + ${project.version} + + + org.onap.sdc.dcae + DCAE-DT-Catalog-Service + ${project.version} + + + org.powermock + powermock-module-junit4 + 1.6.4 + test + + + org.powermock + powermock-api-mockito + 1.6.4 + test + + + org.testng + testng + 6.9.10 + test + + + + com.googlecode.json-simple + json-simple + 1.1.1 + + + io.springfox + springfox-swagger2 + 2.6.1 + compile + + + io.springfox + springfox-swagger-ui + 2.6.1 + compile + + + + + local + + false + + + + org.springframework.boot + spring-boot-starter-jetty + 1.5.2.RELEASE + + + org.eclipse.jetty.websocket + * + + + + + javax.servlet + javax.servlet-api + 4.0.0 + provided + + + + + server + + true + + + + javax.servlet + javax.servlet-api + 4.0.0 + + + + + + dcae + + + org.apache.maven.plugins + maven-surefire-plugin + + + org.springframework.boot + spring-boot-maven-plugin + + src/main/webapp/WEB-INF/web.xml + + + + src/main/webapp/ + + + + + + + org.apache.maven.plugins + maven-war-plugin + + + + ${project.version} + + + + + + + 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 flowTypesMap; + @Value("${compositionConfig.isRuleEditorActive}") + private boolean isRuleEditorActive; + + // get flowTypes as the parsed keySet + public Set getFlowTypes() { + return flowTypesMap.keySet(); + } + + @JsonProperty("isRuleEditorActive") + public boolean isRuleEditorActive() { + return isRuleEditorActive; + } + + public Map 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>(){}.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 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 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 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 items(@RequestBody(required = false) ItemsRequest theRequest) { + + final ItemsRequest request = (theRequest == null) ? ItemsRequest.EMPTY_REQUEST : theRequest; + + Catalog catalog = catalogController.getCatalog(request.getCatalog()); + DeferredResult result = new DeferredResult(request.getTimeout()); + + catalog.rootsByLabel(request.getStartingLabel()) + .setHandler(catalogController.new CatalogHandler(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 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 result = new DeferredResult(request.getTimeout()); + + catalog + // .fetchFolderByItemId(theItemId) + .folder(theItemId).withParts().withPartAnnotations().withItems().withItemAnnotations().withItemModels() + .execute().setHandler(catalogController.new CatalogHandler(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 result = new DeferredResult<>(request.getTimeout()); + + catalog + .item(theItemId).withModels().execute() + .setHandler(catalogController.new CatalogHandler(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