summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/model-catalog/definition-type/starter-type/artifact_type/artifact-k8sconfig-content.json5
-rw-r--r--components/model-catalog/definition-type/starter-type/artifact_type/artifact-k8sprofile-content.json5
-rw-r--r--components/model-catalog/definition-type/starter-type/node_type/component-k8s-config-value.json26
-rw-r--r--components/model-catalog/resource-dictionary/starter-dictionary/k8s-rb-definition-name.json19
-rw-r--r--components/model-catalog/resource-dictionary/starter-dictionary/k8s-rb-definition-version.json19
-rw-r--r--components/model-catalog/resource-dictionary/starter-dictionary/k8s-rb-profile-name.json19
-rw-r--r--components/model-catalog/resource-dictionary/starter-dictionary/k8s-rb-profile-namespace.json39
-rw-r--r--components/model-catalog/resource-dictionary/starter-dictionary/k8s-rb-profile-source.json19
-rw-r--r--components/model-catalog/resource-dictionary/starter-dictionary/vf-module-model-invariant-uuid.json35
-rw-r--r--components/model-catalog/resource-dictionary/starter-dictionary/vf-module-model-version.json35
-rw-r--r--components/model-catalog/resource-dictionary/starter-dictionary/vf-modules-list.json37
-rw-r--r--components/model-catalog/resource-dictionary/starter-dictionary/vpg_management_port.json19
-rw-r--r--ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/definition/K8sPluginDefinitionApi.kt14
-rw-r--r--ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/definition/template/K8sConfigTemplateComponent.kt4
-rw-r--r--ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/definition/template/K8sConfigValueComponent.kt144
-rw-r--r--ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/instance/K8sConfigValueResponse.kt18
-rw-r--r--ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/instance/K8sPluginInstanceApi.kt61
-rw-r--r--ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/BlueprintConstants.kt1
-rw-r--r--ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/GraphExtensionFunctions.kt37
-rw-r--r--ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/data/BlueprintGraph.kt6
-rw-r--r--ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/dsl/BlueprintDSL.kt16
-rw-r--r--ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/GraphExtensionFunctionsTest.kt71
-rw-r--r--ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/dsl/BlueprintDSLTest.kt1
-rw-r--r--ms/blueprintsprocessor/modules/services/workflow-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/ImperativeWorkflowExecutionService.kt6
24 files changed, 574 insertions, 82 deletions
diff --git a/components/model-catalog/definition-type/starter-type/artifact_type/artifact-k8sconfig-content.json b/components/model-catalog/definition-type/starter-type/artifact_type/artifact-k8sconfig-content.json
new file mode 100644
index 000000000..d001d05af
--- /dev/null
+++ b/components/model-catalog/definition-type/starter-type/artifact_type/artifact-k8sconfig-content.json
@@ -0,0 +1,5 @@
+{
+ "description": "K8s Config Folder Artifact",
+ "version": "1.0.0",
+ "derived_from": "tosca.artifacts.Implementation"
+} \ No newline at end of file
diff --git a/components/model-catalog/definition-type/starter-type/artifact_type/artifact-k8sprofile-content.json b/components/model-catalog/definition-type/starter-type/artifact_type/artifact-k8sprofile-content.json
new file mode 100644
index 000000000..8a68dfa42
--- /dev/null
+++ b/components/model-catalog/definition-type/starter-type/artifact_type/artifact-k8sprofile-content.json
@@ -0,0 +1,5 @@
+{
+ "description": "K8s Profile Folder Artifact",
+ "version": "1.0.0",
+ "derived_from": "tosca.artifacts.Implementation"
+} \ No newline at end of file
diff --git a/components/model-catalog/definition-type/starter-type/node_type/component-k8s-config-value.json b/components/model-catalog/definition-type/starter-type/node_type/component-k8s-config-value.json
index 901f322d0..2249d16d2 100644
--- a/components/model-catalog/definition-type/starter-type/node_type/component-k8s-config-value.json
+++ b/components/model-catalog/definition-type/starter-type/node_type/component-k8s-config-value.json
@@ -17,12 +17,12 @@
"operations": {
"process": {
"inputs": {
- "k8s-template-name": {
+ "k8s-rb-config-template-name": {
"description": "K8s template name",
"required": false,
"type": "string"
},
- "k8s-config-name": {
+ "k8s-rb-config-name": {
"description": "K8s config name",
"required": false,
"type": "string"
@@ -32,18 +32,24 @@
"required": false,
"type": "string"
},
- "k8s-rb-template-value-source": {
+ "k8s-rb-config-value-source": {
"description": "Location of value source in CBA",
"required": false,
"type": "string"
},
- "k8s-operation-type" : {
- "required" : false,
- "type" : "string",
- "constraints" : [{
- "valid_values" : [ "create", "update", "rollback" ]
- }],
- "default" : "create"
+ "k8s-config-operation-type": {
+ "required": false,
+ "type": "string",
+ "constraints": [
+ {
+ "valid_values": [
+ "create",
+ "update",
+ "delete"
+ ]
+ }
+ ],
+ "default": "create"
},
"artifact-prefix-names": {
"description": "Resource Assignment Artifact Prefix names",
diff --git a/components/model-catalog/resource-dictionary/starter-dictionary/k8s-rb-definition-name.json b/components/model-catalog/resource-dictionary/starter-dictionary/k8s-rb-definition-name.json
new file mode 100644
index 000000000..8fb643b7d
--- /dev/null
+++ b/components/model-catalog/resource-dictionary/starter-dictionary/k8s-rb-definition-name.json
@@ -0,0 +1,19 @@
+{
+ "tags": "k8s, cnf, k8s-rb-definition-name",
+ "name": "k8s-rb-definition-name",
+ "group": "default",
+ "property": {
+ "description": "K8s RB definition name. Associated with vf-module-model-invariant-uuid",
+ "type": "string"
+ },
+ "updated-by": "Lukasz Rajewski <lukasz.rajewski@orange.com>",
+ "sources": {
+ "input": {
+ "type": "source-input"
+ },
+ "default": {
+ "type": "source-default",
+ "properties": {}
+ }
+ }
+} \ No newline at end of file
diff --git a/components/model-catalog/resource-dictionary/starter-dictionary/k8s-rb-definition-version.json b/components/model-catalog/resource-dictionary/starter-dictionary/k8s-rb-definition-version.json
new file mode 100644
index 000000000..633b412c6
--- /dev/null
+++ b/components/model-catalog/resource-dictionary/starter-dictionary/k8s-rb-definition-version.json
@@ -0,0 +1,19 @@
+{
+ "tags": "k8s, cnf, k8s-rb-definition-version",
+ "name": "k8s-rb-definition-version",
+ "group": "default",
+ "property": {
+ "description": "K8s RB definition version. Associated with vf-module-model-version",
+ "type": "string"
+ },
+ "updated-by": "Lukasz Rajewski <lukasz.rajewski@orange.com>",
+ "sources": {
+ "input": {
+ "type": "source-input"
+ },
+ "default": {
+ "type": "source-default",
+ "properties": {}
+ }
+ }
+} \ No newline at end of file
diff --git a/components/model-catalog/resource-dictionary/starter-dictionary/k8s-rb-profile-name.json b/components/model-catalog/resource-dictionary/starter-dictionary/k8s-rb-profile-name.json
new file mode 100644
index 000000000..b220329bb
--- /dev/null
+++ b/components/model-catalog/resource-dictionary/starter-dictionary/k8s-rb-profile-name.json
@@ -0,0 +1,19 @@
+{
+ "tags": "k8s, cnf, k8s-rb-profile-name",
+ "name": "k8s-rb-profile-name",
+ "group": "default",
+ "property": {
+ "description": "Profile name used in multicloud/k8s plugin to identify Helm chart(s) where this mapping is providing override values.",
+ "type": "string"
+ },
+ "updated-by": "Lukasz Rajewski <lukasz.rajewski@orange.com>",
+ "sources": {
+ "input": {
+ "type": "source-input"
+ },
+ "default": {
+ "type": "source-default",
+ "properties": {}
+ }
+ }
+} \ No newline at end of file
diff --git a/components/model-catalog/resource-dictionary/starter-dictionary/k8s-rb-profile-namespace.json b/components/model-catalog/resource-dictionary/starter-dictionary/k8s-rb-profile-namespace.json
new file mode 100644
index 000000000..a7cd5c806
--- /dev/null
+++ b/components/model-catalog/resource-dictionary/starter-dictionary/k8s-rb-profile-namespace.json
@@ -0,0 +1,39 @@
+{
+ "tags": "k8s, cnf, k8s-rb-profile-namespace",
+ "name": "k8s-rb-profile-namespace",
+ "group": "default",
+ "property": {
+ "description": "Profile name used in multicloud/k8s plugin",
+ "type": "string"
+ },
+ "updated-by": "Lukasz Rajewski <lukasz.rajewski@orange.com>",
+ "sources": {
+ "input": {
+ "type": "source-input"
+ },
+ "default": {
+ "type": "source-default",
+ "properties": {}
+ },
+ "sdnc": {
+ "type": "source-rest",
+ "properties": {
+ "verb": "GET",
+ "type": "JSON",
+ "url-path": "/restconf/config/GENERIC-RESOURCE-API:services/service/$service-instance-id/service-data/vnfs/vnf/$vnf-id/vnf-data/vnf-topology/vnf-parameters-data/param/k8s-rb-profile-namespace",
+ "path": "/param/0/value",
+ "input-key-mapping": {
+ "service-instance-id": "service-instance-id",
+ "vnf-id": "vnf-id"
+ },
+ "output-key-mapping": {
+ "k8s-rb-profile-namespace": "value"
+ },
+ "key-dependencies": [
+ "service-instance-id",
+ "vnf-id"
+ ]
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/components/model-catalog/resource-dictionary/starter-dictionary/k8s-rb-profile-source.json b/components/model-catalog/resource-dictionary/starter-dictionary/k8s-rb-profile-source.json
new file mode 100644
index 000000000..4ed85665c
--- /dev/null
+++ b/components/model-catalog/resource-dictionary/starter-dictionary/k8s-rb-profile-source.json
@@ -0,0 +1,19 @@
+{
+ "tags": "k8s, cnf, k8s-rb-profile-source",
+ "name": "k8s-rb-profile-source",
+ "group": "default",
+ "property": {
+ "description": "The source folder or file relative to 'Templates/k8s-profiles' folder",
+ "type": "string"
+ },
+ "updated-by": "Lukasz Rajewski <lukasz.rajewski@orange.com>",
+ "sources": {
+ "input": {
+ "type": "source-input"
+ },
+ "default": {
+ "type": "source-default",
+ "properties": {}
+ }
+ }
+} \ No newline at end of file
diff --git a/components/model-catalog/resource-dictionary/starter-dictionary/vf-module-model-invariant-uuid.json b/components/model-catalog/resource-dictionary/starter-dictionary/vf-module-model-invariant-uuid.json
new file mode 100644
index 000000000..6fa3c7769
--- /dev/null
+++ b/components/model-catalog/resource-dictionary/starter-dictionary/vf-module-model-invariant-uuid.json
@@ -0,0 +1,35 @@
+{
+ "tags": "vnf, vf-module, vf-module-model-invariant-uuid",
+ "name": "vf-module-model-invariant-uuid",
+ "group": "default",
+ "property": {
+ "description": "vf-module-model-invariant-uuid",
+ "type": "string"
+ },
+ "updated-by": "MALAKOV, YURIY <yuriy.malakov@att.com>",
+ "sources": {
+ "input": {
+ "type": "source-input"
+ },
+ "default": {
+ "type": "source-default",
+ "properties": {}
+ },
+ "processor-db": {
+ "type": "source-db",
+ "properties": {
+ "type": "SQL",
+ "query": "select sdnctl.VF_MODULE_MODEL.invariant_uuid as vf_module_model_invariant_uuid from sdnctl.VF_MODULE_MODEL where sdnctl.VF_MODULE_MODEL.customization_uuid=:customizationid",
+ "input-key-mapping": {
+ "customizationid": "vf-module-model-customization-uuid"
+ },
+ "output-key-mapping": {
+ "vf-module-model-invariant-uuid": "vf_module_model_invariant_uuid"
+ },
+ "key-dependencies": [
+ "vf-module-model-customization-uuid"
+ ]
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/components/model-catalog/resource-dictionary/starter-dictionary/vf-module-model-version.json b/components/model-catalog/resource-dictionary/starter-dictionary/vf-module-model-version.json
new file mode 100644
index 000000000..dc08ea087
--- /dev/null
+++ b/components/model-catalog/resource-dictionary/starter-dictionary/vf-module-model-version.json
@@ -0,0 +1,35 @@
+{
+ "tags": "vnf, vf-module, vf-module-model-version",
+ "name": "vf-module-model-version",
+ "group": "default",
+ "property": {
+ "description": "vf-module-model-version",
+ "type": "string"
+ },
+ "updated-by": "MALAKOV, YURIY <yuriy.malakov@att.com>",
+ "sources": {
+ "input": {
+ "type": "source-input"
+ },
+ "default": {
+ "type": "source-default",
+ "properties": {}
+ },
+ "processor-db": {
+ "type": "source-db",
+ "properties": {
+ "type": "SQL",
+ "query": "select sdnctl.VF_MODULE_MODEL.uuid as vf_module_model_version from sdnctl.VF_MODULE_MODEL where sdnctl.VF_MODULE_MODEL.customization_uuid=:customizationid",
+ "input-key-mapping": {
+ "customizationid": "vf-module-model-customization-uuid"
+ },
+ "output-key-mapping": {
+ "vf-module-model-version": "vf_module_model_version"
+ },
+ "key-dependencies": [
+ "vf-module-model-customization-uuid"
+ ]
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/components/model-catalog/resource-dictionary/starter-dictionary/vf-modules-list.json b/components/model-catalog/resource-dictionary/starter-dictionary/vf-modules-list.json
new file mode 100644
index 000000000..0bf66f6e6
--- /dev/null
+++ b/components/model-catalog/resource-dictionary/starter-dictionary/vf-modules-list.json
@@ -0,0 +1,37 @@
+{
+ "tags": "vnf, vf-modules-list",
+ "name": "vf-modules-list",
+ "group": "default",
+ "property": {
+ "description": "List of vf-modules associated with vnf",
+ "type": "json"
+ },
+ "updated-by": "Lukasz Rajewski <lukasz.rajewski@orange.com>",
+ "sources": {
+ "input": {
+ "type": "source-input"
+ },
+ "default": {
+ "type": "source-default",
+ "properties": {}
+ },
+ "aai-data": {
+ "type": "source-rest",
+ "properties": {
+ "verb": "GET",
+ "type": "JSON",
+ "url-path": "/aai/v19/network/generic-vnfs/generic-vnf/${vnf-id}?depth=1",
+ "path": "/vf-modules",
+ "input-key-mapping": {
+ "vnf-id": "vnf-id"
+ },
+ "output-key-mapping": {
+ "vf-modules": "vf-module"
+ },
+ "key-dependencies": [
+ "vnf-id"
+ ]
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/components/model-catalog/resource-dictionary/starter-dictionary/vpg_management_port.json b/components/model-catalog/resource-dictionary/starter-dictionary/vpg_management_port.json
new file mode 100644
index 000000000..20003dfd6
--- /dev/null
+++ b/components/model-catalog/resource-dictionary/starter-dictionary/vpg_management_port.json
@@ -0,0 +1,19 @@
+{
+ "tags": "k8s, cnf, vpg-management-port",
+ "name": "vpg-management-port",
+ "group": "default",
+ "property": {
+ "description": "Ssh port number in k8s nodeport to associate with vpg",
+ "type": "string"
+ },
+ "updated-by": "Lukasz Rajewski <lukasz.rajewski@orange.com>",
+ "sources": {
+ "input": {
+ "type": "source-input"
+ },
+ "default": {
+ "type": "source-default",
+ "properties": {}
+ }
+ }
+} \ No newline at end of file
diff --git a/ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/definition/K8sPluginDefinitionApi.kt b/ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/definition/K8sPluginDefinitionApi.kt
index 05c3021d9..ae2d1f634 100644
--- a/ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/definition/K8sPluginDefinitionApi.kt
+++ b/ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/definition/K8sPluginDefinitionApi.kt
@@ -111,16 +111,18 @@ class K8sPluginDefinitionApi(
"/profile/${profile.profileName}/content",
filePath
)
+ log.debug(result.toString())
if (result.status !in 200..299) {
throw Exception(result.body)
}
+ log.debug("Profile uploaded properly")
} catch (e: Exception) {
log.error("Caught exception trying to upload k8s rb profile ${profile.profileName}")
throw BlueprintProcessorException("${e.message}")
}
}
- fun createTemplate(definition: String, definitionVersion: String, template: K8sTemplate): Boolean {
+ fun createTemplate(definition: String, definitionVersion: String, template: K8sTemplate) {
val rbDefinitionService = K8sDefinitionRestClient(k8sConfiguration, definition, definitionVersion)
val templateJsonString: String = objectMapper.writeValueAsString(template)
try {
@@ -130,20 +132,23 @@ class K8sPluginDefinitionApi(
templateJsonString
)
log.debug(result.toString())
- return result.status in 200..299
+ if (result.status !in 200..299) {
+ throw Exception(result.body)
+ }
} catch (e: Exception) {
log.error("Caught exception during create template")
throw BlueprintProcessorException("${e.message}")
}
}
- fun uploadTemplate(definition: String, definitionVersion: String, template: K8sTemplate, filePath: Path) {
+ fun uploadConfigTemplateContent(definition: String, definitionVersion: String, template: K8sTemplate, filePath: Path) {
val fileUploadService = K8sUploadFileRestClientService(k8sConfiguration, definition, definitionVersion)
try {
val result: BlueprintWebClientService.WebClientResponse<String> = fileUploadService.uploadBinaryFile(
"/config-template/${template.templateName}/content",
filePath
)
+ log.debug(result.toString())
if (result.status !in 200..299) {
throw Exception(result.body)
}
@@ -162,6 +167,9 @@ class K8sPluginDefinitionApi(
""
)
log.debug(result.toString())
+ if (result.status !in 200..299) {
+ throw Exception(result.body)
+ }
} catch (e: Exception) {
log.error("Caught exception during get template")
throw BlueprintProcessorException("${e.message}")
diff --git a/ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/definition/template/K8sConfigTemplateComponent.kt b/ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/definition/template/K8sConfigTemplateComponent.kt
index cb759e534..0944c2359 100644
--- a/ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/definition/template/K8sConfigTemplateComponent.kt
+++ b/ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/definition/template/K8sConfigTemplateComponent.kt
@@ -141,7 +141,7 @@ open class K8sConfigTemplateComponent(
}
val bluePrintContext = bluePrintRuntimeService.bluePrintContext()
val artifact: ArtifactDefinition = bluePrintContext.nodeTemplateArtifact(nodeTemplateName, templateSource)
- if (artifact.type != BlueprintConstants.MODEL_TYPE_ARTIFACT_K8S_PROFILE)
+ if (artifact.type != BlueprintConstants.MODEL_TYPE_ARTIFACT_K8S_CONFIG)
throw BlueprintProcessorException(
"Unexpected template artifact type for template source $templateSource. Expecting: $artifact.type"
)
@@ -151,7 +151,7 @@ open class K8sConfigTemplateComponent(
val templateFilePath: Path = prepareTemplateFile(templateName, templateSource, artifact.file)
api.createTemplate(definitionName, definitionVersion, template)
- api.uploadTemplate(definitionName, definitionVersion, template, templateFilePath)
+ api.uploadConfigTemplateContent(definitionName, definitionVersion, template, templateFilePath)
log.info("K8s Config Upload Completed")
outputPrefixStatuses[prefix] = OUTPUT_UPLOADED
diff --git a/ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/definition/template/K8sConfigValueComponent.kt b/ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/definition/template/K8sConfigValueComponent.kt
index 2e7b34e01..34b6ea187 100644
--- a/ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/definition/template/K8sConfigValueComponent.kt
+++ b/ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/definition/template/K8sConfigValueComponent.kt
@@ -11,12 +11,17 @@ import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInpu
import org.onap.ccsdk.cds.blueprintsprocessor.functions.k8s.K8sConnectionPluginConfiguration
import org.onap.ccsdk.cds.blueprintsprocessor.functions.k8s.instance.K8sConfigValueRequest
import org.onap.ccsdk.cds.blueprintsprocessor.functions.k8s.instance.K8sPluginInstanceApi
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.ResourceResolutionConstants
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.ResourceResolutionService
import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.AbstractComponentFunction
import org.onap.ccsdk.cds.controllerblueprints.core.BlueprintConstants
import org.onap.ccsdk.cds.controllerblueprints.core.BlueprintProcessorException
+import org.onap.ccsdk.cds.controllerblueprints.core.asJsonNode
import org.onap.ccsdk.cds.controllerblueprints.core.data.ArtifactDefinition
import org.onap.ccsdk.cds.controllerblueprints.core.returnNullIfMissing
+import org.onap.ccsdk.cds.controllerblueprints.core.service.BlueprintVelocityTemplateService
import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
+import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceAssignment
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.config.ConfigurableBeanFactory
import org.springframework.context.annotation.Scope
@@ -28,7 +33,8 @@ import java.nio.file.Paths
@Component("component-k8s-config-value")
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
open class K8sConfigValueComponent(
- private var bluePrintPropertiesService: BlueprintPropertiesService
+ private var bluePrintPropertiesService: BlueprintPropertiesService,
+ private val resourceResolutionService: ResourceResolutionService
) : AbstractComponentFunction() {
private val log = LoggerFactory.getLogger(K8sConfigValueComponent::class.java)!!
@@ -36,11 +42,11 @@ open class K8sConfigValueComponent(
companion object {
const val INPUT_RESOURCE_ASSIGNMENT_MAP = "resource-assignment-map"
const val INPUT_ARTIFACT_PREFIX_NAMES = "artifact-prefix-names"
- const val INPUT_K8S_TEMPLATE_NAME = "k8s-template-name"
- const val INPUT_K8S_CONFIG_NAME = "k8s-config-name"
+ const val INPUT_K8S_RB_CONFIG_TEMPLATE_NAME = "k8s-rb-config-template-name"
+ const val INPUT_K8S_RB_CONFIG_NAME = "k8s-rb-config-name"
const val INPUT_K8S_INSTANCE_ID = "k8s-instance-id"
- const val INPUT_K8S_TEMPLATE_VALUE_SOURCE = "k8s-rb-template-value-source"
- const val INPUT_K8S_OPERATION_TYPE = "k8s-operation-type"
+ const val INPUT_K8S_CONFIG_VALUE_SOURCE = "k8s-rb-config-value-source"
+ const val INPUT_K8S_CONFIG_OPERATION_TYPE = "k8s-config-operation-type"
const val OUTPUT_STATUSES = "statuses"
const val OUTPUT_SKIPPED = "skipped"
@@ -51,11 +57,11 @@ open class K8sConfigValueComponent(
override suspend fun processNB(executionRequest: ExecutionServiceInput) {
log.info("Triggering K8s Config Value component logic.")
val inputParameterNames = arrayOf(
- INPUT_K8S_TEMPLATE_NAME,
- INPUT_K8S_CONFIG_NAME,
+ INPUT_K8S_RB_CONFIG_TEMPLATE_NAME,
+ INPUT_K8S_RB_CONFIG_NAME,
INPUT_K8S_INSTANCE_ID,
- INPUT_K8S_OPERATION_TYPE,
- INPUT_K8S_TEMPLATE_VALUE_SOURCE,
+ INPUT_K8S_CONFIG_OPERATION_TYPE,
+ INPUT_K8S_CONFIG_VALUE_SOURCE,
INPUT_ARTIFACT_PREFIX_NAMES
)
val outputPrefixStatuses = mutableMapOf<String, String>()
@@ -82,74 +88,81 @@ open class K8sConfigValueComponent(
}
}
- val templateName: String? = prefixInputParamsMap[INPUT_K8S_TEMPLATE_NAME]?.returnNullIfMissing()?.asText()
- val configName: String? = prefixInputParamsMap[INPUT_K8S_CONFIG_NAME]?.returnNullIfMissing()?.asText()
+ val templateName: String? = prefixInputParamsMap[INPUT_K8S_RB_CONFIG_TEMPLATE_NAME]?.returnNullIfMissing()?.asText()
+ val configName: String? = prefixInputParamsMap[INPUT_K8S_RB_CONFIG_NAME]?.returnNullIfMissing()?.asText()
val instanceId: String? = prefixInputParamsMap[INPUT_K8S_INSTANCE_ID]?.returnNullIfMissing()?.asText()
- val valueSource: String? = prefixInputParamsMap[INPUT_K8S_TEMPLATE_VALUE_SOURCE]?.returnNullIfMissing()?.asText()
- val operationType = prefixInputParamsMap[INPUT_K8S_TEMPLATE_VALUE_SOURCE]?.returnNullIfMissing()?.asText()?.toUpperCase()
+ var valueSource: String? = prefixInputParamsMap[INPUT_K8S_CONFIG_VALUE_SOURCE]?.returnNullIfMissing()?.asText()
+ val operationType = prefixInputParamsMap[INPUT_K8S_CONFIG_OPERATION_TYPE]?.returnNullIfMissing()?.asText()?.toUpperCase()
+ if (valueSource == null) {
+ valueSource = configName
+ log.info("Config name used instead of value source")
+ }
if (operationType == null || operationType == OperationType.CREATE.toString())
createOperation(templateName, instanceId, valueSource, outputPrefixStatuses, prefix, configName)
else if (operationType == OperationType.UPDATE.toString())
updateOperation(templateName, instanceId, valueSource, outputPrefixStatuses, prefix, configName)
- else if (operationType == OperationType.ROLLBACK.toString())
- rollbackOperation(instanceId)
+ else if (operationType == OperationType.DELETE.toString())
+ deleteOperation(instanceId, configName)
else
throw BlueprintProcessorException("Unknown operation type: $operationType")
}
}
- private fun createOperation(templateName: String?, instanceId: String?, valueSource: String?, outputPrefixStatuses: MutableMap<String, String>, prefix: String, configName: String?) {
+ private suspend fun createOperation(templateName: String?, instanceId: String?, valueSource: String?, outputPrefixStatuses: MutableMap<String, String>, prefix: String, configName: String?) {
+ val api = K8sPluginInstanceApi(K8sConnectionPluginConfiguration(bluePrintPropertiesService))
if (templateName == null || configName == null || instanceId == null || valueSource == null) {
- log.warn("$INPUT_K8S_TEMPLATE_NAME or $INPUT_K8S_INSTANCE_ID or $INPUT_K8S_TEMPLATE_VALUE_SOURCE or $INPUT_K8S_CONFIG_NAME is null")
+ log.warn("$INPUT_K8S_RB_CONFIG_TEMPLATE_NAME or $INPUT_K8S_INSTANCE_ID or $INPUT_K8S_CONFIG_VALUE_SOURCE or $INPUT_K8S_RB_CONFIG_NAME is null - skipping create")
} else if (templateName.isEmpty()) {
- log.warn("$INPUT_K8S_TEMPLATE_NAME is empty")
+ log.warn("$INPUT_K8S_RB_CONFIG_TEMPLATE_NAME is empty - skipping create")
} else if (configName.isEmpty()) {
- log.warn("$INPUT_K8S_CONFIG_NAME is empty")
+ log.warn("$INPUT_K8S_RB_CONFIG_NAME is empty - skipping create")
+ } else if (api.hasConfigurationValues(instanceId, configName)) {
+ log.info("Configuration already exists - skipping create")
} else {
- log.info("Uploading K8s template value..")
+ log.info("Uploading K8s config..")
outputPrefixStatuses[prefix] = OUTPUT_ERROR
val bluePrintContext = bluePrintRuntimeService.bluePrintContext()
val artifact: ArtifactDefinition = bluePrintContext.nodeTemplateArtifact(nodeTemplateName, valueSource)
- if (artifact.type != BlueprintConstants.MODEL_TYPE_ARTIFACT_K8S_PROFILE)
+ if (artifact.type != BlueprintConstants.MODEL_TYPE_ARTIFACT_K8S_CONFIG)
throw BlueprintProcessorException(
- "Unexpected profile artifact type for profile source $valueSource. Expecting: $artifact.type"
+ "Unexpected config artifact type for config value source $valueSource. Expecting: $artifact.type"
)
- // Creating API connector
- val api = K8sPluginInstanceApi(K8sConnectionPluginConfiguration(bluePrintPropertiesService))
val configValueRequest = K8sConfigValueRequest()
configValueRequest.templateName = templateName
configValueRequest.configName = configName
configValueRequest.description = valueSource
- configValueRequest.values = parseResult(valueSource)
+ configValueRequest.values = parseResult(valueSource, artifact.file)
api.createConfigurationValues(configValueRequest, instanceId)
}
}
- private fun updateOperation(templateName: String?, instanceId: String?, valueSource: String?, outputPrefixStatuses: MutableMap<String, String>, prefix: String, configName: String?) {
+ private suspend fun updateOperation(templateName: String?, instanceId: String?, valueSource: String?, outputPrefixStatuses: MutableMap<String, String>, prefix: String, configName: String?) {
+ val api = K8sPluginInstanceApi(K8sConnectionPluginConfiguration(bluePrintPropertiesService))
if (templateName == null || configName == null || instanceId == null || valueSource == null) {
- log.warn("$INPUT_K8S_TEMPLATE_NAME or $INPUT_K8S_INSTANCE_ID or $INPUT_K8S_TEMPLATE_VALUE_SOURCE or $INPUT_K8S_CONFIG_NAME is null")
+ log.warn("$INPUT_K8S_RB_CONFIG_TEMPLATE_NAME or $INPUT_K8S_INSTANCE_ID or $INPUT_K8S_CONFIG_VALUE_SOURCE or $INPUT_K8S_RB_CONFIG_NAME is null - skipping update")
} else if (templateName.isEmpty()) {
- log.warn("$INPUT_K8S_TEMPLATE_NAME is empty")
+ log.warn("$INPUT_K8S_RB_CONFIG_TEMPLATE_NAME is empty - skipping update")
} else if (configName.isEmpty()) {
- log.warn("$INPUT_K8S_CONFIG_NAME is empty")
+ log.warn("$INPUT_K8S_RB_CONFIG_NAME is empty - skipping update")
+ } else if (!api.hasConfigurationValues(instanceId, configName)) {
+ log.info("Configuration does not exist - doing create instead")
+ createOperation(templateName, instanceId, valueSource, outputPrefixStatuses, prefix, configName)
} else {
- log.info("Uploading K8s template value..")
+ log.info("Updating K8s config..")
outputPrefixStatuses[prefix] = OUTPUT_ERROR
val bluePrintContext = bluePrintRuntimeService.bluePrintContext()
val artifact: ArtifactDefinition = bluePrintContext.nodeTemplateArtifact(nodeTemplateName, valueSource)
- if (artifact.type != BlueprintConstants.MODEL_TYPE_ARTIFACT_K8S_PROFILE)
+ if (artifact.type != BlueprintConstants.MODEL_TYPE_ARTIFACT_K8S_CONFIG)
throw BlueprintProcessorException(
- "Unexpected profile artifact type for profile source $valueSource. Expecting: $artifact.type"
+ "Unexpected config artifact type for config value source $valueSource. Expecting: $artifact.type"
)
- // Creating API connector
- val api = K8sPluginInstanceApi(K8sConnectionPluginConfiguration(bluePrintPropertiesService))
if (api.hasConfigurationValues(instanceId, configName)) {
val configValueRequest = K8sConfigValueRequest()
configValueRequest.templateName = templateName
configValueRequest.configName = configName
configValueRequest.description = valueSource
- configValueRequest.values = parseResult(valueSource)
+ configValueRequest.values = parseResult(valueSource, artifact.file)
api.editConfigurationValues(configValueRequest, instanceId, configName)
} else {
throw BlueprintProcessorException("Error while getting configuration value")
@@ -157,24 +170,67 @@ open class K8sConfigValueComponent(
}
}
- private fun rollbackOperation(instanceId: String?) {
- if (instanceId != null) {
- val api = K8sPluginInstanceApi(K8sConnectionPluginConfiguration(bluePrintPropertiesService))
- api.rollbackConfigurationValues(instanceId)
+ private fun deleteOperation(instanceId: String?, configName: String?) {
+ val api = K8sPluginInstanceApi(K8sConnectionPluginConfiguration(bluePrintPropertiesService))
+ if (instanceId == null || configName == null) {
+ log.warn("$INPUT_K8S_INSTANCE_ID or $INPUT_K8S_RB_CONFIG_NAME is null - skipping delete")
+ } else if (api.hasConfigurationValues(instanceId, configName)) {
+ log.info("Configuration does not exists - skipping delete")
} else {
- throw BlueprintProcessorException("$INPUT_K8S_INSTANCE_ID is null")
+ api.deleteConfigurationValues(instanceId, configName)
}
}
- private fun parseResult(templateValueSource: String): Any {
- val ymlSourceFile = getYmlSourceFile(templateValueSource)
+ private suspend fun parseResult(templateValueSource: String, k8sConfigLocation: String): Any {
+ val bluePrintContext = bluePrintRuntimeService.bluePrintContext()
+ val bluePrintBasePath: String = bluePrintContext.rootPath
+ val configeValueSourceFilePath: Path = Paths.get(
+ bluePrintBasePath.plus(File.separator).plus(k8sConfigLocation)
+ )
+
+ if (!configeValueSourceFilePath.toFile().exists() || configeValueSourceFilePath.toFile().isDirectory)
+ throw BlueprintProcessorException("Specified config value source $k8sConfigLocation is not a file")
+
+ var obj: Any? = null
val yamlReader = ObjectMapper(YAMLFactory())
- val obj: Any = yamlReader.readValue(ymlSourceFile, Any::class.java)
+ if (configeValueSourceFilePath.toFile().extension.toLowerCase() == "vtl") {
+ log.info("Config building started from source $templateValueSource")
+ val properties: MutableMap<String, Any> = mutableMapOf()
+ properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT] = false
+ properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOLUTION_KEY] = ""
+ properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_ID] = ""
+ properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_TYPE] = ""
+ properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] = 1
+ properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOLUTION_SUMMARY] = false
+ val resolutionResult: Pair<String, MutableList<ResourceAssignment>> = resourceResolutionService.resolveResources(
+ bluePrintRuntimeService,
+ nodeTemplateName,
+ templateValueSource,
+ properties
+ )
+
+ val resolvedJsonContent = resolutionResult.second
+ .associateBy({ it.name }, { it.property?.value })
+ .asJsonNode()
+ val newContent: String = templateValues(configeValueSourceFilePath.toFile(), resolvedJsonContent)
+ obj = yamlReader.readValue(newContent, Any::class.java)
+ } else {
+ val ymlSourceFile = getYmlSourceFile(k8sConfigLocation)
+ obj = yamlReader.readValue(ymlSourceFile, Any::class.java)
+ }
val jsonWriter = ObjectMapper()
return jsonWriter.convertValue(obj)
}
+ private fun templateValues(templateFile: File, params: JsonNode): String {
+ val fileContent = templateFile.bufferedReader().readText()
+ return BlueprintVelocityTemplateService.generateContent(
+ fileContent,
+ params, true
+ )
+ }
+
private fun getYmlSourceFile(templateValueSource: String): File {
val bluePrintBasePath: String = bluePrintRuntimeService.bluePrintContext().rootPath
val profileSourceFileFolderPath: Path = Paths.get(bluePrintBasePath.plus(File.separator).plus(templateValueSource))
@@ -205,6 +261,6 @@ open class K8sConfigValueComponent(
}
private enum class OperationType {
- CREATE, UPDATE, ROLLBACK
+ CREATE, UPDATE, DELETE
}
}
diff --git a/ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/instance/K8sConfigValueResponse.kt b/ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/instance/K8sConfigValueResponse.kt
index 823009fbb..0106b81a4 100644
--- a/ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/instance/K8sConfigValueResponse.kt
+++ b/ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/instance/K8sConfigValueResponse.kt
@@ -1,29 +1,39 @@
package org.onap.ccsdk.cds.blueprintsprocessor.functions.k8s.instance
+import com.fasterxml.jackson.annotation.JsonAlias
import com.fasterxml.jackson.annotation.JsonProperty
class K8sConfigValueResponse {
-
@get:JsonProperty("rb-name")
var rbName: String? = null
@get:JsonProperty("rb-version")
var rbVersion: String? = null
+ @get:JsonProperty("instance-id")
+ var instanceId: String? = null
+
@get:JsonProperty("profile-name")
var profileName: String? = null
+ @get:JsonProperty("description")
+ var description: String? = null
+
@get:JsonProperty("template-name")
var templateName: String? = null
@get:JsonProperty("config-name")
var configName: String? = null
- @get:JsonProperty("config-name")
- var configVersion: String? = null
+ @get:JsonProperty("config-version")
+ @get:JsonAlias("config-verion")
+ var configVersion: Integer? = null
+
+ @get:JsonProperty("values")
+ var values: Map<String, Object>? = null
override fun toString(): String {
- return "$rbName:$rbVersion:$profileName:$templateName:$configName:$configVersion"
+ return "$templateName:$configName"
}
override fun equals(other: Any?): Boolean {
diff --git a/ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/instance/K8sPluginInstanceApi.kt b/ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/instance/K8sPluginInstanceApi.kt
index 7663699aa..7834c050d 100644
--- a/ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/instance/K8sPluginInstanceApi.kt
+++ b/ms/blueprintsprocessor/functions/k8s-connection-plugin/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/k8s/instance/K8sPluginInstanceApi.kt
@@ -121,14 +121,24 @@ class K8sPluginInstanceApi(
}
}
- fun queryInstanceStatus(instanceId: String, kind: String, apiVersion: String, name: String?, labels: String?): K8sRbInstanceStatus? {
+ fun queryInstanceStatus(
+ instanceId: String,
+ kind: String,
+ apiVersion: String,
+ name: String? = null,
+ labels: Map<String, String>? = null
+ ): K8sRbInstanceStatus? {
val rbInstanceService = K8sRbInstanceRestClient(k8sConfiguration, instanceId)
try {
var path: String = "/query?ApiVersion=$apiVersion&Kind=$kind"
if (name != null)
path = path.plus("&Name=$name")
- if (labels != null)
- path = path.plus("&Labels=$labels")
+ if (labels != null && labels.isNotEmpty()) {
+ path = path.plus("&Labels=")
+ for ((name, value) in labels)
+ path = path.plus("$name%3D$value,")
+ path = path.trimEnd(',')
+ }
val result: BlueprintWebClientService.WebClientResponse<String> = rbInstanceService.exchangeResource(
GET.name,
path,
@@ -240,7 +250,7 @@ class K8sPluginInstanceApi(
} else
throw BlueprintProcessorException(result.body)
} catch (e: Exception) {
- log.error("Caught exception trying to get k8s rb instance")
+ log.error("Caught exception trying to create config instance")
throw BlueprintProcessorException("${e.message}")
}
}
@@ -262,7 +272,7 @@ class K8sPluginInstanceApi(
} else
throw BlueprintProcessorException(result.body)
} catch (e: Exception) {
- log.error("Caught exception trying to get k8s rb instance")
+ log.error("Caught exception trying to edit config instance")
throw BlueprintProcessorException("${e.message}")
}
}
@@ -283,6 +293,45 @@ class K8sPluginInstanceApi(
}
}
+ fun getConfigurationValues(instanceId: String, configName: String): K8sConfigValueResponse? {
+ val rbInstanceService = K8sRbInstanceRestClient(k8sConfiguration, instanceId)
+ try {
+ val result: BlueprintWebClientService.WebClientResponse<String> = rbInstanceService.exchangeResource(
+ GET.name,
+ "/config/$configName",
+ ""
+ )
+ log.debug(result.toString())
+ return if (result.status in 200..299) {
+ val parsedObject: K8sConfigValueResponse? = JacksonUtils.readValue(
+ result.body, K8sConfigValueResponse::class.java
+ )
+ parsedObject
+ } else
+ throw BlueprintProcessorException(result.body)
+ } catch (e: Exception) {
+ log.error("Caught exception trying to get config instance")
+ throw BlueprintProcessorException("${e.message}")
+ }
+ }
+
+ fun deleteConfigurationValues(instanceId: String, configName: String) {
+ val rbInstanceService = K8sRbInstanceRestClient(k8sConfiguration, instanceId)
+ try {
+ val result: BlueprintWebClientService.WebClientResponse<String> = rbInstanceService.exchangeResource(
+ DELETE.name,
+ "/config/$configName",
+ ""
+ )
+ log.debug(result.toString())
+ if (result.status !in 200..299)
+ throw BlueprintProcessorException(result.body)
+ } catch (e: Exception) {
+ log.error("Caught exception trying to delete config instance")
+ throw BlueprintProcessorException("${e.message}")
+ }
+ }
+
fun rollbackConfigurationValues(instanceId: String): K8sConfigValueResponse? {
val rbInstanceService = K8sRbInstanceRestClient(k8sConfiguration, instanceId)
try {
@@ -305,7 +354,7 @@ class K8sPluginInstanceApi(
}
}
- fun createConfigurationValues(instanceId: String): K8sConfigValueResponse? {
+ fun tagConfigurationValues(instanceId: String): K8sConfigValueResponse? {
val rbInstanceService = K8sRbInstanceRestClient(k8sConfiguration, instanceId)
try {
val result: BlueprintWebClientService.WebClientResponse<String> = rbInstanceService.exchangeResource(
diff --git a/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/BlueprintConstants.kt b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/BlueprintConstants.kt
index cfe436023..256339c62 100644
--- a/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/BlueprintConstants.kt
+++ b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/BlueprintConstants.kt
@@ -232,6 +232,7 @@ object BlueprintConstants {
const val MODEL_TYPE_ARTIFACT_DIRECTED_GRAPH = "artifact-directed-graph"
const val MODEL_TYPE_ARTIFACT_COMPONENT_JAR = "artifact-component-jar"
const val MODEL_TYPE_ARTIFACT_K8S_PROFILE = "artifact-k8sprofile-content"
+ const val MODEL_TYPE_ARTIFACT_K8S_CONFIG = "artifact-k8sconfig-content"
const val TOSCA_SPEC = "TOSCA"
diff --git a/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/GraphExtensionFunctions.kt b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/GraphExtensionFunctions.kt
index 5995a8a9e..26f74669e 100644
--- a/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/GraphExtensionFunctions.kt
+++ b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/GraphExtensionFunctions.kt
@@ -33,7 +33,7 @@ fun String.toGraph(): Graph {
if (!startsWith('[') || !endsWith(']')) {
throw IllegalArgumentException("Expected string starting '[' and ending with ']' but it was '$")
}
- val tokens = substring(1, length - 1).split(", ").map { it.split(graphTokenSeparators) }
+ val tokens = substring(1, length - 1).replace("\n", "").split(", ").map { it.trim().split(graphTokenSeparators) }
val nodes = tokens.flatMap { it.take(2) }.toCollection(LinkedHashSet())
val edges = tokens.filter { it.size == 3 }.map { Graph.TermForm.Term(it[0], it[1], EdgeLabel.valueOf(it[2])) }
return Graph.labeledDirectedTerms(Graph.TermForm(nodes, edges))
@@ -41,7 +41,7 @@ fun String.toGraph(): Graph {
fun Graph.toAdjacencyList(): Graph.AdjacencyList<String, EdgeLabel> {
val entries = nodes.values.map { node ->
- val links = node.edges.map { Graph.AdjacencyList.Link(it.target(node).id, it.label) }
+ val links = node.edges.map { Graph.AdjacencyList.Link(it.target.id, it.label) }
Graph.AdjacencyList.Entry(node = node.id, links = links)
}
return Graph.AdjacencyList(entries)
@@ -54,14 +54,33 @@ fun Graph.findAllPaths(from: String, to: String, path: List<String> = emptyList(
.flatMap { findAllPaths(it.id, to, path + from) }
}
-fun Graph.findCycles(node: String): List<List<String>> {
- fun findCycles(path: List<String>): List<List<String>> {
- if (path.size > 3 && path.first() == path.last()) return listOf(path)
- return nodes[path.last()]!!.neighbors()
- .filterNot { path.tail().contains(it.id) }
- .flatMap { findCycles(path + it.id) }
+fun Graph.isAcyclic(): Boolean {
+ val startNodes = startNodes()
+ if (startNodes.isEmpty())
+ return false
+
+ val adj: Map<String, Set<String>> = toAdjacencyList().entries
+ .associate { it.node to it.links }
+ .mapValues { it.value.map { x -> x.node }.toSet() }
+
+ fun hasCycle(node: String, visited: MutableSet<String> = mutableSetOf()): Boolean {
+ if (visited.contains(node))
+ return true
+ visited.add(node)
+
+ if (adj[node]!!.isEmpty()) {
+ visited.remove(node)
+ return false
+ }
+
+ if (adj[node]!!.any { hasCycle(it, visited) })
+ return true
+
+ visited.remove(node)
+ return false
}
- return findCycles(listOf(node))
+
+ return startNodes.none { n -> hasCycle(n.id) }
}
fun Graph.startNodes() = this.nodes.values.filter {
diff --git a/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/data/BlueprintGraph.kt b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/data/BlueprintGraph.kt
index b833db755..bc6cbe426 100644
--- a/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/data/BlueprintGraph.kt
+++ b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/data/BlueprintGraph.kt
@@ -97,10 +97,10 @@ class Graph {
val edges: MutableList<Edge> = ArrayList()
- fun neighbors(): List<Node> = edges.map { edge -> edge.target(this) }
+ fun neighbors(): List<Node> = edges.map { it.target }
fun neighbors(label: EdgeLabel): List<Node> = edges.filter { it.label == label }
- .map { edge -> edge.target(this) }
+ .map { it.target }
fun labelEdges(label: EdgeLabel): List<Edge> = edges.filter { it.label == label }
@@ -114,8 +114,6 @@ class Graph {
var status: EdgeStatus = EdgeStatus.NOT_STARTED
) {
- fun target(node: Node): Node = target
-
fun equivalentTo(other: Edge) =
(source == other.source && target == other.target) ||
(source == other.target && target == other.source)
diff --git a/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/dsl/BlueprintDSL.kt b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/dsl/BlueprintDSL.kt
index 503e07048..81593c935 100644
--- a/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/dsl/BlueprintDSL.kt
+++ b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/dsl/BlueprintDSL.kt
@@ -327,6 +327,22 @@ fun BlueprintTypes.artifactTypeK8sProfileFolder(): ArtifactType {
}
}
+fun ServiceTemplateBuilder.artifactTypeK8sConfigFolder() {
+ val artifactType = BlueprintTypes.artifactTypeK8sConfigFolder()
+ if (this.artifactTypes == null) this.artifactTypes = hashMapOf()
+ this.artifactTypes!![artifactType.id!!] = artifactType
+}
+
+fun BlueprintTypes.artifactTypeK8sConfigFolder(): ArtifactType {
+ return artifactType(
+ id = BlueprintConstants.MODEL_TYPE_ARTIFACT_K8S_CONFIG,
+ version = BlueprintConstants.DEFAULT_VERSION_NUMBER,
+ derivedFrom = BlueprintConstants.MODEL_TYPE_ARTIFACT_TYPE_IMPLEMENTATION,
+ description = "K8s Config Folder Artifact"
+ ) {
+ }
+}
+
@Deprecated("CDS won't support, use implerative workflow definitions.")
fun BlueprintTypes.artifactTypeDirectedGraph(): ArtifactType {
return artifactType(
diff --git a/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/GraphExtensionFunctionsTest.kt b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/GraphExtensionFunctionsTest.kt
index 86cb473ae..ba4115f02 100644
--- a/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/GraphExtensionFunctionsTest.kt
+++ b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/GraphExtensionFunctionsTest.kt
@@ -18,7 +18,9 @@ package org.onap.ccsdk.cds.controllerblueprints.core
import org.junit.Test
import org.onap.ccsdk.cds.controllerblueprints.core.data.EdgeLabel
+import kotlin.test.assertFalse
import kotlin.test.assertNotNull
+import kotlin.test.assertTrue
class GraphExtensionFunctionsTest {
@@ -34,4 +36,73 @@ class GraphExtensionFunctionsTest {
val nodePath = graph.nodes["p"]!!.neighbors(EdgeLabel.SUCCESS)
assertNotNull(nodePath, "failed to nodePath from graph for 'p' node 'SUCCESS' label")
}
+
+ @Test
+ fun `isAcyclic should return false`() {
+ assertFalse(
+ """[
+ assign>deploy/SUCCESS,
+ deploy>assign/FAILURE
+ ]""".toGraph().isAcyclic()
+ )
+
+ assertFalse(
+ """[
+ assign>deploy/SUCCESS,
+ deploy>recover/FAILURE,
+ recover>deploy/SUCCESS
+ ]""".toGraph().isAcyclic()
+ )
+
+ assertFalse(
+ """[
+ assign>deploy/SUCCESS,
+ assign>recover/FAILURE,
+ recover>deploy/SUCCESS,
+ deploy>finalize/SUCCESS,
+ deploy>recover/FAILURE
+ ]""".toGraph().isAcyclic()
+ )
+
+ assertFalse(
+ """[
+ A>B/SUCCESS,
+ A>C/SUCCESS,
+ B>E/SUCCESS,
+ B>D/FAILURE,
+ D>B/FAILURE,
+ C>E/SUCCESS
+ ]""".toGraph().isAcyclic()
+ )
+ }
+
+ @Test
+ fun `isAcyclic should return true`() {
+ assertTrue(
+ """[
+ assign>deploy/SUCCESS,
+ deploy>recover/FAILURE
+ ]""".toGraph().isAcyclic()
+ )
+
+ assertTrue(
+ """[
+ A>C/SUCCESS,
+ A>B/FAILURE,
+ C>B/SUCCESS
+ ]""".toGraph().isAcyclic()
+ )
+
+ assertTrue(
+ """[
+ assign>execute1/SUCCESS,
+ assign>execute2/SUCCESS,
+ execute1>finalize/SUCCESS,
+ execute2>finalize/SUCCESS,
+ execute1>cleanup/FAILURE,
+ execute2>cleanup/FAILURE,
+ finalize>cleanup/SUCCESS
+ ]""".toGraph().isAcyclic()
+ )
+ }
}
diff --git a/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/dsl/BlueprintDSLTest.kt b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/dsl/BlueprintDSLTest.kt
index 5143c9dc7..57f671dc4 100644
--- a/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/dsl/BlueprintDSLTest.kt
+++ b/ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/dsl/BlueprintDSLTest.kt
@@ -111,6 +111,7 @@ class BlueprintDSLTest {
artifactTypeMappingResource()
artifactTypeComponentJar()
artifactTypeK8sProfileFolder()
+ artifactTypeK8sConfigFolder()
relationshipTypeConnectsTo()
relationshipTypeDependsOn()
diff --git a/ms/blueprintsprocessor/modules/services/workflow-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/ImperativeWorkflowExecutionService.kt b/ms/blueprintsprocessor/modules/services/workflow-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/ImperativeWorkflowExecutionService.kt
index 2278dbfb4..561136a87 100644
--- a/ms/blueprintsprocessor/modules/services/workflow-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/ImperativeWorkflowExecutionService.kt
+++ b/ms/blueprintsprocessor/modules/services/workflow-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/ImperativeWorkflowExecutionService.kt
@@ -23,6 +23,7 @@ import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceOutp
import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.Status
import org.onap.ccsdk.cds.controllerblueprints.common.api.EventType
import org.onap.ccsdk.cds.controllerblueprints.core.BlueprintConstants
+import org.onap.ccsdk.cds.controllerblueprints.core.BlueprintException
import org.onap.ccsdk.cds.controllerblueprints.core.BlueprintProcessorException
import org.onap.ccsdk.cds.controllerblueprints.core.MDCContext
import org.onap.ccsdk.cds.controllerblueprints.core.asGraph
@@ -30,6 +31,7 @@ import org.onap.ccsdk.cds.controllerblueprints.core.checkNotEmpty
import org.onap.ccsdk.cds.controllerblueprints.core.data.EdgeLabel
import org.onap.ccsdk.cds.controllerblueprints.core.data.Graph
import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BlueprintWorkflowExecutionService
+import org.onap.ccsdk.cds.controllerblueprints.core.isAcyclic
import org.onap.ccsdk.cds.controllerblueprints.core.logger
import org.onap.ccsdk.cds.controllerblueprints.core.service.AbstractBlueprintWorkFlowService
import org.onap.ccsdk.cds.controllerblueprints.core.service.BlueprintRuntimeService
@@ -57,6 +59,10 @@ class ImperativeWorkflowExecutionService(
val graph = bluePrintContext.workflowByName(workflowName).asGraph()
+ if (!graph.isAcyclic()) {
+ throw BlueprintException("Imperative workflow must be acyclic. Check on_success/on_failure for circular references")
+ }
+
return coroutineScope {
ImperativeBlueprintWorkflowService(
nodeTemplateExecutionService,