diff options
author | 2020-02-18 18:54:44 +0000 | |
---|---|---|
committer | 2020-02-26 15:23:42 +0000 | |
commit | 94ad509756f17e79c278e3cc2f87440009125cd1 (patch) | |
tree | ccd6a842eb0fdca66689b2569cd71cb78ec81cd2 /components/model-catalog/blueprint-model/uat-blueprints/PNF_CDS_RESTCONF/Scripts/kotlin | |
parent | ac31d2159014a84de91b6c7baeb29adf90284c10 (diff) |
Merge SW Upgrade Blueprint into PNF_AAI and create one UAT BP for PNF
UAT: Add support to multiple responses for a single request
Set property IN_UAT=1 during UAT execution
so blueprints can tune their settings to values more
suitable for testing (like timeouts)
Add 'times' field to specify expected number of invocations
Add UAT blueprint script for PNF SW Upgrade UC
Add current thread check for Hazelcast distributed lock
Resolve URI before returning
Issue-ID: CCSDK-2091
Change-Id: Id256bad043488f88f1b60015ebf9ade4be607fa2
Signed-off-by: gummar <raj.gumma@est.tech>
Diffstat (limited to 'components/model-catalog/blueprint-model/uat-blueprints/PNF_CDS_RESTCONF/Scripts/kotlin')
2 files changed, 288 insertions, 0 deletions
diff --git a/components/model-catalog/blueprint-model/uat-blueprints/PNF_CDS_RESTCONF/Scripts/kotlin/RestconfConfigDeploy.kt b/components/model-catalog/blueprint-model/uat-blueprints/PNF_CDS_RESTCONF/Scripts/kotlin/RestconfConfigDeploy.kt new file mode 100644 index 000000000..730565959 --- /dev/null +++ b/components/model-catalog/blueprint-model/uat-blueprints/PNF_CDS_RESTCONF/Scripts/kotlin/RestconfConfigDeploy.kt @@ -0,0 +1,93 @@ +/* +* ============LICENSE_START======================================================= +* Copyright (C) 2020 Nordix Foundation. +* ================================================================================ +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============LICENSE_END========================================================= + */ + + +package cba.pnf.config.aai + + +import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput +import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.contentFromResolvedArtifactNB +import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.storedContentFromResolvedArtifactNB +import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.restconfMountDevice +import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.restconfApplyDeviceConfig +import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.restconfUnMountDevice +import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.restconfDeviceConfig +import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.restconfClientService +import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.AbstractScriptComponentFunction +import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException +import org.onap.ccsdk.cds.controllerblueprints.core.logger +import com.fasterxml.jackson.databind.ObjectMapper +import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BlueprintWebClientService.WebClientResponse + +class RestconfConfigDeploy : AbstractScriptComponentFunction() { + private val CONFIGLET_TEMPLATE_NAME = "config-assign" + private val CONFIGLET_RESOURCE_PATH = "yang-ext:mount/mynetconf:netconflist" + private val RESTCONF_SERVER_IDENTIFIER = "sdnc" + private val mapper = ObjectMapper() + private val log = logger(AbstractScriptComponentFunction::class.java) + + override suspend fun processNB(executionRequest: ExecutionServiceInput) { + log.info("Started execution of process method") + try { + // Extract Resolution key & Device ID + val resolutionKey = getDynamicProperties("resolution-key").asText() + log.info("resolution_key: $resolutionKey") + val deviceID: String = requestPayloadActionProperty("config-deploy-properties")?.get(0)?.get("pnf-id")?.textValue()!! + log.info("device_id: $deviceID") + val webclientService = restconfClientService(RESTCONF_SERVER_IDENTIFIER) + + try { + // Mount the device + val mountPayload = contentFromResolvedArtifactNB("config-deploy") + log.debug("Mounting Device : $deviceID") + restconfMountDevice(webclientService, deviceID, mountPayload, mutableMapOf("Content-Type" to "application/json")) + + //Log the current configuration for the subtree + val currentConfig: Any = restconfDeviceConfig(webclientService, deviceID, CONFIGLET_RESOURCE_PATH) + log.info("Current configuration subtree : $currentConfig") + //Apply configlet + val result = restconfApplyDeviceConfig(webclientService, deviceID, CONFIGLET_RESOURCE_PATH, + storedContentFromResolvedArtifactNB(resolutionKey, CONFIGLET_TEMPLATE_NAME), + mutableMapOf("Content-Type" to "application/yang.patch+json")) as WebClientResponse<*> + + val jsonResult = mapper.readTree((result.body).toString()) + + if (jsonResult.get("ietf-yang-patch:yang-patch-status").get("errors") != null) { + log.error("There was an error configuring device") + } else { + log.info("Device has been configured succesfully") + } + + } catch (err: Exception) { + log.error("an error occurred while configuring device {}", err) + } finally { + //Un mount device + restconfUnMountDevice(webclientService, deviceID, "") + } + } catch (bpe: BluePrintProcessorException) { + log.error("Error looking up server identifier ", bpe) + } + } + + + override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: ExecutionServiceInput) { + log.info("Recover function called!") + log.info("Execution request : $executionRequest") + log.error("Exception", runtimeException) + } +}
\ No newline at end of file diff --git a/components/model-catalog/blueprint-model/uat-blueprints/PNF_CDS_RESTCONF/Scripts/kotlin/RestconfSoftwareUpgrade.kt b/components/model-catalog/blueprint-model/uat-blueprints/PNF_CDS_RESTCONF/Scripts/kotlin/RestconfSoftwareUpgrade.kt new file mode 100644 index 000000000..07e804b95 --- /dev/null +++ b/components/model-catalog/blueprint-model/uat-blueprints/PNF_CDS_RESTCONF/Scripts/kotlin/RestconfSoftwareUpgrade.kt @@ -0,0 +1,195 @@ +/* +* ============LICENSE_START======================================================= +* Copyright (C) 2020 Nordix Foundation. +* ================================================================================ +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* ============LICENSE_END========================================================= + */ + + +package cba.pnf.swug + +import com.fasterxml.jackson.databind.node.ObjectNode +import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput +import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.contentFromResolvedArtifactNB +import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.restconfApplyDeviceConfig +import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.restconfDeviceConfig +import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.restconfMountDevice +import org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor.restconfUnMountDevice +import org.onap.ccsdk.cds.blueprintsprocessor.rest.restClientService +import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BlueprintWebClientService +import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.AbstractScriptComponentFunction +import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException +import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintRetryException +import org.onap.ccsdk.cds.controllerblueprints.core.logger +import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintDependencyService +import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils + +class RestconfSoftwareUpgrade : AbstractScriptComponentFunction() { + + private val RESTCONF_SERVER_IDENTIFIER = "sdnc" + private val CONFIGLET_RESOURCE_PATH = "yang-ext:mount/pnf-sw-upgrade:software-upgrade" + private val log = logger(AbstractScriptComponentFunction::class.java) + private val TARGET_SOFTWARE_PATH = "$CONFIGLET_RESOURCE_PATH/upgrade-package/" + + override suspend fun processNB(executionRequest: ExecutionServiceInput) { + + // Extract request properties + val properties = requestPayloadActionProperty(executionRequest.actionIdentifiers.actionName + "-properties")!!.get(0) + val model= SoftwareUpgradeModel(getDynamicProperties("resolution-key").asText(), + BluePrintDependencyService.restClientService(RESTCONF_SERVER_IDENTIFIER), + properties.get("pnf-id").textValue(), properties.get("target-software-version").textValue(), + Action.getEnumFromActionName(executionRequest.actionIdentifiers.actionName)) + + log.info("Blueprint invoked for ${model.resolutionKey} for SW Upgrade : " + + "${model.action} for sw version ${model.targetSwVersion} on pnf: ${model.deviceId}") + + try { + val mountPayload = contentFromResolvedArtifactNB("mount-node") + log.debug("Mount Payload : $mountPayload") + restconfMountDevice(model.client, model.deviceId, mountPayload, mutableMapOf("Content-Type" to "application/json")) + + when (model.action) { + Action.PRE_CHECK -> processPrecheck(model) + Action.DOWNLOAD_NE_SW -> processDownloadNeSw(model) + Action.ACTIVATE_NE_SW -> processActivateNeSw(model) + Action.POST_CHECK -> processPostcheck(model) + Action.CANCEL -> processCancel(model) + } + + } catch (err: Exception) { + log.error("an error occurred while configuring device {}", err) + } finally { + restconfUnMountDevice(model.client, model.deviceId, "") + } + } + + private suspend fun processPrecheck(model: SoftwareUpgradeModel) { + log.debug("In PNF SW upgrade : processPreCheck") + //Log the current configuration for the subtree + val payloadObject = getCurrentConfig(model) + log.debug("Current sw version on pnf : ${payloadObject.get("software-upgrade")?.get("upgrade-package")?.get(0)?.get("software-version")?.asText()}") + log.info("PNF is Healthy!") + } + + private suspend fun processDownloadNeSw(model: SoftwareUpgradeModel) { + log.debug("In PNF SW upgrade : processDownloadNeSw") + //Check if there is existing config for the targeted software version + + var downloadConfigPayload: String + if (checkIfSwReadyToPerformAction(Action.PRE_CHECK, model)) { + downloadConfigPayload = contentFromResolvedArtifactNB("configure") + downloadConfigPayload =downloadConfigPayload.replace("%id%", model.yangId) + } + else { + downloadConfigPayload = contentFromResolvedArtifactNB("download-ne-sw") + model.yangId=model.targetSwVersion + } + downloadConfigPayload = downloadConfigPayload.replace("%actionName%", Action.DOWNLOAD_NE_SW.name) + log.info("Config Payload to start download : $downloadConfigPayload") + + //Apply configlet + restconfApplyDeviceConfig(model.client, model.deviceId, CONFIGLET_RESOURCE_PATH, downloadConfigPayload, + mutableMapOf("Content-Type" to "application/yang.patch+json")) + + //Poll PNF for Download action's progress + checkExecution(model) + } + + private suspend fun processActivateNeSw(model: SoftwareUpgradeModel) { + log.debug("In PNF SW upgrade : processActivateNeSw") + //Check if the software is downloaded and ready to be activated + if (checkIfSwReadyToPerformAction(Action.DOWNLOAD_NE_SW, model)) { + var activateConfigPayload: String = contentFromResolvedArtifactNB("configure") + activateConfigPayload = activateConfigPayload.replace("%actionName%", Action.ACTIVATE_NE_SW.name) + log.info("Config Payload to start activate : $activateConfigPayload") + //Apply configlet + restconfApplyDeviceConfig(model.client, model.deviceId, CONFIGLET_RESOURCE_PATH, activateConfigPayload, + mutableMapOf("Content-Type" to "application/yang.patch+json")) + + //Poll PNF for Activate action's progress + checkExecution(model) + } else { + throw BluePrintRetryException("Software Download not completed for device(${model.deviceId}) to activate sw version: ${model.targetSwVersion}") + } + } + + private suspend fun processPostcheck(model: SoftwareUpgradeModel) { + log.info("In PNF SW upgrade : processPostcheck") + //Log the current configuration for the subtree + if (checkIfSwReadyToPerformAction(Action.POST_CHECK, model)) { + log.info("PNF is healthy post activation!") + } + } + + private fun processCancel(model :SoftwareUpgradeModel) { + //This is for future implementation of cancel step during software upgrade + log.info("In PNF SW upgrade : processCancel") + } + + private suspend fun getCurrentConfig(model: SoftwareUpgradeModel) : ObjectNode{ + val currentConfig: BlueprintWebClientService.WebClientResponse<String> = restconfDeviceConfig(model.client, model.deviceId, CONFIGLET_RESOURCE_PATH) + return JacksonUtils.jsonNode(currentConfig.body) as ObjectNode + } + private suspend fun checkExecution(model: SoftwareUpgradeModel) { + val checkExecutionBlock: suspend (Int) -> String = { + val result = restconfDeviceConfig(model.client, model.deviceId, TARGET_SOFTWARE_PATH.plus(model.yangId)) + if (result.body.contains(model.action.completionStatus)) { + log.info("${model.action.name} is complete") + result.body + } else { + throw BluePrintRetryException("Waiting for device(${model.deviceId}) to activate sw version ${model.targetSwVersion}") + } + } + model.client.retry<String>(10, 0, 1000, checkExecutionBlock) + + } + + private suspend fun checkIfSwReadyToPerformAction(action : Action, model: SoftwareUpgradeModel): Boolean { + val configBody = getCurrentConfig(model) + configBody.get("software-upgrade")?.get("upgrade-package")?.iterator()?.forEach { item -> + if (model.targetSwVersion == item.get("software-version")?.asText() && + action.completionStatus == item?.get("current-status")?.asText()) { + model.yangId= item.get("id").textValue() + return true + } + } + return false + } + + override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: ExecutionServiceInput) { + log.info("Recover function called!") + log.info("Execution request : $executionRequest") + log.error("Exception", runtimeException) + } +} + +enum class Action(val actionName: String, val completionStatus: String) { + PRE_CHECK("precheck", "INITIALIZED"), + DOWNLOAD_NE_SW("downloadNeSw", "DOWNLOAD_COMPLETED"), + ACTIVATE_NE_SW("activateNeSw", "ACTIVATION_COMPLETED"), + POST_CHECK("postcheck", "ACTIVATION_COMPLETED"), + CANCEL("cancel", "CANCELLED") + ; + companion object{ + fun getEnumFromActionName(name: String): Action { + for(value in values()){ + if (value.actionName==name) return value + } + throw BluePrintException("Invalid Action sent to CDS") + } + } +} + +data class SoftwareUpgradeModel(val resolutionKey: String, val client: BlueprintWebClientService, val deviceId: String, + val targetSwVersion: String, val action: Action, var yangId: String = "")
\ No newline at end of file |