diff options
Diffstat (limited to 'adapters')
202 files changed, 17343 insertions, 2306 deletions
diff --git a/adapters/mso-adapter-utils/src/main/java/org/onap/so/cloudify/utils/MsoCloudifyUtils.java b/adapters/mso-adapter-utils/src/main/java/org/onap/so/cloudify/utils/MsoCloudifyUtils.java index e821d806dd..9042095e84 100644 --- a/adapters/mso-adapter-utils/src/main/java/org/onap/so/cloudify/utils/MsoCloudifyUtils.java +++ b/adapters/mso-adapter-utils/src/main/java/org/onap/so/cloudify/utils/MsoCloudifyUtils.java @@ -258,7 +258,7 @@ public class MsoCloudifyUtils extends MsoCommonUtils implements VduPlugin { // The workflow completed with errors. Must try to back it out. if (!backout) { logger.warn("{} Deployment installation failed, backout deletion suppressed {} {}", - MessageEnum.RA_CREATE_STACK_ERR, ErrorCode.BusinessProcesssError.getValue(), + MessageEnum.RA_CREATE_STACK_ERR, ErrorCode.BusinessProcessError.getValue(), "Exception in Deployment Installation, backout suppressed"); } else { // Poll on delete if we rollback - use same values for now @@ -278,13 +278,13 @@ public class MsoCloudifyUtils extends MsoCommonUtils implements VduPlugin { // Didn't uninstall successfully. Log this error logger.error("{} Create Deployment: Cloudify error rolling back deployment install: {} {}", MessageEnum.RA_CREATE_STACK_ERR, installWorkflow.getError(), - ErrorCode.BusinessProcesssError.getValue()); + ErrorCode.BusinessProcessError.getValue()); } } catch (Exception e) { // Catch-all for backout errors trying to uninstall/delete // Log this error, and return the original exception logger.error("{} Create Stack: Nested exception rolling back deployment install: {}", - MessageEnum.RA_CREATE_STACK_ERR, ErrorCode.BusinessProcesssError.getValue(), e); + MessageEnum.RA_CREATE_STACK_ERR, ErrorCode.BusinessProcessError.getValue(), e); } } @@ -299,7 +299,7 @@ public class MsoCloudifyUtils extends MsoCommonUtils implements VduPlugin { if (!backout) { logger.warn("{} Deployment installation failed, backout deletion suppressed {}", - MessageEnum.RA_CREATE_STACK_ERR, ErrorCode.BusinessProcesssError.getValue()); + MessageEnum.RA_CREATE_STACK_ERR, ErrorCode.BusinessProcessError.getValue()); } else { // Poll on delete if we rollback - use same values for now int deletePollInterval = createPollInterval; @@ -318,7 +318,7 @@ public class MsoCloudifyUtils extends MsoCommonUtils implements VduPlugin { // Catch-all for backout errors trying to uninstall/delete // Log this error, and return the original exception logger.error("{} Create Stack: Nested exception rolling back deployment install: {} ", - MessageEnum.RA_CREATE_STACK_ERR, ErrorCode.BusinessProcesssError.getValue(), e); + MessageEnum.RA_CREATE_STACK_ERR, ErrorCode.BusinessProcessError.getValue(), e); } } @@ -350,7 +350,7 @@ public class MsoCloudifyUtils extends MsoCommonUtils implements VduPlugin { } catch (CloudifyConnectException ce) { // Couldn't connect to Cloudify logger.error("{} QueryDeploymentOutputs: Cloudify connection failure: {} ", MessageEnum.RA_CREATE_STACK_ERR, - ErrorCode.BusinessProcesssError.getValue(), ce); + ErrorCode.BusinessProcessError.getValue(), ce); throw new MsoIOException(ce.getMessage(), ce); } catch (CloudifyResponseException re) { if (re.getStatus() == 404) { @@ -419,7 +419,11 @@ public class MsoCloudifyUtils extends MsoCommonUtils implements VduPlugin { logger.debug("pollTimeout remaining: " + pollTimeout); execution = queryExecution.execute(); - status = execution.getStatus(); + if (execution != null) { + status = execution.getStatus(); + } else { + status = TERMINATED; + } } // Broke the loop. Check again for a terminal state @@ -431,32 +435,32 @@ public class MsoCloudifyUtils extends MsoCommonUtils implements VduPlugin { // Workflow failed. Log it and return the execution object (don't throw exception here) logger.error("{} Cloudify workflow failure: {} {} Execute Workflow: Failed: {}", MessageEnum.RA_CREATE_STACK_ERR, execution.getError(), - ErrorCode.BusinessProcesssError.getValue(), execution.getError()); + ErrorCode.BusinessProcessError.getValue(), execution.getError()); return execution; } else if (status.equals(CANCELLED)) { // Workflow was cancelled, leaving the deployment in an indeterminate state. Log it and return the // execution object (don't throw exception here) logger.error("{} Cloudify workflow cancelled. Deployment is in an indeterminate state {} {} {}", - MessageEnum.RA_CREATE_STACK_ERR, ErrorCode.BusinessProcesssError.getValue(), + MessageEnum.RA_CREATE_STACK_ERR, ErrorCode.BusinessProcessError.getValue(), "Execute Workflow cancelled: ", workflowId); return execution; } else { // Can only get here after a timeout logger.error("{} Cloudify workflow timeout {} Execute Workflow: Timed Out", - MessageEnum.RA_CREATE_STACK_ERR, ErrorCode.BusinessProcesssError.getValue()); + MessageEnum.RA_CREATE_STACK_ERR, ErrorCode.BusinessProcessError.getValue()); } } catch (CloudifyConnectException ce) { logger.error("{} {} Execute Workflow ({} {}): Cloudify connection failure {} ", - MessageEnum.RA_CREATE_STACK_ERR, ErrorCode.BusinessProcesssError.getValue(), command, ce); + MessageEnum.RA_CREATE_STACK_ERR, ErrorCode.BusinessProcessError.getValue(), command, ce); savedException = ce; } catch (CloudifyResponseException re) { logger.error("{} {} Execute Workflow ({}): Cloudify response error {} ", MessageEnum.RA_CREATE_STACK_ERR, - ErrorCode.BusinessProcesssError.getValue(), command, re.getMessage(), re); + ErrorCode.BusinessProcessError.getValue(), command, re.getMessage(), re); savedException = re; } catch (RuntimeException e) { // Catch-all logger.error("{} {} Execute Workflow ({}): Internal error {}", MessageEnum.RA_CREATE_STACK_ERR, - ErrorCode.BusinessProcesssError.getValue(), command, e.getMessage(), e); + ErrorCode.BusinessProcessError.getValue(), command, e.getMessage(), e); savedException = e; } @@ -478,12 +482,14 @@ public class MsoCloudifyUtils extends MsoCommonUtils implements VduPlugin { boolean timedOut = false; int cancelTimeout = timeout; // TODO: For now, just use same timeout - String status = cancelExecution.getStatus(); - + String status = null; + if (cancelExecution != null) { + status = cancelExecution.getStatus(); + } // Poll for completion. Create a reusable cloudify query request GetExecution queryExecution = cloudify.executions().byId(executionId); - while (!timedOut && !status.equals(CANCELLED)) { + while (!timedOut && !CANCELLED.equals(status)) { // workflow is still running; check for timeout if (cancelTimeout <= 0) { logger.debug("Cancel timeout for workflow {} on deployment {}", workflowId, deploymentId); @@ -497,11 +503,13 @@ public class MsoCloudifyUtils extends MsoCommonUtils implements VduPlugin { logger.debug("pollTimeout remaining: {}", cancelTimeout); execution = queryExecution.execute(); - status = execution.getStatus(); + if (execution != null) { + status = execution.getStatus(); + } } // Broke the loop. Check again for a terminal state - if (status.equals(CANCELLED)) { + if (CANCELLED.equals(status)) { // Finished cancelling. Return the original exception logger.debug("Cancel workflow {} completed on deployment {}", workflowId, deploymentId); throw new MsoCloudifyException(-1, "", "", savedException); @@ -558,7 +566,7 @@ public class MsoCloudifyUtils extends MsoCommonUtils implements VduPlugin { Executions executions = listExecutions.execute(); // If no executions, does this give NOT_FOUND or empty set? - if (executions.getItems().isEmpty()) { + if (executions == null || executions.getItems().isEmpty()) { return new DeploymentInfoBuilder().withId(deployment.getId()) .withDeploymentInputs(deployment.getInputs()).build(); } else { @@ -570,7 +578,7 @@ public class MsoCloudifyUtils extends MsoCommonUtils implements VduPlugin { } catch (CloudifyConnectException ce) { // Couldn't connect to Cloudify logger.error("{} QueryDeployment: Cloudify connection failure: {} ", MessageEnum.RA_CREATE_STACK_ERR, - ErrorCode.BusinessProcesssError.getValue(), ce); + ErrorCode.BusinessProcessError.getValue(), ce); throw new MsoIOException(ce.getMessage(), ce); } catch (CloudifyResponseException re) { if (re.getStatus() == 404) { @@ -747,16 +755,19 @@ public class MsoCloudifyUtils extends MsoCommonUtils implements VduPlugin { GetBlueprint getRequest = cloudify.blueprints().getMetadataById(blueprintId); try { Blueprint bp = getRequest.execute(); - logger.debug("Blueprint exists: {}", bp.getId()); - return true; + if (bp != null) { + logger.debug("Blueprint exists: {}", bp.getId()); + return true; + } else { + logger.debug("Null blueprint!"); + return false; + } } catch (CloudifyResponseException ce) { if (ce.getStatus() == 404) { return false; } else { throw ce; } - } catch (Exception e) { - throw e; } } @@ -795,8 +806,12 @@ public class MsoCloudifyUtils extends MsoCommonUtils implements VduPlugin { GetBlueprint getRequest = cloudify.blueprints().getMetadataById(blueprintId); try { Blueprint bp = getRequest.execute(); - logger.debug("Blueprint {} already exists.", bp.getId()); - return false; + if (bp != null) { + logger.debug("Blueprint {} already exists.", bp.getId()); + return false; + } else { + logger.debug("Null blueprint!"); + } } catch (CloudifyResponseException ce) { if (ce.getStatus() == 404) { // This is the expected result. @@ -804,8 +819,6 @@ public class MsoCloudifyUtils extends MsoCommonUtils implements VduPlugin { } else { throw ce; } - } catch (Exception e) { - throw e; } // Create a blueprint ZIP file in memory diff --git a/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MsoHeatEnvironmentEntry.java b/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MsoHeatEnvironmentEntry.java index 8cacf8526a..47ba076e0e 100644 --- a/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MsoHeatEnvironmentEntry.java +++ b/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MsoHeatEnvironmentEntry.java @@ -132,14 +132,14 @@ public class MsoHeatEnvironmentEntry { } public boolean hasResources() { - if (this.resources != null && this.resources.size() > 0) { + if (this.resources != null && !this.resources.isEmpty()) { return true; } return false; } public boolean hasParameters() { - if (this.parameters != null && this.parameters.size() > 0) { + if (this.parameters != null && !this.parameters.isEmpty()) { return true; } return false; @@ -147,7 +147,7 @@ public class MsoHeatEnvironmentEntry { public boolean containsParameter(String paramName) { boolean contains = false; - if (this.parameters == null || this.parameters.size() < 1) { + if (this.parameters == null || this.parameters.isEmpty()) { return false; } if (this.parameters.contains(new MsoHeatEnvironmentParameter(paramName))) { @@ -246,22 +246,4 @@ public class MsoHeatEnvironmentEntry { sb.append(this.rawEntry.substring(indexOf)); return sb; } - - public void setHPAParameters(StringBuilder hpasb) { - try { - MsoYamlEditorWithEnvt yaml = new MsoYamlEditorWithEnvt(hpasb.toString().getBytes()); - Set<MsoHeatEnvironmentParameter> hpaParams = yaml.getParameterListFromEnvt(); - for (MsoHeatEnvironmentParameter hpaparam : hpaParams) { - for (MsoHeatEnvironmentParameter param : this.parameters) { - if (param.getName() == hpaparam.getName()) { - param.setValue(hpaparam.getValue()); - } - } - } - } catch (Exception e) { - logger.debug("Exception:", e); - this.errorString = e.getMessage(); - // e.printStackTrace(); - } - } } diff --git a/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MsoHeatUtils.java b/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MsoHeatUtils.java index 6565db7ebc..16639d9166 100644 --- a/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MsoHeatUtils.java +++ b/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MsoHeatUtils.java @@ -89,6 +89,10 @@ import com.woorea.openstack.heat.model.Stacks; @Component public class MsoHeatUtils extends MsoCommonUtils implements VduPlugin { + private static final String CREATE_FAILED = "CREATE_FAILED"; + + private static final String DELETE_FAILED = "DELETE_FAILED"; + private static final String CREATE_COMPLETE = "CREATE_COMPLETE"; private static final String DELETE_COMPLETE = "DELETE_COMPLETE"; @@ -123,52 +127,14 @@ public class MsoHeatUtils extends MsoCommonUtils implements VduPlugin { // Properties names and variables (with default values) protected String createPollIntervalProp = "org.onap.so.adapters.po.pollInterval"; - private String deletePollIntervalProp = "org.onap.so.adapters.po.pollInterval"; - private String deletePollTimeoutProp = "org.onap.so.adapters.po.pollTimeout"; private String pollingMultiplierProp = "org.onap.so.adapters.po.pollMultiplier"; protected static final String CREATE_POLL_INTERVAL_DEFAULT = "15"; - private static final String DELETE_POLL_INTERVAL_DEFAULT = "15"; private static final String POLLING_MULTIPLIER_DEFAULT = "60"; private static final ObjectMapper JSON_MAPPER = new ObjectMapper(); - /** - * keep this old method signature here to maintain backwards compatibility. keep others as well. this method does - * not include environment, files, or heatFiles - */ - public StackInfo createStack(String cloudSiteId, String cloudOwner, String tenantId, String stackName, - String heatTemplate, Map<String, ?> stackInputs, boolean pollForCompletion, int timeoutMinutes) - throws MsoException { - // Just call the new method with the environment & files variable set to null - return this.createStack(cloudSiteId, cloudOwner, tenantId, stackName, null, heatTemplate, stackInputs, - pollForCompletion, timeoutMinutes, null, null, null, true); - } - // This method has environment, but not files or heatFiles - public StackInfo createStack(String cloudSiteId, String cloudOwner, String tenantId, String stackName, - String heatTemplate, Map<String, ?> stackInputs, boolean pollForCompletion, int timeoutMinutes, - String environment) throws MsoException { - // Just call the new method with the files/heatFiles variables set to null - return this.createStack(cloudSiteId, cloudOwner, tenantId, stackName, null, heatTemplate, stackInputs, - pollForCompletion, timeoutMinutes, environment, null, null, true); - } - - // This method has environment and files, but not heatFiles. - public StackInfo createStack(String cloudSiteId, String cloudOwner, String tenantId, String stackName, - String heatTemplate, Map<String, ?> stackInputs, boolean pollForCompletion, int timeoutMinutes, - String environment, Map<String, Object> files) throws MsoException { - return this.createStack(cloudSiteId, cloudOwner, tenantId, stackName, null, heatTemplate, stackInputs, - pollForCompletion, timeoutMinutes, environment, files, null, true); - } - - // This method has environment, files, heatfiles - public StackInfo createStack(String cloudSiteId, String cloudOwner, String tenantId, String stackName, - String heatTemplate, Map<String, ?> stackInputs, boolean pollForCompletion, int timeoutMinutes, - String environment, Map<String, Object> files, Map<String, Object> heatFiles) throws MsoException { - return this.createStack(cloudSiteId, cloudOwner, tenantId, stackName, null, heatTemplate, stackInputs, - pollForCompletion, timeoutMinutes, environment, files, heatFiles, true); - } /** * Create a new Stack in the specified cloud location and tenant. The Heat template and parameter map are passed in @@ -208,23 +174,52 @@ public class MsoHeatUtils extends MsoCommonUtils implements VduPlugin { * @throws MsoOpenstackException Thrown if the Openstack API call returns an exception. */ - @SuppressWarnings("unchecked") public StackInfo createStack(String cloudSiteId, String cloudOwner, String tenantId, String stackName, VduModelInfo vduModel, String heatTemplate, Map<String, ?> stackInputs, boolean pollForCompletion, - int timeoutMinutes, String environment, Map<String, Object> files, Map<String, Object> heatFiles, - boolean backout) throws MsoException { - + int timeoutMinutes, String environment, Map<String, Object> nestedTemplates, Map<String, Object> heatFiles, + boolean backout, boolean failIfExists) throws MsoException { stripMultiCloudInputs(stackInputs); - CreateStackParam createStack = - createStackParam(stackName, heatTemplate, stackInputs, timeoutMinutes, environment, files, heatFiles); - Stack currentStack = createStack(createStack, cloudSiteId, tenantId); - currentStack.setStackName(stackName); - if (pollForCompletion) { - currentStack = + CreateStackParam createStack = createStackParam(stackName, heatTemplate, stackInputs, timeoutMinutes, + environment, nestedTemplates, heatFiles); + Stack currentStack = queryHeatStack(stackName, cloudSiteId, tenantId); + if (currentStack != null) { + logger.debug("Existing Stack found with Status: {} ", currentStack.getStackStatus()); + if (CREATE_COMPLETE.equals(currentStack.getStackStatus())) { + new StackInfoMapper(currentStack).map(); + } else if (CREATE_IN_PROGRESS.equals(currentStack.getStackStatus())) { + currentStack = processCreateStack(cloudSiteId, tenantId, timeoutMinutes, backout, currentStack, + createStack, true); + } else if (CREATE_FAILED.equals(currentStack.getStackStatus()) + || DELETE_FAILED.equals(currentStack.getStackStatus())) { + try { processCreateStack(cloudSiteId, tenantId, timeoutMinutes, backout, currentStack, createStack, true); + } catch (MsoException e) { + if (e instanceof StackCreationException) { + logger.warn("Error during Stack will attempt to recreate stack"); + currentStack = createStack(createStack, cloudSiteId, tenantId); + currentStack.setStackName(stackName); + if (pollForCompletion) { + currentStack = processCreateStack(cloudSiteId, tenantId, timeoutMinutes, backout, + currentStack, createStack, true); + } else { + currentStack = queryHeatStack(currentStack.getStackName() + "/" + currentStack.getId(), + cloudSiteId, tenantId); + } + } else { + throw e; + } + } + } } else { - currentStack = - queryHeatStack(currentStack.getStackName() + "/" + currentStack.getId(), cloudSiteId, tenantId); + currentStack = createStack(createStack, cloudSiteId, tenantId); + currentStack.setStackName(stackName); + if (pollForCompletion) { + currentStack = processCreateStack(cloudSiteId, tenantId, timeoutMinutes, backout, currentStack, + createStack, true); + } else { + currentStack = + queryHeatStack(currentStack.getStackName() + "/" + currentStack.getId(), cloudSiteId, tenantId); + } } return new StackInfoMapper(currentStack).map(); } @@ -270,7 +265,8 @@ public class MsoHeatUtils extends MsoCommonUtils implements VduPlugin { Stack heatStack, CreateStackParam stackCreate, boolean keyPairCleanUp) throws MsoException { Stack latestStack = null; try { - latestStack = pollStackForStatus(timeoutMinutes, heatStack, CREATE_IN_PROGRESS, cloudSiteId, tenantId); + latestStack = + pollStackForStatus(timeoutMinutes, heatStack, CREATE_IN_PROGRESS, cloudSiteId, tenantId, false); } catch (MsoException me) { logger.error("Exception in Create Stack", me); } @@ -280,67 +276,76 @@ public class MsoHeatUtils extends MsoCommonUtils implements VduPlugin { protected Stack postProcessStackCreate(Stack stack, boolean backout, int timeoutMinutes, boolean cleanUpKeyPair, String cloudSiteId, String tenantId, CreateStackParam stackCreate) throws MsoException { + boolean stackCreationFailed = false; + boolean stackRollbackFailed = false; if (stack == null) { throw new StackCreationException("Unknown Error in Stack Creation"); - } - - logger.info("Performing post processing backout: {} cleanUpKeyPair: {}, stack {}", backout, cleanUpKeyPair, - stack); - if (!CREATE_COMPLETE.equals(stack.getStackStatus())) { - if (cleanUpKeyPair && !Strings.isNullOrEmpty(stack.getStackStatusReason()) - && isKeyPairFailure(stack.getStackStatusReason())) { - return handleKeyPairConflict(cloudSiteId, tenantId, stackCreate, timeoutMinutes, backout, stack); - } - if (!backout) { - logger.info("Status is not CREATE_COMPLETE, stack deletion suppressed"); - throw new StackCreationException("Stack rollback suppressed, stack not deleted"); - } else { - logger.info("Status is not CREATE_COMPLETE, stack deletion will be executed"); - String errorMessage = "Stack Creation Failed Openstack Status: " + stack.getStackStatus() - + " Status Reason: " + stack.getStackStatusReason(); - try { - Stack deletedStack = handleUnknownCreateStackFailure(stack, timeoutMinutes, cloudSiteId, tenantId); - errorMessage = errorMessage + " , Rollback of Stack Creation completed with status: " - + deletedStack.getStackStatus() + " Status Reason: " + deletedStack.getStackStatusReason(); - } catch (StackRollbackException se) { - logger.error("Sync Error Deleting Stack during rollback process", se); - errorMessage = errorMessage + se.getMessage(); - } catch (MsoException e) { - logger.error("Sync Error Deleting Stack during rollback", e); - - errorMessage = - errorMessage + " , Rollback of Stack Creation failed with sync error: " + e.getMessage(); + } else { + logger.info("Performing post processing backout: {} cleanUpKeyPair: {}, stack {}", backout, cleanUpKeyPair, + stack); + if (!CREATE_COMPLETE.equals(stack.getStackStatus())) { + if (cleanUpKeyPair && !Strings.isNullOrEmpty(stack.getStackStatusReason()) + && isKeyPairFailure(stack.getStackStatusReason())) { + return handleKeyPairConflict(cloudSiteId, tenantId, stackCreate, timeoutMinutes, backout, stack); + } + if (!backout) { + logger.info("Status is not CREATE_COMPLETE, stack deletion suppressed"); + stackCreationFailed = true; + throw new StackCreationException("Stack rollback suppressed, stack not deleted", + stackCreationFailed, stackRollbackFailed); + } else { + logger.info("Status is not CREATE_COMPLETE, stack deletion will be executed"); + stackCreationFailed = true; + String errorMessage = "Stack Creation Failed Openstack Status: " + stack.getStackStatus() + + " Status Reason: " + stack.getStackStatusReason(); + try { + Stack deletedStack = + handleUnknownCreateStackFailure(stack, timeoutMinutes, cloudSiteId, tenantId); + errorMessage = errorMessage + " , Rollback of Stack Creation completed with status: " + + deletedStack.getStackStatus() + " Status Reason: " + + deletedStack.getStackStatusReason(); + } catch (MsoException e) { + stackRollbackFailed = true; + logger.error("Sync Error Deleting Stack during rollback", e); + if (e instanceof StackRollbackException) { + errorMessage = errorMessage + e.getMessage(); + } else { + errorMessage = errorMessage + " , Rollback of Stack Creation failed with sync error: " + + e.getMessage(); + } + } + throw new StackCreationException(errorMessage, stackCreationFailed, stackRollbackFailed); } - throw new StackCreationException(errorMessage); + } else { + return stack; } - } else { - return stack; } - } protected Stack pollStackForStatus(int timeoutMinutes, Stack stack, String stackStatus, String cloudSiteId, - String tenantId) throws MsoException { + String tenantId, boolean notFoundIsSuccess) throws MsoException { int pollingFrequency = Integer.parseInt(this.environment.getProperty(createPollIntervalProp, CREATE_POLL_INTERVAL_DEFAULT)); int pollingMultiplier = Integer.parseInt(this.environment.getProperty(pollingMultiplierProp, POLLING_MULTIPLIER_DEFAULT)); int numberOfPollingAttempts = Math.floorDiv((timeoutMinutes * pollingMultiplier), pollingFrequency); Heat heatClient = getHeatClient(cloudSiteId, tenantId); - Stack latestStack = null; while (true) { - latestStack = queryHeatStack(heatClient, stack.getStackName() + "/" + stack.getId()); - statusHandler.updateStackStatus(latestStack); - logger.debug("Polling: {} ({})", latestStack.getStackStatus(), latestStack.getStackName()); - if (stackStatus.equals(latestStack.getStackStatus())) { - if (numberOfPollingAttempts <= 0) { - logger.error("Polling of stack timed out with Status: {}", latestStack.getStackStatus()); + Stack latestStack = queryHeatStack(heatClient, stack.getStackName() + "/" + stack.getId()); + if (latestStack == null && notFoundIsSuccess) { + return null; + } else if (latestStack != null) { + statusHandler.updateStackStatus(latestStack); + if (stackStatus.equals(latestStack.getStackStatus())) { + if (numberOfPollingAttempts <= 0) { + logger.error("Polling of stack timed out with Status: {}", latestStack.getStackStatus()); + return latestStack; + } + sleep(pollingFrequency * 1000L); + numberOfPollingAttempts -= 1; + } else { return latestStack; } - sleep(pollingFrequency * 1000L); - numberOfPollingAttempts -= 1; - } else { - return latestStack; } } } @@ -377,17 +382,26 @@ public class MsoHeatUtils extends MsoCommonUtils implements VduPlugin { protected Stack handleUnknownCreateStackFailure(Stack stack, int timeoutMinutes, String cloudSiteId, String tenantId) throws MsoException { if (stack != null && !Strings.isNullOrEmpty(stack.getStackName()) && !Strings.isNullOrEmpty(stack.getId())) { - OpenStackRequest<Void> request = getHeatClient(cloudSiteId, tenantId).getStacks() - .deleteByName(stack.getStackName() + "/" + stack.getId()); - executeAndRecordOpenstackRequest(request); - Stack currentStack = pollStackForStatus(timeoutMinutes, stack, DELETE_IN_PROGRESS, cloudSiteId, tenantId); - postProcessStackDelete(currentStack); - return currentStack; + return deleteStack(stack, timeoutMinutes, cloudSiteId, tenantId); } else { throw new StackCreationException("Cannot Find Stack Name or Id"); } } + private Stack deleteStack(Stack stack, int timeoutMinutes, String cloudSiteId, String tenantId) + throws MsoException { + OpenStackRequest<Void> request = getHeatClient(cloudSiteId, tenantId).getStacks() + .deleteByName(stack.getStackName() + "/" + stack.getId()); + executeAndRecordOpenstackRequest(request); + Stack currentStack = pollStackForStatus(timeoutMinutes, stack, DELETE_IN_PROGRESS, cloudSiteId, tenantId, true); + if (currentStack == null) { + return currentStack; + } else { + postProcessStackDelete(currentStack); + } + return currentStack; + } + protected void postProcessStackDelete(Stack stack) throws MsoException { logger.info("Performing post processing on delete stack {}", stack); if (stack != null && !Strings.isNullOrEmpty(stack.getStackStatus())) { @@ -449,7 +463,6 @@ public class MsoHeatUtils extends MsoCommonUtils implements VduPlugin { // Query the Stack. // An MsoException will propagate transparently to the caller. Stack heatStack = queryHeatStack(heatClient, stackName); - if (heatStack == null) { // Stack does not exist. Return a StackInfo with status NOTFOUND return new StackInfo(stackName, HeatStatus.NOTFOUND); @@ -480,114 +493,16 @@ public class MsoHeatUtils extends MsoCommonUtils implements VduPlugin { * @throws MsoCloudSiteNotFound */ public StackInfo deleteStack(String tenantId, String cloudOwner, String cloudSiteId, String stackName, - boolean pollForCompletion) throws MsoException { - Heat heatClient = null; - try { - heatClient = getHeatClient(cloudSiteId, tenantId); - } catch (MsoTenantNotFound e) { - logger.debug("Tenant with id " + tenantId + "not found.", e); - return new StackInfo(stackName, HeatStatus.NOTFOUND); - } catch (MsoException me) { - logger.error("{} {} Openstack Exception on Token request: ", MessageEnum.RA_CONNECTION_EXCEPTION, - ErrorCode.AvailabilityError.getValue(), me); - me.addContext(DELETE_STACK); - throw me; - } - - // OK if stack not found, perform a query first - Stack heatStack = queryHeatStack(heatClient, stackName); - if (heatStack == null || DELETE_COMPLETE.equals(heatStack.getStackStatus())) { - // Not found. Return a StackInfo with status NOTFOUND - return new StackInfo(stackName, HeatStatus.NOTFOUND); - } - - // Use canonical name "<stack name>/<stack-id>" to delete. - // Otherwise, deletion by name returns a 302 redirect. - // NOTE: This is specific to the v1 Orchestration API. - String canonicalName = heatStack.getStackName() + "/" + heatStack.getId(); - - try { - OpenStackRequest<Void> request = null; - if (null != heatClient) { - request = heatClient.getStacks().deleteByName(canonicalName); - } else { - logger.debug("Heat Client is NULL"); - } - executeAndRecordOpenstackRequest(request); - } catch (OpenStackResponseException e) { - if (e.getStatus() == 404) { - // Not found. We are OK with this. Return a StackInfo with status NOTFOUND - return new StackInfo(stackName, HeatStatus.NOTFOUND); - } else { - // Convert the OpenStackResponseException to an MsoOpenstackException - throw heatExceptionToMsoException(e, DELETE_STACK); - } - } catch (OpenStackConnectException e) { - // Error connecting to Openstack instance. Convert to an MsoException - throw heatExceptionToMsoException(e, DELETE_STACK); - } catch (RuntimeException e) { - // Catch-all - throw runtimeExceptionToMsoException(e, DELETE_STACK); - } - - // Requery the stack for current status. - // It will probably still exist with "DELETE_IN_PROGRESS" status. - heatStack = queryHeatStack(heatClient, canonicalName); - statusHandler.updateStackStatus(heatStack); - if (pollForCompletion) { - int pollInterval = Integer - .parseInt(this.environment.getProperty(deletePollIntervalProp, "" + DELETE_POLL_INTERVAL_DEFAULT)); - int pollTimeout = Integer - .parseInt(this.environment.getProperty(deletePollTimeoutProp, "" + DELETE_POLL_INTERVAL_DEFAULT)); - statusHandler.updateStackStatus(heatStack); - // When querying by canonical name, Openstack returns DELETE_COMPLETE status - // instead of "404" (which would result from query by stack name). - while (heatStack != null && !DELETE_COMPLETE.equals(heatStack.getStackStatus())) { - logger.debug("Stack status: {}", heatStack.getStackStatus()); - - if ("DELETE_FAILED".equals(heatStack.getStackStatus())) { - // Throw a 'special case' of MsoOpenstackException to report the Heat status - String error = "Stack delete error (" + heatStack.getStackStatus() + "): " - + heatStack.getStackStatusReason(); - MsoOpenstackException me = new MsoOpenstackException(0, "", error); - me.addContext(DELETE_STACK); - - // Alarm this condition, stack deletion failed - - - throw me; - } - - if (pollTimeout <= 0) { - logger.error("{} Cloud site: {} Tenant: {} Stack: {} Stack status: {} {} Delete Stack Timeout", - MessageEnum.RA_DELETE_STACK_TIMEOUT, cloudSiteId, tenantId, stackName, - heatStack.getStackStatus(), ErrorCode.AvailabilityError.getValue()); - - // Throw a 'special case' of MsoOpenstackException to report the Heat status - MsoOpenstackException me = new MsoOpenstackException(0, "", "Stack Deletion Timeout"); - me.addContext(DELETE_STACK); - - // Alarm this condition, stack deletion failed - - - throw me; - } - - sleep(pollInterval * 1000L); - - pollTimeout -= pollInterval; - logger.debug("pollTimeout remaining: {}", pollTimeout); - - heatStack = queryHeatStack(heatClient, canonicalName); - } - - // The stack is gone when this point is reached + boolean pollForCompletion, int timeoutMinutes) throws MsoException { + Stack currentStack = queryHeatStack(stackName, cloudSiteId, tenantId); + if (currentStack == null || DELETE_COMPLETE.equals(currentStack.getStackStatus())) { return new StackInfo(stackName, HeatStatus.NOTFOUND); + } else { + currentStack = deleteStack(currentStack, timeoutMinutes, cloudSiteId, tenantId); + StackInfo stackInfo = new StackInfoMapper(currentStack).map(); + stackInfo.setName(stackName); + return stackInfo; } - // Return the current status (if not polling, the delete may still be in progress) - StackInfo stackInfo = new StackInfoMapper(heatStack).map(); - stackInfo.setName(stackName); - return stackInfo; } /** @@ -730,7 +645,7 @@ public class MsoHeatUtils extends MsoCommonUtils implements VduPlugin { if (!inputs.containsKey(key)) { Object obj = otherStackOutputs.get(key); if (obj instanceof String) { - inputs.put(key, (String) otherStackOutputs.get(key)); + inputs.put(key, otherStackOutputs.get(key)); } else if (obj instanceof JsonNode) { // This is a bit of mess - but I think it's the least impacting // let's convert it BACK to a string - then it will get converted back later @@ -929,7 +844,7 @@ public class MsoHeatUtils extends MsoCommonUtils implements VduPlugin { * Boolean if any of the conversions should fail, we will default to adding it to the inputs as a string - see if * Openstack can handle it. Also, will remove any params that are extra. Any aliases will be converted to their * appropriate name (anyone use this feature?) - * + * * @param inputs - the Map<String, String> of the inputs received on the request * @param template the HeatTemplate object - this is so we can also verify if the param is valid for this template * @return HashMap<String, Object> of the inputs, cleaned and converted @@ -1111,11 +1026,11 @@ public class MsoHeatUtils extends MsoCommonUtils implements VduPlugin { } try { - StackInfo stackInfo = - createStack(cloudSiteId, cloudOwner, tenantId, instanceName, vduModel, heatTemplate, inputs, true, // poll - // for - // completion - vduModel.getTimeoutMinutes(), heatEnvironment, nestedTemplates, files, rollbackOnFailure); + StackInfo stackInfo = createStack(cloudSiteId, cloudOwner, tenantId, instanceName, vduModel, heatTemplate, + inputs, true, // poll + // for + // completion + vduModel.getTimeoutMinutes(), heatEnvironment, nestedTemplates, files, rollbackOnFailure, false); // Populate a vduInstance from the StackInfo return stackInfoToVduInstance(stackInfo); @@ -1156,7 +1071,7 @@ public class MsoHeatUtils extends MsoCommonUtils implements VduPlugin { try { // Delete the Heat stack - StackInfo stackInfo = deleteStack(tenantId, cloudOwner, cloudSiteId, instanceId, true); + StackInfo stackInfo = deleteStack(tenantId, cloudOwner, cloudSiteId, instanceId, true, timeoutMinutes); // Populate a VduInstance based on the deleted Cloudify Deployment object VduInstance vduInstance = stackInfoToVduInstance(stackInfo); diff --git a/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MsoMulticloudUtils.java b/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MsoMulticloudUtils.java index 49ba336e3f..ca0180ae4b 100644 --- a/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MsoMulticloudUtils.java +++ b/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MsoMulticloudUtils.java @@ -22,10 +22,6 @@ package org.onap.so.openstack.utils; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.woorea.openstack.heat.model.CreateStackParam; -import com.woorea.openstack.heat.model.Stack; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; @@ -52,17 +48,20 @@ import org.onap.so.logger.MessageEnum; import org.onap.so.openstack.beans.HeatStatus; import org.onap.so.openstack.beans.StackInfo; import org.onap.so.openstack.exceptions.MsoAdapterException; -import org.onap.so.openstack.exceptions.MsoCloudSiteNotFound; import org.onap.so.openstack.exceptions.MsoException; import org.onap.so.openstack.exceptions.MsoOpenstackException; import org.onap.so.openstack.mappers.StackInfoMapper; -import org.onap.so.utils.TargetEntity; +import org.onap.logging.filter.base.ONAPComponents; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.ImmutableSet; +import com.woorea.openstack.heat.model.CreateStackParam; +import com.woorea.openstack.heat.model.Stack; @Component public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { @@ -136,7 +135,7 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { public StackInfo createStack(String cloudSiteId, String cloudOwner, String tenantId, String stackName, VduModelInfo vduModel, String heatTemplate, Map<String, ?> stackInputs, boolean pollForCompletion, int timeoutMinutes, String environment, Map<String, Object> files, Map<String, Object> heatFiles, - boolean backout) throws MsoException { + boolean backout, boolean failIfExists) throws MsoException { logger.trace("Started MsoMulticloudUtils.createStack"); @@ -299,7 +298,7 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { responseBody = getQueryBody((java.io.InputStream) response.getEntity()); if (responseBody != null) { if (logger.isDebugEnabled()) { - logger.debug("Multicloud Create Response Body: " + responseBody.toString()); + logger.debug("Multicloud Create Response Body: {}", responseBody); } Stack workloadStack = getWorkloadStack(responseBody.getWorkloadStatusReason()); if (workloadStack != null && !responseBody.getWorkloadStatus().equals("GET_FAILED") @@ -354,7 +353,7 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { } } if (workloadStack != null) - logger.debug("Multicloud getWorkloadStack() returning Stack Object: {} ", workloadStack.toString()); + logger.debug("Multicloud getWorkloadStack() returning Stack Object: {} ", workloadStack); return workloadStack; } @@ -457,8 +456,8 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { Response response = multicloudClient.post(multicloudRequest); if (response.getStatus() != Response.Status.ACCEPTED.getStatusCode()) { if (logger.isDebugEnabled()) - logger.debug( - "Multicloud AAI update request failed: " + response.getStatus() + response.getStatusInfo()); + logger.debug("Multicloud AAI update request failed: {} {}", response.getStatus(), + response.getStatusInfo()); return; } @@ -470,14 +469,14 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { Integer.parseInt(this.environment.getProperty(createPollIntervalProp, CREATE_POLL_INTERVAL_DEFAULT)); int pollTimeout = (timeoutMinutes * 60) + updatePollInterval; boolean updateTimedOut = false; - logger.debug("updatePollInterval=" + updatePollInterval + ", pollTimeout=" + pollTimeout); + logger.debug("updatePollInterval={}, pollTimeout={}", updatePollInterval, pollTimeout); StackInfo stackInfo = null; while (true) { try { stackInfo = queryStack(cloudSiteId, cloudOwner, tenantId, workloadId); if (logger.isDebugEnabled()) - logger.debug(stackInfo.getStatus() + " (" + workloadId + ")"); + logger.debug("{} ({})", stackInfo.getStatus(), workloadId); if (HeatStatus.UPDATING.equals(stackInfo.getStatus())) { if (pollTimeout <= 0) { @@ -494,7 +493,7 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { pollTimeout -= updatePollInterval; if (logger.isDebugEnabled()) - logger.debug("pollTimeout remaining: " + pollTimeout); + logger.debug("pollTimeout remaining: {}", pollTimeout); } else { break; } @@ -508,15 +507,14 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { if (updateTimedOut) { if (logger.isDebugEnabled()) logger.debug("Multicloud AAI update request failed: {} {}", response.getStatus(), - response.getStatusInfo().toString()); + response.getStatusInfo()); } else if (!HeatStatus.UPDATED.equals(stackInfo.getStatus())) { if (logger.isDebugEnabled()) logger.debug("Multicloud AAI update request failed: {} {}", response.getStatus(), - response.getStatusInfo().toString()); + response.getStatusInfo()); } else { if (logger.isDebugEnabled()) - logger.debug("Multicloud AAI update successful: {} {}", response.getStatus(), - response.getStatusInfo().toString()); + logger.debug("Multicloud AAI update successful: {} {}", response.getStatus(), response.getStatusInfo()); } } @@ -527,7 +525,7 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { private StackInfo getStackStatus(String cloudSiteId, String cloudOwner, String tenantId, String instanceId, boolean pollForCompletion, int timeoutMinutes, boolean backout) throws MsoException { - StackInfo stackInfo = new StackInfo(); + StackInfo stackInfo; // If client has requested a final response, poll for stack completion if (pollForCompletion) { @@ -543,12 +541,12 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { int deletePollTimeout = pollTimeout; boolean createTimedOut = false; StringBuilder stackErrorStatusReason = new StringBuilder(""); - logger.debug("createPollInterval=" + createPollInterval + ", pollTimeout=" + pollTimeout); + logger.debug("createPollInterval={}, pollTimeout={} ", createPollInterval, pollTimeout); while (true) { try { stackInfo = queryStack(cloudSiteId, cloudOwner, tenantId, instanceId); - logger.debug(stackInfo.getStatus() + " (" + instanceId + ")"); + logger.debug("{} ({})", stackInfo.getStatus(), instanceId); if (HeatStatus.BUILDING.equals(stackInfo.getStatus())) { // Stack creation is still running. @@ -567,7 +565,7 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { sleep(createPollInterval * 1000L); pollTimeout -= createPollInterval; - logger.debug("pollTimeout remaining: " + pollTimeout); + logger.debug("pollTimeout remaining: {}", pollTimeout); } else { // save off the status & reason msg before we attempt delete stackErrorStatusReason @@ -580,7 +578,7 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { if (!backout) { logger.warn(String.format("%s %s %s %s %d %s", MessageEnum.RA_CREATE_STACK_ERR.toString(), "Create Stack error, stack deletion suppressed", "", "", - ErrorCode.BusinessProcesssError.getValue(), + ErrorCode.BusinessProcessError.getValue(), "Exception in Create Stack, stack deletion suppressed")); } else { try { @@ -596,7 +594,7 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { while (!deleted) { try { StackInfo queryInfo = queryStack(cloudSiteId, cloudOwner, tenantId, instanceId); - logger.debug("Deleting " + instanceId + ", status: " + queryInfo.getStatus()); + logger.debug("Deleting {}, status: {}", instanceId, queryInfo.getStatus()); if (HeatStatus.DELETING.equals(queryInfo.getStatus())) { if (deletePollTimeout <= 0) { logger.error(String.format("%s %s %s %s %s %s %s %s %d %s", @@ -610,7 +608,7 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { deletePollTimeout -= deletePollInterval; } } else if (HeatStatus.NOTFOUND.equals(queryInfo.getStatus())) { - logger.debug("DELETE_COMPLETE for " + instanceId); + logger.debug("DELETE_COMPLETE for {}", instanceId); deleted = true; continue; } else { @@ -623,7 +621,7 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { logger.error(String.format("%s %s %s %s %d %s", MessageEnum.RA_CREATE_STACK_ERR.toString(), "Create Stack: Nested exception rolling back stack: " + e3, "", "", - ErrorCode.BusinessProcesssError.getValue(), + ErrorCode.BusinessProcessError.getValue(), "Create Stack: Nested exception rolling back stack on error on query")); } } @@ -631,7 +629,7 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { // Just log this one. We will report the original exception. logger.error(String.format("%s %s %s %s %d %s", MessageEnum.RA_CREATE_STACK_ERR.toString(), "Create Stack: Nested exception rolling back stack: " + e2, "", "", - ErrorCode.BusinessProcesssError.getValue(), + ErrorCode.BusinessProcessError.getValue(), "Create Stack: Nested exception rolling back stack")); } } @@ -646,13 +644,13 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { logger.error(String.format("%s %s %s %s %d %s", MessageEnum.RA_CREATE_STACK_ERR.toString(), "Create Stack error: Polling complete with non-success status: " + stackInfo.getStatus() + ", " + stackInfo.getStatusMessage(), - "", "", ErrorCode.BusinessProcesssError.getValue(), "Create Stack error")); + "", "", ErrorCode.BusinessProcessError.getValue(), "Create Stack error")); // Rollback the stack creation, since it is in an indeterminate state. if (!backout) { logger.warn(String.format("%s %s %s %s %d %s", MessageEnum.RA_CREATE_STACK_ERR.toString(), "Create Stack errored, stack deletion suppressed", "", "", - ErrorCode.BusinessProcesssError.getValue(), + ErrorCode.BusinessProcessError.getValue(), "Create Stack error, stack deletion suppressed")); } else { try { @@ -664,7 +662,7 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { while (!deleted) { try { StackInfo queryInfo = queryStack(cloudSiteId, cloudOwner, tenantId, instanceId); - logger.debug("Deleting " + instanceId + ", status: " + queryInfo.getStatus()); + logger.debug("Deleting {}, status: {}", instanceId, queryInfo.getStatus()); if (HeatStatus.DELETING.equals(queryInfo.getStatus())) { if (deletePollTimeout <= 0) { logger.error(String.format("%s %s %s %s %s %s %s %s %d %s", @@ -678,7 +676,7 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { deletePollTimeout -= deletePollInterval; } } else if (HeatStatus.NOTFOUND.equals(queryInfo.getStatus())) { - logger.debug("DELETE_COMPLETE for " + instanceId); + logger.debug("DELETE_COMPLETE for {}", instanceId); deleted = true; continue; } else { @@ -687,7 +685,7 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { logger.warn(String.format("%s %s %s %s %d %s", MessageEnum.RA_CREATE_STACK_ERR.toString(), "Create Stack errored, stack deletion FAILED", "", "", - ErrorCode.BusinessProcesssError.getValue(), + ErrorCode.BusinessProcessError.getValue(), "Create Stack error, stack deletion FAILED")); logger.debug("Stack deletion FAILED on a rollback of a create - " + instanceId + ", status=" + queryInfo.getStatus() + ", reason=" @@ -701,7 +699,7 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { logger.warn(String.format("%s %s %s %s %d %s", MessageEnum.RA_CREATE_STACK_ERR.toString(), "Create Stack errored, then stack deletion FAILED - exception thrown", "", "", - ErrorCode.BusinessProcesssError.getValue(), me2.getContextMessage())); + ErrorCode.BusinessProcessError.getValue(), me2.getContextMessage())); } } StringBuilder errorContextMessage; @@ -719,7 +717,7 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { // shouldn't happen - but handle logger.error(String.format("%s %s %s %s %d %s", MessageEnum.RA_CREATE_STACK_ERR.toString(), "Create Stack: Nested exception rolling back stack: " + e2, "", "", - ErrorCode.BusinessProcesssError.getValue(), + ErrorCode.BusinessProcessError.getValue(), "Exception in Create Stack: rolling back stack")); } } @@ -730,7 +728,7 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { } else { // Get initial status, since it will have been null after the create. stackInfo = queryStack(cloudSiteId, cloudOwner, tenantId, instanceId); - logger.debug("Multicloud stack query status is: " + stackInfo.getStatus()); + logger.debug("Multicloud stack query status is: {}", stackInfo.getStatus()); } return stackInfo; } @@ -769,7 +767,7 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { try { return new ObjectMapper().readerFor(MulticloudCreateResponse.class).readValue(body); } catch (Exception e) { - logger.debug("Exception retrieving multicloud vfModule POST response body " + e); + logger.debug("Exception retrieving multicloud vfModule POST response body ", e); } return null; } @@ -786,7 +784,7 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { try { return new ObjectMapper().readerFor(MulticloudQueryResponse.class).readValue(body); } catch (Exception e) { - logger.debug("Exception retrieving multicloud workload query response body " + e); + logger.debug("Exception retrieving multicloud workload query response body ", e); } return null; } @@ -823,19 +821,16 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { private RestClient getMulticloudClient(String endpoint, String tenantId) { HttpClient client = null; try { - client = httpClientFactory.newJsonClient(new URL(endpoint), TargetEntity.MULTICLOUD); + client = httpClientFactory.newJsonClient(new URL(endpoint), ONAPComponents.MULTICLOUD); if (tenantId != null && !tenantId.isEmpty()) { client.addAdditionalHeader("Project", tenantId); } } catch (MalformedURLException e) { - logger.debug( - String.format("Encountered malformed URL error getting multicloud rest client %s", e.getMessage())); + logger.debug("Encountered malformed URL error getting multicloud rest client ", e); } catch (IllegalArgumentException e) { - logger.debug( - String.format("Encountered illegal argument getting multicloud rest client %s", e.getMessage())); + logger.debug("Encountered illegal argument getting multicloud rest client ", e); } catch (UriBuilderException e) { - logger.debug( - String.format("Encountered URI builder error getting multicloud rest client %s", e.getMessage())); + logger.debug("Encountered URI builder error getting multicloud rest client ", e); } return client; } @@ -845,7 +840,7 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { return JSON_MAPPER.readTree(directives); } catch (Exception e) { logger.error(String.format("%s %s %s %s %d %s", MessageEnum.RA_CREATE_STACK_ERR.toString(), - "Create Stack: " + e, "", "", ErrorCode.BusinessProcesssError.getValue(), + "Create Stack: " + e, "", "", ErrorCode.BusinessProcessError.getValue(), "Exception in Create Stack: Invalid JSON format of directives" + directives)); MsoException me = new MsoAdapterException("Invalid JSON format of directives parameter: " + directives); me.addContext(CREATE_STACK); @@ -886,11 +881,11 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { } try { - StackInfo stackInfo = - createStack(cloudSiteId, cloudOwner, tenantId, instanceName, vduModel, heatTemplate, inputs, true, // poll - // for - // completion - vduModel.getTimeoutMinutes(), heatEnvironment, nestedTemplates, files, rollbackOnFailure); + StackInfo stackInfo = createStack(cloudSiteId, cloudOwner, tenantId, instanceName, vduModel, heatTemplate, + inputs, true, // poll + // for + // completion + vduModel.getTimeoutMinutes(), heatEnvironment, nestedTemplates, files, rollbackOnFailure, false); // Populate a vduInstance from the StackInfo return stackInfoToVduInstance(stackInfo); } catch (Exception e) { @@ -962,6 +957,7 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { /* * Convert the local DeploymentInfo object (Cloudify-specific) to a generic VduInstance object */ + @Override protected VduInstance stackInfoToVduInstance(StackInfo stackInfo) { VduInstance vduInstance = new VduInstance(); @@ -989,7 +985,7 @@ public class MsoMulticloudUtils extends MsoHeatUtils implements VduPlugin { // There are lots of HeatStatus values, so this is a bit long... HeatStatus heatStatus = stackInfo.getStatus(); String statusMessage = stackInfo.getStatusMessage(); - logger.debug("HeatStatus = " + heatStatus + " msg = " + statusMessage); + logger.debug("HeatStatus = {} msg = {}", heatStatus, statusMessage); if (logger.isDebugEnabled()) { logger.debug(String.format("Stack Status: %s", heatStatus.toString())); diff --git a/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MsoNeutronUtils.java b/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MsoNeutronUtils.java index 069c6c7c5b..44fc620b07 100644 --- a/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MsoNeutronUtils.java +++ b/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MsoNeutronUtils.java @@ -130,13 +130,13 @@ public class MsoNeutronUtils extends MsoCommonUtils { network.setAdminStateUp(true); if (type == NetworkType.PROVIDER) { - if (provider != null && vlans != null && vlans.size() > 0) { + if (provider != null && vlans != null && !vlans.isEmpty()) { network.setProviderPhysicalNetwork(provider); network.setProviderNetworkType("vlan"); network.setProviderSegmentationId(vlans.get(0)); } } else if (type == NetworkType.MULTI_PROVIDER) { - if (provider != null && vlans != null && vlans.size() > 0) { + if (provider != null && vlans != null && !vlans.isEmpty()) { List<Segment> segments = new ArrayList<>(vlans.size()); for (int vlan : vlans) { Segment segment = new Segment(); diff --git a/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MulticloudQueryResponse.java b/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MulticloudQueryResponse.java index ad37b39f30..c575304ade 100644 --- a/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MulticloudQueryResponse.java +++ b/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/MulticloudQueryResponse.java @@ -40,7 +40,7 @@ public class MulticloudQueryResponse implements Serializable { @JsonProperty("workload_status") private String workloadStatus; @JsonProperty("workload_status_reason") - private JsonNode workloadStatusReason; + private transient JsonNode workloadStatusReason; @JsonCreator public MulticloudQueryResponse(@JsonProperty("template_type") String templateType, diff --git a/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/StackCreationException.java b/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/StackCreationException.java index e3936e31f7..ab9c8a6dee 100644 --- a/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/StackCreationException.java +++ b/adapters/mso-adapter-utils/src/main/java/org/onap/so/openstack/utils/StackCreationException.java @@ -24,8 +24,22 @@ import org.onap.so.openstack.exceptions.MsoException; public class StackCreationException extends MsoException { + /** + * + */ + private static final long serialVersionUID = 6221508301589330950L; + + boolean stackCreationFailed = false; + boolean stackRollbackFailed = false; + public StackCreationException(String error) { super(error); } + public StackCreationException(String error, boolean stackCreationFailed, boolean stackRollbackFailed) { + super(error); + this.stackRollbackFailed = stackRollbackFailed; + this.stackCreationFailed = stackCreationFailed; + } + } diff --git a/adapters/mso-adapter-utils/src/test/java/org/onap/so/openstack/utils/MsoHeatUtilsITTest.java b/adapters/mso-adapter-utils/src/test/java/org/onap/so/openstack/utils/MsoHeatUtilsITTest.java index 7e783aa7a4..86b1413291 100644 --- a/adapters/mso-adapter-utils/src/test/java/org/onap/so/openstack/utils/MsoHeatUtilsITTest.java +++ b/adapters/mso-adapter-utils/src/test/java/org/onap/so/openstack/utils/MsoHeatUtilsITTest.java @@ -133,7 +133,7 @@ public class MsoHeatUtilsITTest extends BaseTest { @Test public void deleteVduTest() throws Exception { VduInstance expected = new VduInstance(); - expected.setVduInstanceId("instanceId"); + expected.setVduInstanceId("name/stackId"); expected.setVduInstanceName("instanceId"); VduStatus status = new VduStatus(); status.setState(VduStateType.DELETED); @@ -209,8 +209,8 @@ public class MsoHeatUtilsITTest extends BaseTest { StubOpenStack.mockOpenStackResponseAccess(wireMockServer, wireMockPort); StubOpenStack.mockOpenStackPostStack_200(wireMockServer, "OpenstackResponse_Stack_Created.json"); StubOpenStack.mockOpenStackGet(wireMockServer, "TEST-stack/stackId"); - StackInfo stackInfo = heatUtils.createStack(cloudSite.getId(), "CloudOwner", "tenantId", "TEST-stack", - "TEST-heat", new HashMap<>(), false, 1, "TEST-env", new HashMap<>(), new HashMap<>()); + StackInfo stackInfo = heatUtils.createStack(cloudSite.getId(), "CloudOwner", "tenantId", "TEST-stack", null, + "TEST-heat", new HashMap<>(), false, 1, "TEST-env", new HashMap<>(), new HashMap<>(), false, false); assertNotNull(stackInfo); } diff --git a/adapters/mso-adapter-utils/src/test/java/org/onap/so/openstack/utils/MsoHeatUtilsTest.java b/adapters/mso-adapter-utils/src/test/java/org/onap/so/openstack/utils/MsoHeatUtilsTest.java index e68364eab8..92cf96ed16 100644 --- a/adapters/mso-adapter-utils/src/test/java/org/onap/so/openstack/utils/MsoHeatUtilsTest.java +++ b/adapters/mso-adapter-utils/src/test/java/org/onap/so/openstack/utils/MsoHeatUtilsTest.java @@ -124,7 +124,7 @@ public class MsoHeatUtilsTest extends MsoHeatUtils { latestStack.setStackStatusReason("Stack Finished"); doReturn(latestStack).when(heatUtils).queryHeatStack(isA(Heat.class), eq("stackName/id")); doReturn(heatClient).when(heatUtils).getHeatClient(cloudSiteId, tenantId); - Stack actual = heatUtils.pollStackForStatus(1, stack, "CREATE_IN_PROGRESS", cloudSiteId, tenantId); + Stack actual = heatUtils.pollStackForStatus(1, stack, "CREATE_IN_PROGRESS", cloudSiteId, tenantId, false); Mockito.verify(stackStatusHandler, times(1)).updateStackStatus(latestStack); Mockito.verify(heatUtils, times(1)).queryHeatStack(isA(Heat.class), eq("stackName/id")); assertEquals(true, actual != null); @@ -141,7 +141,7 @@ public class MsoHeatUtilsTest extends MsoHeatUtils { doNothing().when(stackStatusHandler).updateStackStatus(stack); doReturn(stack).when(heatUtils).queryHeatStack(isA(Heat.class), eq("stackName/id")); doReturn(heatClient).when(heatUtils).getHeatClient(cloudSiteId, tenantId); - Stack actual = heatUtils.pollStackForStatus(1, stack, "CREATE_IN_PROGRESS", cloudSiteId, tenantId); + Stack actual = heatUtils.pollStackForStatus(1, stack, "CREATE_IN_PROGRESS", cloudSiteId, tenantId, false); Mockito.verify(stackStatusHandler, times(1)).updateStackStatus(stack); Mockito.verify(heatUtils, times(1)).queryHeatStack(isA(Heat.class), eq("stackName/id")); assertEquals(true, actual != null); @@ -259,11 +259,12 @@ public class MsoHeatUtilsTest extends MsoHeatUtils { doReturn(stackResource).when(heatClient).getStacks(); doReturn(mockDeleteStack).when(stackResource).deleteByName("stackName/id"); doReturn(deletedStack).when(heatUtils).pollStackForStatus(120, stack, "DELETE_IN_PROGRESS", cloudSiteId, - tenantId); + tenantId, true); heatUtils.handleUnknownCreateStackFailure(stack, 120, cloudSiteId, tenantId); Mockito.verify(heatUtils, times(1)).executeAndRecordOpenstackRequest(mockDeleteStack); - Mockito.verify(heatUtils, times(1)).pollStackForStatus(120, stack, "DELETE_IN_PROGRESS", cloudSiteId, tenantId); + Mockito.verify(heatUtils, times(1)).pollStackForStatus(120, stack, "DELETE_IN_PROGRESS", cloudSiteId, tenantId, + true); Mockito.verify(heatUtils, times(1)).postProcessStackDelete(deletedStack); } @@ -357,12 +358,13 @@ public class MsoHeatUtilsTest extends MsoHeatUtils { createStackParam.setStackName("stackName"); doReturn(createdStack).when(heatUtils).pollStackForStatus(120, stack, "CREATE_IN_PROGRESS", cloudSiteId, - tenantId); + tenantId, false); doReturn(createdStack).when(heatUtils).postProcessStackCreate(createdStack, true, 120, true, cloudSiteId, tenantId, createStackParam); heatUtils.processCreateStack(cloudSiteId, tenantId, 120, true, stack, createStackParam, true); - Mockito.verify(heatUtils, times(1)).pollStackForStatus(120, stack, "CREATE_IN_PROGRESS", cloudSiteId, tenantId); + Mockito.verify(heatUtils, times(1)).pollStackForStatus(120, stack, "CREATE_IN_PROGRESS", cloudSiteId, tenantId, + false); Mockito.verify(heatUtils, times(1)).postProcessStackCreate(createdStack, true, 120, true, cloudSiteId, tenantId, createStackParam); } @@ -387,11 +389,12 @@ public class MsoHeatUtilsTest extends MsoHeatUtils { createStackParam.setStackName("stackName"); doThrow(new StackCreationException("Error")).when(heatUtils).pollStackForStatus(120, stack, - "CREATE_IN_PROGRESS", cloudSiteId, tenantId); + "CREATE_IN_PROGRESS", cloudSiteId, tenantId, false); exceptionRule.expect(MsoException.class); exceptionRule.expectMessage("Error"); heatUtils.processCreateStack(cloudSiteId, tenantId, 120, true, stack, createStackParam, true); - Mockito.verify(heatUtils, times(1)).pollStackForStatus(120, stack, "CREATE_IN_PROGRESS", cloudSiteId, tenantId); + Mockito.verify(heatUtils, times(1)).pollStackForStatus(120, stack, "CREATE_IN_PROGRESS", cloudSiteId, tenantId, + false); Mockito.verify(heatUtils, times(1)).postProcessStackCreate(stack, true, 120, true, cloudSiteId, tenantId, createStackParam); } @@ -527,12 +530,13 @@ public class MsoHeatUtilsTest extends MsoHeatUtils { createStackParam.setStackName("stackName"); doThrow(new StackCreationException("Error")).when(heatUtils).pollStackForStatus(120, stack, - "CREATE_IN_PROGRESS", cloudSiteId, tenantId); + "CREATE_IN_PROGRESS", cloudSiteId, tenantId, false); exceptionRule.expect(MsoException.class); exceptionRule.expectMessage("Error"); heatUtils.processCreateStack(cloudSiteId, tenantId, 120, false, stack, createStackParam, true); - Mockito.verify(heatUtils, times(1)).pollStackForStatus(120, stack, "CREATE_IN_PROGRESS", cloudSiteId, tenantId); + Mockito.verify(heatUtils, times(1)).pollStackForStatus(120, stack, "CREATE_IN_PROGRESS", cloudSiteId, tenantId, + false); Mockito.verify(heatUtils, times(0)).handleUnknownCreateStackFailure(stack, 120, cloudSiteId, tenantId); } diff --git a/adapters/mso-adapter-utils/src/test/java/org/onap/so/openstack/utils/MsoMulticloudUtilsTest.java b/adapters/mso-adapter-utils/src/test/java/org/onap/so/openstack/utils/MsoMulticloudUtilsTest.java index 995db522e9..44a9bc3e10 100644 --- a/adapters/mso-adapter-utils/src/test/java/org/onap/so/openstack/utils/MsoMulticloudUtilsTest.java +++ b/adapters/mso-adapter-utils/src/test/java/org/onap/so/openstack/utils/MsoMulticloudUtilsTest.java @@ -24,8 +24,8 @@ import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; import static com.github.tomakehurst.wiremock.client.WireMock.delete; import static com.github.tomakehurst.wiremock.client.WireMock.get; import static com.github.tomakehurst.wiremock.client.WireMock.post; -import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -95,9 +95,9 @@ public class MsoMulticloudUtilsTest extends BaseTest { wireMockServer.stubFor(get(urlEqualTo(MULTICLOUD_GET_PATH)).inScenario("CREATE").whenScenarioStateIs("UPDATING") .willReturn(aResponse().withHeader("Content-Type", "application/json") .withBodyFile("MulticloudGetUpdateResponse.json").withStatus(HttpStatus.SC_OK))); - StackInfo result = - multicloudUtils.createStack("MTN14", "CloudOwner", "TEST-tenant", "TEST-stack", new VduModelInfo(), - "TEST-heat", new HashMap<>(), true, 200, "TEST-env", new HashMap<>(), new HashMap<>(), false); + StackInfo result = multicloudUtils.createStack("MTN14", "CloudOwner", "TEST-tenant", "TEST-stack", + new VduModelInfo(), "TEST-heat", new HashMap<>(), true, 200, "TEST-env", new HashMap<>(), + new HashMap<>(), false, false); wireMockServer.resetScenarios(); assertNotNull(result); assertEquals("TEST-stack", result.getName()); @@ -155,7 +155,8 @@ public class MsoMulticloudUtilsTest extends BaseTest { cloudSite.setIdentityService(new CloudIdentity()); when(cloudConfigMock.getCloudSite("MTN13")).thenReturn(Optional.of(cloudSite)); multicloudUtilsMock.createStack("MNT14", "CloudOwner", "TEST-tenant", "TEST-stack", new VduModelInfo(), - "TEST-heat", new HashMap<>(), false, 200, "TEST-env", new HashMap<>(), new HashMap<>(), false); + "TEST-heat", new HashMap<>(), false, 200, "TEST-env", new HashMap<>(), new HashMap<>(), false, + false); } catch (MsoException e) { assertEquals("0 : Multicloud client could not be initialized", e.toString()); return; @@ -169,7 +170,8 @@ public class MsoMulticloudUtilsTest extends BaseTest { wireMockServer.stubFor(post(urlPathEqualTo(MULTICLOUD_CREATE_PATH)).willReturn( aResponse().withHeader("Content-Type", "application/json").withStatus(HttpStatus.SC_BAD_REQUEST))); multicloudUtils.createStack("MTN14", "CloudOwner", "TEST-tenant", "TEST-stack", new VduModelInfo(), - "TEST-heat", new HashMap<>(), false, 200, "TEST-env", new HashMap<>(), new HashMap<>(), false); + "TEST-heat", new HashMap<>(), false, 200, "TEST-env", new HashMap<>(), new HashMap<>(), false, + false); } catch (MsoException e) { assertEquals("0 : Bad Request", e.toString()); return; @@ -181,9 +183,9 @@ public class MsoMulticloudUtilsTest extends BaseTest { public void createStackEmptyResponseEntity() throws MsoException { wireMockServer.stubFor(post(urlPathEqualTo(MULTICLOUD_CREATE_PATH)).willReturn( aResponse().withHeader("Content-Type", "application/json").withStatus(HttpStatus.SC_CREATED))); - StackInfo result = - multicloudUtils.createStack("MTN14", "CloudOwner", "TEST-tenant", "TEST-stack", new VduModelInfo(), - "TEST-heat", new HashMap<>(), false, 200, "TEST-env", new HashMap<>(), new HashMap<>(), false); + StackInfo result = multicloudUtils.createStack("MTN14", "CloudOwner", "TEST-tenant", "TEST-stack", + new VduModelInfo(), "TEST-heat", new HashMap<>(), false, 200, "TEST-env", new HashMap<>(), + new HashMap<>(), false, false); assertNotNull(result); assertEquals("TEST-stack/", result.getName()); } diff --git a/adapters/mso-adapter-utils/src/test/resources/__files/OpenstackResponse_Stack_DeleteComplete.json b/adapters/mso-adapter-utils/src/test/resources/__files/OpenstackResponse_Stack_DeleteComplete.json index a26a551f7d..ea05b64e08 100644 --- a/adapters/mso-adapter-utils/src/test/resources/__files/OpenstackResponse_Stack_DeleteComplete.json +++ b/adapters/mso-adapter-utils/src/test/resources/__files/OpenstackResponse_Stack_DeleteComplete.json @@ -3,7 +3,7 @@ "description": null, "links": null, "stack_status_reason": null, - "stack_name": null, + "stack_name": "name", "updated_time": null, "creation_time": null, "stack_status": "DELETE_COMPLETE", diff --git a/adapters/mso-adapters-rest-interface/src/main/java/org/onap/so/adapters/vnfrest/DeleteVfModuleRequest.java b/adapters/mso-adapters-rest-interface/src/main/java/org/onap/so/adapters/vnfrest/DeleteVfModuleRequest.java index 6a979d754b..7e10bb3801 100644 --- a/adapters/mso-adapters-rest-interface/src/main/java/org/onap/so/adapters/vnfrest/DeleteVfModuleRequest.java +++ b/adapters/mso-adapters-rest-interface/src/main/java/org/onap/so/adapters/vnfrest/DeleteVfModuleRequest.java @@ -7,9 +7,9 @@ * 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. @@ -30,7 +30,7 @@ import com.fasterxml.jackson.annotation.JsonRootName; @XmlRootElement(name = "deleteVfModuleRequest") public class DeleteVfModuleRequest extends VfRequestCommon implements Serializable { /** - * + * */ private static final long serialVersionUID = -8504083539107392561L; private String cloudSiteId; @@ -39,6 +39,7 @@ public class DeleteVfModuleRequest extends VfRequestCommon implements Serializab private String vnfId; private String vfModuleId; private String vfModuleStackId; + private String modelCustomizationUuid; private MsoRequest msoRequest = new MsoRequest(); @@ -94,6 +95,14 @@ public class DeleteVfModuleRequest extends VfRequestCommon implements Serializab this.vfModuleStackId = vfModuleStackId; } + public String getModelCustomizationUuid() { + return modelCustomizationUuid; + } + + public void setModelCustomizationUuid(String modelCustomizationUuid) { + this.modelCustomizationUuid = modelCustomizationUuid; + } + public MsoRequest getMsoRequest() { return msoRequest; } diff --git a/adapters/mso-catalog-db-adapter/pom.xml b/adapters/mso-catalog-db-adapter/pom.xml index 9ec98cf96c..9745935925 100644 --- a/adapters/mso-catalog-db-adapter/pom.xml +++ b/adapters/mso-catalog-db-adapter/pom.xml @@ -14,6 +14,7 @@ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> + <swagger.version>2.0.8</swagger.version> </properties> <build> <plugins> @@ -84,40 +85,6 @@ </plugins> <pluginManagement> <plugins> - <!--This plugin's configuration is used to store Eclipse m2e settings - only. It has no influence on the Maven build itself. --> - <plugin> - <groupId>org.eclipse.m2e</groupId> - <artifactId>lifecycle-mapping</artifactId> - <version>1.0.0</version> - <configuration> - <lifecycleMappingMetadata> - <pluginExecutions> - <pluginExecution> - <pluginExecutionFilter> - <groupId> - org.jvnet.jax-ws-commons - </groupId> - <artifactId> - jaxws-maven-plugin - </artifactId> - <versionRange> - [2.3,) - </versionRange> - <goals> - <goal>wsgen</goal> - </goals> - </pluginExecutionFilter> - <action> - <ignore> - </ignore> - </action> - </pluginExecution> - </pluginExecutions> - </lifecycleMappingMetadata> - </configuration> - </plugin> - <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> @@ -143,10 +110,22 @@ <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> + + <dependency> + <groupId>com.fasterxml.jackson.dataformat</groupId> + <artifactId>jackson-dataformat-yaml</artifactId> + <version>2.9.9</version> + </dependency> + + <dependency> + <groupId>io.swagger.core.v3</groupId> + <artifactId>swagger-annotations</artifactId> + <version>${swagger.version}</version> + </dependency> <dependency> - <groupId>io.swagger</groupId> - <artifactId>swagger-jersey2-jaxrs</artifactId> - <version>1.5.16</version> + <groupId>io.swagger.core.v3</groupId> + <artifactId>swagger-jaxrs2</artifactId> + <version>2.0.6</version> </dependency> <dependency> <groupId>org.mariadb.jdbc</groupId> diff --git a/adapters/mso-catalog-db-adapter/src/main/java/db/migration/R__CloudConfigMigration.java b/adapters/mso-catalog-db-adapter/src/main/java/db/migration/R__CloudConfigMigration.java index 354c3d07f7..691ae60afd 100644 --- a/adapters/mso-catalog-db-adapter/src/main/java/db/migration/R__CloudConfigMigration.java +++ b/adapters/mso-catalog-db-adapter/src/main/java/db/migration/R__CloudConfigMigration.java @@ -128,8 +128,8 @@ public class R__CloudConfigMigration implements JdbcMigration, MigrationInfoProv private void migrateCloudIdentity(Collection<CloudIdentity> entities, Connection connection) throws SQLException { logger.debug("Starting migration for CloudConfig-->IdentityService"); String insert = - "INSERT INTO `identity_services` (`ID`, `IDENTITY_URL`, `MSO_ID`, `MSO_PASS`, `ADMIN_TENANT`, `MEMBER_ROLE`, `TENANT_METADATA`, `IDENTITY_SERVER_TYPE`, `IDENTITY_AUTHENTICATION_TYPE`, `LAST_UPDATED_BY`) " - + "VALUES (?,?,?,?,?,?,?,?,?,?);"; + "INSERT INTO `identity_services` (`ID`, `IDENTITY_URL`, `MSO_ID`, `MSO_PASS`, `ADMIN_TENANT`, `MEMBER_ROLE`, `TENANT_METADATA`, `IDENTITY_SERVER_TYPE`, `IDENTITY_AUTHENTICATION_TYPE`, `LAST_UPDATED_BY`, `PROJECT_DOMAIN_NAME`, `USER_DOMAIN_NAME`) " + + "VALUES (?,?,?,?,?,?,?,?,?,?,?,?);"; try (Statement stmt = connection.createStatement(); PreparedStatement ps = connection.prepareStatement(insert)) { @@ -157,6 +157,8 @@ public class R__CloudConfigMigration implements JdbcMigration, MigrationInfoProv ? cloudIdentity.getIdentityAuthenticationType().name() : null); ps.setString(10, FLYWAY); + ps.setString(11, cloudIdentity.getProjectDomainName()); + ps.setString(12, cloudIdentity.getUserDomainName()); ps.executeUpdate(); } } diff --git a/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/CatalogDBApplication.java b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/CatalogDBApplication.java index aa19aed515..1ad4238ade 100644 --- a/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/CatalogDBApplication.java +++ b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/CatalogDBApplication.java @@ -28,7 +28,8 @@ import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication(scanBasePackages = {"org.onap.so.adapters.catalogdb", "org.onap.so.db.catalog.client", "org.onap.so.logging.jaxrs.filter", "org.onap.so.logging.spring.interceptor", "org.onap.so.client", - "org.onap.so.configuration", "org.onap.so.db"}) + "org.onap.so.configuration", "org.onap.so.db", "org.onap.logging.filter", + "org.onap.so.logger, org.onap.so.security"}) @EnableJpaRepositories("org.onap.so.db.catalog.data.repository") @EntityScan("org.onap.so.db.catalog.beans") @EnableScheduling diff --git a/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/JerseyConfiguration.java b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/JerseyConfiguration.java index 79aad1ad1a..359c8cd46e 100644 --- a/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/JerseyConfiguration.java +++ b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/JerseyConfiguration.java @@ -20,16 +20,25 @@ package org.onap.so.adapters.catalogdb; +import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.annotation.PostConstruct; import javax.ws.rs.ApplicationPath; import org.glassfish.jersey.server.ResourceConfig; +import org.onap.logging.filter.base.Constants; +import org.onap.logging.filter.base.ONAPComponents; import org.onap.so.adapters.catalogdb.rest.CatalogDbAdapterRest; import org.onap.so.adapters.catalogdb.rest.ServiceRestImpl; -import org.onap.so.logging.jaxrs.filter.JaxRsFilterLogging; +import org.onap.so.adapters.catalogdb.rest.VnfRestImpl; +import org.onap.so.logging.jaxrs.filter.SOAuditLogContainerFilter; import org.springframework.context.annotation.Configuration; -import io.swagger.jaxrs.config.BeanConfig; -import io.swagger.jaxrs.listing.ApiListingResource; -import io.swagger.jaxrs.listing.SwaggerSerializers; +import io.swagger.v3.jaxrs2.integration.JaxrsOpenApiContextBuilder; +import io.swagger.v3.jaxrs2.integration.resources.AcceptHeaderOpenApiResource; +import io.swagger.v3.jaxrs2.integration.resources.OpenApiResource; +import io.swagger.v3.oas.integration.OpenApiConfigurationException; +import io.swagger.v3.oas.integration.SwaggerConfiguration; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; @Configuration @ApplicationPath("/ecomp/mso/catalog") @@ -37,18 +46,27 @@ public class JerseyConfiguration extends ResourceConfig { @PostConstruct public void setUp() { + System.setProperty(Constants.Property.PARTNER_NAME, ONAPComponents.CATALOG_DB.toString()); register(CatalogDbAdapterRest.class); - register(ApiListingResource.class); - register(SwaggerSerializers.class); - register(JaxRsFilterLogging.class); + register(SOAuditLogContainerFilter.class); + register(OpenApiResource.class); + register(AcceptHeaderOpenApiResource.class); register(ServiceRestImpl.class); - BeanConfig beanConfig = new BeanConfig(); - beanConfig.setVersion("1.0.2"); - beanConfig.setSchemes(new String[] {"https"}); - beanConfig.setBasePath("/ecomp/mso/catalog"); - beanConfig.setResourcePackage("org.onap.so.adapters.catalogdb.rest"); - beanConfig.setPrettyPrint(true); - beanConfig.setScan(true); + register(VnfRestImpl.class); + + OpenAPI oas = new OpenAPI(); + Info info = new Info(); + info.title("Swagger catalog-db-adapter bootstrap code"); + info.setVersion("1.0.2"); + + SwaggerConfiguration oasConfig = new SwaggerConfiguration().openAPI(oas).prettyPrint(true) + .resourcePackages(Stream.of("org.onap.so.adapters.catalogdb.rest").collect(Collectors.toSet())); + + try { + new JaxrsOpenApiContextBuilder().application(this).openApiConfiguration(oasConfig).buildContext(true); + } catch (OpenApiConfigurationException e) { + throw new RuntimeException(e.getMessage(), e); + } } } diff --git a/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/WebMvcConfig.java b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/WebMvcConfig.java index 4dabb58f7d..cd3b2a377b 100644 --- a/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/WebMvcConfig.java +++ b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/WebMvcConfig.java @@ -21,22 +21,32 @@ package org.onap.so.adapters.catalogdb; -import org.onap.so.logging.spring.interceptor.LoggingInterceptor; +import org.onap.logging.filter.spring.LoggingInterceptor; +import org.onap.logging.filter.spring.StatusLoggingInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.handler.MappedInterceptor; @Configuration +@ComponentScan(basePackages = {"org.onap.logging.filter"}) public class WebMvcConfig extends WebMvcConfigurerAdapter { @Autowired - LoggingInterceptor loggingInterceptor; + private LoggingInterceptor loggingInterceptor; + + @Autowired + private StatusLoggingInterceptor statusLoggingInterceptor; @Bean public MappedInterceptor mappedLoggingInterceptor() { return new MappedInterceptor(new String[] {"/**"}, loggingInterceptor); } + @Bean + public MappedInterceptor mappedStatusLoggingInterceptor() { + return new MappedInterceptor(new String[] {"/**"}, statusLoggingInterceptor); + } } diff --git a/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/WebSecurityConfigImpl.java b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/WebSecurityConfigImpl.java deleted file mode 100644 index 1d58975e6b..0000000000 --- a/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/WebSecurityConfigImpl.java +++ /dev/null @@ -1,50 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * ONAP - SO - * ================================================================================ - * Copyright (C) 2017 - 2018 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Modifications Copyright (C) 2018 IBM. - * ================================================================================ - * 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 org.onap.so.adapters.catalogdb; - -import org.onap.so.security.MSOSpringFirewall; -import org.onap.so.security.WebSecurityConfig; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.builders.WebSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.web.firewall.StrictHttpFirewall; -import org.springframework.util.StringUtils; - -@EnableWebSecurity -public class WebSecurityConfigImpl extends WebSecurityConfig { - - @Override - protected void configure(HttpSecurity http) throws Exception { - http.csrf().disable().authorizeRequests().antMatchers("/manage/health", "/manage/info").permitAll() - .antMatchers("/**").hasAnyRole(StringUtils.collectionToDelimitedString(getRoles(), ",")).and() - .httpBasic(); - } - - @Override - public void configure(WebSecurity web) throws Exception { - super.configure(web); - StrictHttpFirewall firewall = new MSOSpringFirewall(); - web.httpFirewall(firewall); - } - -} diff --git a/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/catalogrest/CatalogQuery.java b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/catalogrest/CatalogQuery.java index edec48dc95..a98778bf5d 100644 --- a/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/catalogrest/CatalogQuery.java +++ b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/catalogrest/CatalogQuery.java @@ -21,6 +21,7 @@ package org.onap.so.adapters.catalogdb.catalogrest; +import java.io.IOException; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -95,4 +96,17 @@ public abstract class CatalogQuery { return smartToJSON(); } + + protected boolean isJSONValid(String jsonInString) { + try { + if (jsonInString == null) { + return false; + } + ObjectMapper mapper = new ObjectMapper(); + mapper.readValue(jsonInString, String.class); + return true; + } catch (IOException e) { + return false; + } + } } diff --git a/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/catalogrest/QueryAllottedResourceCustomization.java b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/catalogrest/QueryAllottedResourceCustomization.java index c1acc319f7..afcb2d5761 100644 --- a/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/catalogrest/QueryAllottedResourceCustomization.java +++ b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/catalogrest/QueryAllottedResourceCustomization.java @@ -123,7 +123,10 @@ public class QueryAllottedResourceCustomization extends CatalogQuery { put(valueMap, "PROVIDING_SERVICE_MODEL_INVARIANT_UUID", o.getProvidingServiceModelInvariantUUID()); put(valueMap, "PROVIDING_SERVICE_MODEL_UUID", o.getProvidingServiceModelUUID()); put(valueMap, "PROVIDING_SERVICE_MODEL_NAME", o.getProvidingServiceModelName()); - put(valueMap, "RESOURCE_INPUT", o.getResourceInput()); + + if (isJSONValid(o.getResourceInput())) { + put(valueMap, "RESOURCE_INPUT", o.getResourceInput()); + } sb.append(sep).append(this.setTemplate(TEMPLATE, valueMap)); sep = ",\n"; diff --git a/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/catalogrest/QueryServiceNetworks.java b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/catalogrest/QueryServiceNetworks.java index 5573b23a8d..129718241c 100644 --- a/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/catalogrest/QueryServiceNetworks.java +++ b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/catalogrest/QueryServiceNetworks.java @@ -116,7 +116,10 @@ public class QueryServiceNetworks extends CatalogQuery { put(valueMap, "NETWORK_ROLE", o.getNetworkRole()); put(valueMap, "NETWORK_SCOPE", o.getNetworkScope()); put(valueMap, "NETWORK_TECHNOLOGY", o.getNetworkTechnology()); - put(valueMap, "RESOURCE_INPUT", o.getResourceInput()); + + if (isJSONValid(o.getResourceInput())) { + put(valueMap, "RESOURCE_INPUT", o.getResourceInput()); + } sb.append(sep).append(this.setTemplate(TEMPLATE, valueMap)); sep = ",\n"; diff --git a/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/catalogrest/QueryServiceVnfs.java b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/catalogrest/QueryServiceVnfs.java index 0b8de60a81..d6e7415a77 100644 --- a/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/catalogrest/QueryServiceVnfs.java +++ b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/catalogrest/QueryServiceVnfs.java @@ -23,6 +23,7 @@ package org.onap.so.adapters.catalogdb.catalogrest; /* should be called QueryVnfResource.java */ +import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -32,6 +33,7 @@ import org.onap.so.db.catalog.beans.VnfResourceCustomization; import org.onap.so.db.catalog.beans.VnfcInstanceGroupCustomization; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.fasterxml.jackson.databind.ObjectMapper; @XmlRootElement(name = "serviceVnfs") public class QueryServiceVnfs extends CatalogQuery { @@ -120,7 +122,9 @@ public class QueryServiceVnfs extends CatalogQuery { put(valueMap, "NF_NAMING_CODE", o.getNfNamingCode()); put(valueMap, "VNFC_INSTANCE_GROUP_ORDER", o.getVnfcInstanceGroupOrder()); put(valueMap, "MULTI_STEP_DESIGN", o.getMultiStageDesign()); - put(valueMap, "RESOURCE_INPUT", o.getResourceInput()); + if (isJSONValid(o.getResourceInput())) { + put(valueMap, "RESOURCE_INPUT", o.getResourceInput()); + } String subitem = new QueryVfModule(vrNull ? null : o.getVfModuleCustomizations()).JSON2(true, true); valueMap.put("_VFMODULES_", subitem.replaceAll("(?m)^", "\t\t")); @@ -142,4 +146,5 @@ public class QueryServiceVnfs extends CatalogQuery { sb.append("}"); return sb.toString(); } + } diff --git a/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/catalogrest/QueryVnfcs.java b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/catalogrest/QueryVnfcs.java index dc73fe904d..24c07d6d3e 100644 --- a/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/catalogrest/QueryVnfcs.java +++ b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/catalogrest/QueryVnfcs.java @@ -20,12 +20,12 @@ package org.onap.so.adapters.catalogdb.catalogrest; -import org.onap.so.db.catalog.beans.VnfcCustomization; -import javax.xml.bind.annotation.XmlRootElement; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import javax.xml.bind.annotation.XmlRootElement; +import org.onap.so.db.catalog.beans.VnfcCustomization; @XmlRootElement(name = "vnfcs") public class QueryVnfcs extends CatalogQuery { @@ -105,8 +105,10 @@ public class QueryVnfcs extends CatalogQuery { put(valueMap, "MODEL_INVARIANT_ID", o.getModelInvariantUUID()); put(valueMap, "MODEL_VERSION", o.getModelVersion()); put(valueMap, "MODEL_CUSTOMIZATION_UUID", o.getModelCustomizationUUID()); - put(valueMap, "RESOURCE_INPUT", o.getResourceInput()); + if (isJSONValid(o.getResourceInput())) { + put(valueMap, "RESOURCE_INPUT", o.getResourceInput()); + } sb.append(sep).append(this.setTemplate(TEMPLATE, valueMap)); sep = ",\n"; } diff --git a/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/rest/CatalogEntityNotFoundException.java b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/rest/CatalogEntityNotFoundException.java new file mode 100644 index 0000000000..f8a7ba6da4 --- /dev/null +++ b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/rest/CatalogEntityNotFoundException.java @@ -0,0 +1,14 @@ +package org.onap.so.adapters.catalogdb.rest; + +public class CatalogEntityNotFoundException extends RuntimeException { + + /** + * + */ + private static final long serialVersionUID = -300157844846680791L; + + public CatalogEntityNotFoundException(String errorMessage) { + super(errorMessage); + } + +} diff --git a/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/rest/CatalogEntityNotFoundExceptionMapper.java b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/rest/CatalogEntityNotFoundExceptionMapper.java new file mode 100644 index 0000000000..c42eaabea7 --- /dev/null +++ b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/rest/CatalogEntityNotFoundExceptionMapper.java @@ -0,0 +1,38 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 - 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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 org.onap.so.adapters.catalogdb.rest; + +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Provider +public class CatalogEntityNotFoundExceptionMapper implements ExceptionMapper<CatalogEntityNotFoundException> { + + private static final Logger logger = LoggerFactory.getLogger(CatalogEntityNotFoundExceptionMapper.class); + + @Override + public Response toResponse(CatalogEntityNotFoundException e) { + return Response.status(Response.Status.NOT_FOUND).entity(e).build(); + } +} diff --git a/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/rest/ServiceMapper.java b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/rest/ServiceMapper.java index dd18767762..e74663dbba 100644 --- a/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/rest/ServiceMapper.java +++ b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/rest/ServiceMapper.java @@ -22,9 +22,11 @@ package org.onap.so.adapters.catalogdb.rest; import java.util.ArrayList; import java.util.List; +import org.onap.so.db.catalog.beans.CvnfcCustomization; import org.onap.so.db.catalog.beans.HeatEnvironment; import org.onap.so.db.catalog.beans.VfModuleCustomization; import org.onap.so.db.catalog.beans.VnfResourceCustomization; +import org.onap.so.rest.catalog.beans.Cvnfc; import org.onap.so.rest.catalog.beans.Service; import org.onap.so.rest.catalog.beans.VfModule; import org.onap.so.rest.catalog.beans.Vnf; @@ -39,16 +41,23 @@ public class ServiceMapper { public Service mapService(org.onap.so.db.catalog.beans.Service service, int depth) { Service restService = new Service(); - restService.setCategory(service.getCategory()); + if (service.getCategory() != null) { + restService.setCategory(service.getCategory()); + } restService.setCreated(service.getCreated()); restService.setDescription(service.getDescription()); - restService.setDistrobutionStatus(service.getDistrobutionStatus()); + + if (service.getDistrobutionStatus() != null) { + restService.setDistrobutionStatus(service.getDistrobutionStatus()); + } restService.setEnvironmentContext(service.getEnvironmentContext()); restService.setModelInvariantId(service.getModelInvariantUUID()); restService.setModelName(service.getModelName()); restService.setModelVersionId(service.getModelUUID()); restService.setModelVersion(service.getModelVersion()); - restService.setServiceRole(service.getServiceRole()); + if (service.getServiceRole() != null) { + restService.setServiceRole(service.getServiceRole()); + } restService.setServiceType(service.getServiceType()); restService.setWorkloadContext(service.getWorkloadContext()); if (depth > 0) @@ -63,7 +72,7 @@ public class ServiceMapper { return vnfs; } - private Vnf mapVnf(org.onap.so.db.catalog.beans.VnfResourceCustomization vnfResourceCustomization, int depth) { + protected Vnf mapVnf(org.onap.so.db.catalog.beans.VnfResourceCustomization vnfResourceCustomization, int depth) { Vnf vnf = new Vnf(); vnf.setAvailabilityZoneMaxCount(vnfResourceCustomization.getAvailabilityZoneMaxCount()); vnf.setCategory(vnfResourceCustomization.getVnfResources().getCategory()); @@ -81,9 +90,12 @@ public class ServiceMapper { vnf.setNfFunction(vnfResourceCustomization.getNfFunction()); vnf.setNfNamingCode(vnfResourceCustomization.getNfNamingCode()); vnf.setNfRole(vnfResourceCustomization.getNfRole()); + vnf.setNfType(vnfResourceCustomization.getNfType()); + vnf.setNfDataValid(vnfResourceCustomization.getNfDataValid()); vnf.setOrchestrationMode(vnfResourceCustomization.getVnfResources().getOrchestrationMode()); vnf.setSubCategory(vnfResourceCustomization.getVnfResources().getSubCategory()); vnf.setToscaNodeType(vnfResourceCustomization.getVnfResources().getToscaNodeType()); + if (depth > 1) { vnf.setVfModule(mapVfModules(vnfResourceCustomization, depth)); } @@ -93,11 +105,11 @@ public class ServiceMapper { private List<VfModule> mapVfModules(VnfResourceCustomization vnfResourceCustomization, int depth) { List<VfModule> vfModules = new ArrayList<>(); vnfResourceCustomization.getVfModuleCustomizations().parallelStream() - .forEach(vfModule -> vfModules.add(mapVfModule(vfModule))); + .forEach(vfModule -> vfModules.add(mapVfModule(vfModule, depth))); return vfModules; } - private VfModule mapVfModule(VfModuleCustomization vfModuleCust) { + private VfModule mapVfModule(VfModuleCustomization vfModuleCust, int depth) { VfModule vfModule = new VfModule(); vfModule.setAvailabilityZoneCount(vfModuleCust.getAvailabilityZoneCount()); vfModule.setCreated(vfModuleCust.getCreated()); @@ -113,9 +125,34 @@ public class ServiceMapper { vfModule.setModelName(vfModuleCust.getVfModule().getModelName()); vfModule.setModelVersionId(vfModuleCust.getVfModule().getModelUUID()); vfModule.setModelVersion(vfModuleCust.getVfModule().getModelVersion()); + if (depth > 3) { + vfModule.setVnfc(mapCvnfcs(vfModuleCust)); + } return vfModule; } + private List<Cvnfc> mapCvnfcs(VfModuleCustomization vfModuleCustomization) { + List<Cvnfc> cvnfcs = new ArrayList<>(); + vfModuleCustomization.getCvnfcCustomization().parallelStream() + .forEach(cvnfcCust -> cvnfcs.add(mapCvnfcCus(cvnfcCust))); + return cvnfcs; + } + + private Cvnfc mapCvnfcCus(CvnfcCustomization cvnfcCust) { + Cvnfc cvnfc = new Cvnfc(); + cvnfc.setCreated(cvnfcCust.getCreated()); + cvnfc.setDescription(cvnfcCust.getDescription()); + cvnfc.setModelCustomizationId(cvnfcCust.getModelCustomizationUUID()); + cvnfc.setModelInstanceName(cvnfcCust.getModelInstanceName()); + cvnfc.setModelInvariantId(cvnfcCust.getModelInvariantUUID()); + cvnfc.setModelName(cvnfcCust.getModelName()); + cvnfc.setModelVersion(cvnfcCust.getModelVersion()); + cvnfc.setModelVersionId(cvnfcCust.getModelUUID()); + cvnfc.setNfcFunction(cvnfcCust.getNfcFunction()); + cvnfc.setNfcNamingCode(cvnfcCust.getNfcNamingCode()); + return cvnfc; + } + private boolean getIsVolumeGroup(VfModuleCustomization vfModuleCust) { boolean isVolumeGroup = false; HeatEnvironment envt = vfModuleCust.getVolumeHeatEnv(); diff --git a/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/rest/ServiceRestImpl.java b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/rest/ServiceRestImpl.java index 520de4d38c..9663033c20 100644 --- a/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/rest/ServiceRestImpl.java +++ b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/rest/ServiceRestImpl.java @@ -34,11 +34,17 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import com.google.common.base.Strings; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.info.Info; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; -@Api(value = "/v1/services", tags = "model") + +@OpenAPIDefinition(info = @Info(title = "/v1", description = "model")) @Path("/v1/services") @Component public class ServiceRestImpl { @@ -49,31 +55,37 @@ public class ServiceRestImpl { @Autowired private ServiceMapper serviceMapper; + @GET @Path("/{modelUUID}") @Produces({MediaType.APPLICATION_JSON}) @Transactional(readOnly = true) public Service findService(@PathParam("modelUUID") String modelUUID, @QueryParam("depth") int depth) { org.onap.so.db.catalog.beans.Service service = serviceRepo.findOneByModelUUID(modelUUID); + if (service == null) { + throw new CatalogEntityNotFoundException("Unable to find Service " + modelUUID); + } return serviceMapper.mapService(service, depth); } @GET - @ApiOperation(value = "Find Service Models", response = Service.class, responseContainer = "List", - notes = "If no query parameters are sent an empty list will be returned") + @Operation(description = "Find Service Models", responses = @ApiResponse( + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Service.class))))) @Produces({MediaType.APPLICATION_JSON}) @Transactional(readOnly = true) public List<Service> queryServices( - @ApiParam(value = "modelName", required = false) @QueryParam("modelName") String modelName, - @ApiParam(value = "distributionStatus", + @Parameter(description = "modelName", required = false) @QueryParam("modelName") String modelName, + @Parameter(description = "distributionStatus", required = false) @QueryParam("distributionStatus") String distributionStatus, - @ApiParam(value = "depth", required = false) @QueryParam("depth") int depth) { + @Parameter(description = "depth", required = false) @QueryParam("depth") int depth) { List<Service> services = new ArrayList<>(); - List<org.onap.so.db.catalog.beans.Service> serviceFromDB = new ArrayList<>(); + List<org.onap.so.db.catalog.beans.Service> serviceFromDB; if (!Strings.isNullOrEmpty(modelName) && !Strings.isNullOrEmpty(distributionStatus)) { serviceFromDB = serviceRepo.findByModelNameAndDistrobutionStatus(modelName, distributionStatus); } else if (!Strings.isNullOrEmpty(modelName)) { serviceFromDB = serviceRepo.findByModelName(modelName); + } else { + serviceFromDB = serviceRepo.findAll(); } serviceFromDB.stream().forEach(serviceDB -> services.add(serviceMapper.mapService(serviceDB, depth))); return services; diff --git a/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/rest/VnfMapper.java b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/rest/VnfMapper.java new file mode 100644 index 0000000000..52a8ccb5a7 --- /dev/null +++ b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/rest/VnfMapper.java @@ -0,0 +1,37 @@ +package org.onap.so.adapters.catalogdb.rest; + +import org.onap.so.db.catalog.beans.VnfResource; +import org.onap.so.db.catalog.beans.VnfResourceCustomization; +import org.onap.so.rest.catalog.beans.Vnf; +import org.springframework.stereotype.Component; +import com.google.common.base.Strings; + +@Component +public class VnfMapper { + + public VnfResourceCustomization mapVnf(VnfResourceCustomization vnfCust, Vnf vnf) { + + vnfCust.setAvailabilityZoneMaxCount(vnf.getAvailabilityZoneMaxCount()); + vnfCust.setMaxInstances(vnf.getMaxInstances()); + vnfCust.setMinInstances(vnf.getMinInstances()); + vnfCust.setModelCustomizationUUID(vnf.getModelCustomizationId()); + vnfCust.setModelInstanceName(vnf.getModelInstanceName()); + vnfCust.setMultiStageDesign(vnf.getMultiStageDesign()); + vnfCust.setNfDataValid(vnf.getNfDataValid()); + vnfCust.setNfFunction(Strings.nullToEmpty(vnf.getNfFunction())); + vnfCust.setNfNamingCode(Strings.nullToEmpty(vnf.getNfNamingCode())); + vnfCust.setNfRole(Strings.nullToEmpty(vnf.getNfRole())); + vnfCust.setNfType(Strings.nullToEmpty(vnf.getNfType())); + + VnfResource vnfRes = vnfCust.getVnfResources(); + vnfRes.setOrchestrationMode(Strings.nullToEmpty(vnfRes.getOrchestrationMode())); + vnfRes.setSubCategory(Strings.nullToEmpty(vnfRes.getSubCategory())); + vnfRes.setToscaNodeType(Strings.nullToEmpty(vnfRes.getToscaNodeType())); + vnfRes.setModelInvariantUUID(vnfRes.getModelInvariantId()); + vnfRes.setModelName(vnfRes.getModelName()); + vnfRes.setModelUUID(vnfRes.getModelUUID()); + vnfRes.setModelVersion(vnfRes.getModelVersion()); + return vnfCust; + } + +} diff --git a/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/rest/VnfRestImpl.java b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/rest/VnfRestImpl.java new file mode 100644 index 0000000000..9202fd21d4 --- /dev/null +++ b/adapters/mso-catalog-db-adapter/src/main/java/org/onap/so/adapters/catalogdb/rest/VnfRestImpl.java @@ -0,0 +1,115 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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 org.onap.so.adapters.catalogdb.rest; + +import java.util.List; +import java.util.stream.Collectors; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import org.onap.so.db.catalog.beans.VnfResourceCustomization; +import org.onap.so.db.catalog.data.repository.ServiceRepository; +import org.onap.so.db.catalog.data.repository.VnfCustomizationRepository; +import org.onap.so.rest.catalog.beans.Service; +import org.onap.so.rest.catalog.beans.Vnf; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.info.Info; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; + +@OpenAPIDefinition(info = @Info(title = "/v1/services/{modelUUID}/vnfs", description = "model")) +@Path("/v1/services/{modelUUID}/vnfs") +@Component +public class VnfRestImpl { + + @Autowired + private ServiceRepository serviceRepo; + + @Autowired + private ServiceMapper serviceMapper; + + @Autowired + private VnfMapper vnfMapper; + + @Autowired + private VnfCustomizationRepository vnfCustRepo; + + @GET + @Operation(description = "Find a VNF model contained within a service", responses = @ApiResponse( + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Vnf.class))))) + @Path("/{modelCustomizationUUID}") + @Produces({MediaType.APPLICATION_JSON}) + @Transactional(readOnly = true) + public Vnf findService(@PathParam("modelUUID") String serviceModelUUID, + @PathParam("modelCustomizationUUID") String modelCustomizationUUID, @QueryParam("depth") int depth) { + org.onap.so.db.catalog.beans.Service service = serviceRepo.findOneByModelUUID(serviceModelUUID); + if (service.getVnfCustomizations() == null || service.getVnfCustomizations().isEmpty()) { + throw new WebApplicationException("Vnf Not Found", 404); + } + List<VnfResourceCustomization> vnfCustom = service.getVnfCustomizations().stream() + .filter(vnfCust -> vnfCust.getModelCustomizationUUID().equals(modelCustomizationUUID)) + .collect(Collectors.toList()); + if (vnfCustom.isEmpty()) { + return null; + } else if (vnfCustom.size() > 1) { + throw new RuntimeException( + "More than one Vnf model returned with model Customization UUID: " + modelCustomizationUUID); + } + return serviceMapper.mapVnf(vnfCustom.get(0), depth); + } + + @PUT + @Operation(description = "Update a VNF model contained within a service", responses = @ApiResponse( + content = @Content(array = @ArraySchema(schema = @Schema(implementation = Vnf.class))))) + @Path("/{modelCustomizationUUID}") + @Produces({MediaType.APPLICATION_JSON}) + @Transactional + public Response findService(@PathParam("modelUUID") String serviceModelUUID, + @PathParam("modelCustomizationUUID") String modelCustomizationUUID, Vnf vnf) { + org.onap.so.db.catalog.beans.Service service = serviceRepo.findOneByModelUUID(serviceModelUUID); + List<VnfResourceCustomization> vnfCustom = service.getVnfCustomizations().stream() + .filter(vnfCust -> vnfCust.getModelCustomizationUUID().equals(modelCustomizationUUID)) + .collect(Collectors.toList()); + if (vnfCustom.isEmpty()) { + throw new RuntimeException("No Vnf Found"); + } else if (vnfCustom.size() > 1) { + throw new RuntimeException( + "More than one Vnf model returned with model Customization UUID: " + modelCustomizationUUID); + } + VnfResourceCustomization vnfCust = vnfMapper.mapVnf(vnfCustom.get(0), vnf); + vnfCustRepo.save(vnfCust); + return Response.ok().build(); + } + +} + diff --git a/adapters/mso-catalog-db-adapter/src/main/resources/application-aaf.yaml b/adapters/mso-catalog-db-adapter/src/main/resources/application-aaf.yaml new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/adapters/mso-catalog-db-adapter/src/main/resources/application-aaf.yaml diff --git a/adapters/mso-catalog-db-adapter/src/main/resources/application-basic.yaml b/adapters/mso-catalog-db-adapter/src/main/resources/application-basic.yaml new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/adapters/mso-catalog-db-adapter/src/main/resources/application-basic.yaml diff --git a/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/R__MacroData.sql b/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/R__MacroData.sql index 13d736e747..f5c7cd65c2 100644 --- a/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/R__MacroData.sql +++ b/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/R__MacroData.sql @@ -25,9 +25,12 @@ INSERT INTO northbound_request_ref_lookup(MACRO_ACTION, ACTION, REQUEST_SCOPE, I ('VolumeGroup-Delete', 'deleteInstance', 'VolumeGroup', true,true, '7','7', 'DEFAULT', '*'), ('VFModule-Create', 'createInstance', 'VfModule', true,true, '7','7', 'DEFAULT', '*'), ('VFModule-Delete', 'deleteInstance', 'VfModule', true,true, '7','7', 'DEFAULT', '*'), +('VFModule-Replace', 'replaceInstance', 'VfModule', true,true, '7','7', 'DEFAULT', '*'), +('VFModule-Replace-Retain-Assignments', 'replaceInstanceRetainAssignments', 'VfModule', true,true, '7','7', 'DEFAULT', '*'), ('NetworkCollection-Macro-Create', 'createInstance', 'NetworkCollection', false,true, '7','7', 'DEFAULT', '*'), ('NetworkCollection-Macro-Delete', 'deleteInstance', 'NetworkCollection', false,true, '7','7', 'DEFAULT', '*'), -('VFModule-ScaleOut', 'scaleOut', 'VfModule', true, true, '7','7', 'DEFAULT', '*'); +('VFModule-ScaleOut', 'scaleOut', 'VfModule', true, true, '7','7', 'DEFAULT', '*'), +('VNF-InPlaceUpdate', 'inPlaceSoftwareUpdate', 'Vnf', true, true, '7','7', 'DEFAULT', '*'); INSERT INTO orchestration_flow_reference(COMPOSITE_ACTION, SEQ_NO, FLOW_NAME, FLOW_VERSION, NB_REQ_REF_LOOKUP_ID) VALUES @@ -147,7 +150,54 @@ INSERT INTO orchestration_flow_reference(COMPOSITE_ACTION, SEQ_NO, FLOW_NAME, FL ('VFModule-ScaleOut', '3', 'CreateVfModuleBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-ScaleOut' and CLOUD_OWNER = 'DEFAULT')), ('VFModule-ScaleOut', '4', 'ActivateVfModuleBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-ScaleOut' and CLOUD_OWNER = 'DEFAULT')), ('VFModule-ScaleOut', '5', 'ConfigurationScaleOutBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-ScaleOut' and CLOUD_OWNER = 'DEFAULT')), -('VFModule-ScaleOut', '6', 'GenericVnfHealthCheckBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-ScaleOut' and CLOUD_OWNER = 'DEFAULT')); +('VFModule-ScaleOut', '6', 'GenericVnfHealthCheckBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-ScaleOut' and CLOUD_OWNER = 'DEFAULT')), +('VFModule-Replace', '1', 'DeactivateVfModuleBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-Replace' and CLOUD_OWNER = 'DEFAULT')), +('VFModule-Replace', '2', 'DeleteVfModuleBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-Replace' and CLOUD_OWNER = 'DEFAULT')), +('VFModule-Replace', '3', 'DeactivateVolumeGroupBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-Replace' and CLOUD_OWNER = 'DEFAULT')), +('VFModule-Replace', '4', 'DeleteVolumeGroupBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-Replace' and CLOUD_OWNER = 'DEFAULT')), +('VFModule-Replace', '5', 'UnassignVfModuleBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-Replace' and CLOUD_OWNER = 'DEFAULT')), +('VFModule-Replace', '6', 'UnassignVolumeGroupBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-Replace' and CLOUD_OWNER = 'DEFAULT')), +('VFModule-Replace', '7', 'AssignVolumeGroupBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-Replace' and CLOUD_OWNER = 'DEFAULT')), +('VFModule-Replace', '8', 'AssignVfModuleBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-Replace' and CLOUD_OWNER = 'DEFAULT')), +('VFModule-Replace', '9', 'CreateVolumeGroupBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-Replace' and CLOUD_OWNER = 'DEFAULT')), +('VFModule-Replace', '10', 'ActivateVolumeGroupBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-Replace' and CLOUD_OWNER = 'DEFAULT')), +('VFModule-Replace', '11', 'CreateVfModuleBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-Replace' and CLOUD_OWNER = 'DEFAULT')), +('VFModule-Replace', '12', 'ActivateVfModuleBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-Replace' and CLOUD_OWNER = 'DEFAULT')), +('VFModule-Replace', '13', 'ChangeModelVnfBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-Replace' and CLOUD_OWNER = 'DEFAULT')), +('VFModule-Replace', '14', 'ChangeModelServiceInstanceBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-Replace' and CLOUD_OWNER = 'DEFAULT')), +('VFModule-Replace-Retain-Assignments', '1', 'DeactivateVfModuleBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-Replace-Retain-Assignments' and CLOUD_OWNER = 'DEFAULT')), +('VFModule-Replace-Retain-Assignments', '2', 'DeleteVfModuleBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-Replace-Retain-Assignments' and CLOUD_OWNER = 'DEFAULT')), +('VFModule-Replace-Retain-Assignments', '3', 'DeactivateVolumeGroupBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-Replace-Retain-Assignments' and CLOUD_OWNER = 'DEFAULT')), +('VFModule-Replace-Retain-Assignments', '4', 'DeleteVolumeGroupBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-Replace-Retain-Assignments' and CLOUD_OWNER = 'DEFAULT')), +('VFModule-Replace-Retain-Assignments', '5', 'UnassignVolumeGroupBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-Replace-Retain-Assignments' and CLOUD_OWNER = 'DEFAULT')), +('VFModule-Replace-Retain-Assignments', '6', 'AssignVolumeGroupBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-Replace-Retain-Assignments' and CLOUD_OWNER = 'DEFAULT')), +('VFModule-Replace-Retain-Assignments', '7', 'ChangeModelVfModuleBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-Replace-Retain-Assignments' and CLOUD_OWNER = 'DEFAULT')), +('VFModule-Replace-Retain-Assignments', '8', 'CreateVolumeGroupBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-Replace-Retain-Assignments' and CLOUD_OWNER = 'DEFAULT')), +('VFModule-Replace-Retain-Assignments', '9', 'ActivateVolumeGroupBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-Replace-Retain-Assignments' and CLOUD_OWNER = 'DEFAULT')), +('VFModule-Replace-Retain-Assignments', '10', 'CreateVfModuleBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-Replace-Retain-Assignments' and CLOUD_OWNER = 'DEFAULT')), +('VFModule-Replace-Retain-Assignments', '11', 'ActivateVfModuleBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-Replace-Retain-Assignments' and CLOUD_OWNER = 'DEFAULT')), +('VFModule-Replace-Retain-Assignments', '12', 'ChangeModelVnfBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-Replace-Retain-Assignments' and CLOUD_OWNER = 'DEFAULT')), +('VFModule-Replace-Retain-Assignments', '13', 'ChangeModelServiceInstanceBB', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VFModule-Replace-Retain-Assignments' and CLOUD_OWNER = 'DEFAULT')), +('VNF-InPlaceUpdate', '1', 'VNFCheckPserversLockedFlagActivity', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VNF-InPlaceUpdate' and CLOUD_OWNER = 'DEFAULT')), +('VNF-InPlaceUpdate', '2', 'VNFCheckInMaintFlagActivity', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VNF-InPlaceUpdate' and CLOUD_OWNER = 'DEFAULT')), +('VNF-InPlaceUpdate', '3', 'VNFSetInMaintFlagActivity', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VNF-InPlaceUpdate' and CLOUD_OWNER = 'DEFAULT')), +('VNF-InPlaceUpdate', '4', 'VNFCheckClosedLoopDisabledFlagActivity', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VNF-InPlaceUpdate' and CLOUD_OWNER = 'DEFAULT')), +('VNF-InPlaceUpdate', '5', 'VNFSetClosedLoopDisabledFlagActivity', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VNF-InPlaceUpdate' and CLOUD_OWNER = 'DEFAULT')), +('VNF-InPlaceUpdate', '6', 'VNFLockActivity', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VNF-InPlaceUpdate' and CLOUD_OWNER = 'DEFAULT')), +('VNF-InPlaceUpdate', '7', 'VNFUpgradePreCheckActivity', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VNF-InPlaceUpdate' and CLOUD_OWNER = 'DEFAULT')), +('VNF-InPlaceUpdate', '8', 'VNFQuiesceTrafficActivity', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VNF-InPlaceUpdate' and CLOUD_OWNER = 'DEFAULT')), +('VNF-InPlaceUpdate', '9', 'VNFStopActivity', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VNF-InPlaceUpdate' and CLOUD_OWNER = 'DEFAULT')), +('VNF-InPlaceUpdate', '10', 'VNFSnapShotActivity', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VNF-InPlaceUpdate' and CLOUD_OWNER = 'DEFAULT')), +('VNF-InPlaceUpdate', '11', 'VNFStartActivity', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VNF-InPlaceUpdate' and CLOUD_OWNER = 'DEFAULT')), +('VNF-InPlaceUpdate', '12', 'VNFUpgradeBackupActivity', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VNF-InPlaceUpdate' and CLOUD_OWNER = 'DEFAULT')), +('VNF-InPlaceUpdate', '13', 'VNFUpgradeSoftwareActivity', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VNF-InPlaceUpdate' and CLOUD_OWNER = 'DEFAULT')), +('VNF-InPlaceUpdate', '14', 'VNFUpgradePostCheckActivity', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VNF-InPlaceUpdate' and CLOUD_OWNER = 'DEFAULT')), +('VNF-InPlaceUpdate', '15', 'VNFResumeTrafficActivity', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VNF-InPlaceUpdate' and CLOUD_OWNER = 'DEFAULT')), +('VNF-InPlaceUpdate', '16', 'VNFUnlockActivity', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VNF-InPlaceUpdate' and CLOUD_OWNER = 'DEFAULT')), +('VNF-InPlaceUpdate', '17', 'VNFUnsetInMaintFlagActivity', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VNF-InPlaceUpdate' and CLOUD_OWNER = 'DEFAULT')), +('VNF-InPlaceUpdate', '18', 'VNFUnsetClosedLoopDisabledFlagActivity', 1.0,(SELECT id from northbound_request_ref_lookup WHERE MACRO_ACTION = 'VNF-InPlaceUpdate' and CLOUD_OWNER = 'DEFAULT')); + + INSERT INTO rainy_day_handler_macro (FLOW_NAME, SERVICE_TYPE, VNF_TYPE, ERROR_CODE, WORK_STEP, POLICY) VALUES @@ -815,3 +865,11 @@ VALUES UPDATE rainy_day_handler_macro SET reg_ex_error_message = '*' WHERE reg_ex_error_message IS null; UPDATE rainy_day_handler_macro SET SERVICE_ROLE = '*' WHERE SERVICE_ROLE IS null; + +INSERT INTO vnf_components_recipe (VNF_TYPE, VNF_COMPONENT_TYPE, ACTION, VERSION, ORCHESTRATION_URI, RECIPE_TIMEOUT) +VALUES +(NULL, 'vfModule', 'replaceInstanceRetainAssignments', '1', '/mso/async/services/WorkflowActionBB', 180); + +UPDATE vnf_recipe +SET ORCHESTRATION_URI = '/mso/async/services/WorkflowActionBB' +WHERE NF_ROLE = 'GR-API-DEFAULT' AND ACTION = 'inPlaceSoftwareUpdate'; diff --git a/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/R__WorkflowDesignerData.sql b/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/R__WorkflowDesignerData.sql index 137f73cf65..42df1adf13 100644 --- a/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/R__WorkflowDesignerData.sql +++ b/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/R__WorkflowDesignerData.sql @@ -202,4 +202,6 @@ INSERT INTO `workflow` (`ARTIFACT_UUID`,`ARTIFACT_NAME`,`NAME`,`OPERATION_NAME`, VALUES ('9d45cd30-1a89-4993-87c1-6dd09c1696cf','VFModule-ScaleOut','VNF Scale Out','ScaleOut',1.0,'native static workflow to support ScaleOut','vfModule','native'), ('da6478e4-ea33-3346-ac12-ab121284a333','VnfInPlaceUpdate.bpmn','VnfInPlaceUpdate','inPlaceSoftwareUpdate',1.0,'native static workflow to support inPlaceSoftwareUpdate','vnf','native'), -('fdb3ac48-70f9-4584-bd92-253bdbdec1e1','VnfConfigUpdate.bpmn','VnfConfigUpdate','applyConfigModify',1.0,'native static workflow to support applyConfigModify','vnf','native'); +('fdb3ac48-70f9-4584-bd92-253bdbdec1e1','VnfConfigUpdate.bpmn','VnfConfigUpdate','applyConfigModify',1.0,'native static workflow to support applyConfigModify','vnf','native'), +('b2fd5627-55e4-4f4f-8064-9e6f443e9152','DummyPnfWorkflow','Dummy Pnf Workflow','DummyPnfWorkflow',1.0,'Dummy Pnf Workflow to test custom Pnf workflow','pnf','native'); + diff --git a/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V5.5.1__Correct_Default_NeutronNetwork.sql b/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V5.5.1__Correct_Default_NeutronNetwork.sql index 5d940fb9ea..8e52fbeeaf 100644 --- a/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V5.5.1__Correct_Default_NeutronNetwork.sql +++ b/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V5.5.1__Correct_Default_NeutronNetwork.sql @@ -30,3 +30,8 @@ resources: INSERT INTO `temp_network_heat_template_lookup` (`NETWORK_RESOURCE_MODEL_NAME`, `HEAT_TEMPLATE_ARTIFACT_UUID`,`AIC_VERSION_MIN` , `AIC_VERSION_MAX` ) VALUES ('Generic NeutronNet','efee1d84-b8ec-11e7-abc4-cec278b6b50a','2.0','3.0'); +INSERT INTO `heat_template_params` (`HEAT_TEMPLATE_ARTIFACT_UUID`, `PARAM_NAME`, `IS_REQUIRED`, `PARAM_TYPE`, `PARAM_ALIAS`) +VALUES ('efee1d84-b8ec-11e7-abc4-cec278b6b50a', 'network_name', 0, 'String', NULL); + +INSERT INTO `heat_template_params` (`HEAT_TEMPLATE_ARTIFACT_UUID`, `PARAM_NAME`, `IS_REQUIRED`, `PARAM_TYPE`, `PARAM_ALIAS`) +VALUES ('efee1d84-b8ec-11e7-abc4-cec278b6b50a', 'shared', 0, 'Boolean', NULL); diff --git a/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V5.7.1__WorkFlowDesignerTables.sql b/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V5.7.1__WorkFlowDesignerTables.sql index e44a6b97ba..8641e51862 100644 --- a/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V5.7.1__WorkFlowDesignerTables.sql +++ b/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V5.7.1__WorkFlowDesignerTables.sql @@ -40,6 +40,27 @@ CREATE TABLE IF NOT EXISTS `catalogdb`.`vnf_resource_to_workflow` ( ENGINE = InnoDB DEFAULT CHARACTER SET = latin1; +CREATE TABLE IF NOT EXISTS `catalogdb`.`pnf_resource_to_workflow` ( + `ID` INT(11) NOT NULL AUTO_INCREMENT, + `PNF_RESOURCE_MODEL_UUID` VARCHAR(200) NOT NULL, + `WORKFLOW_ID` INT(11) NOT NULL, + PRIMARY KEY (`ID`), + UNIQUE INDEX `UK_pnf_resource_to_workflow` (`PNF_RESOURCE_MODEL_UUID` ASC, `WORKFLOW_ID` ASC), + INDEX `fk_pnf_resource_to_workflow__workflow1_idx` (`WORKFLOW_ID` ASC), + INDEX `fk_pnf_resource_to_workflow__pnf_res_mod_uuid_idx` (`PNF_RESOURCE_MODEL_UUID` ASC), + CONSTRAINT `fk_pnf_resource_to_workflow__pnf_resource1` + FOREIGN KEY (`PNF_RESOURCE_MODEL_UUID`) + REFERENCES `catalogdb`.`pnf_resource` (`MODEL_UUID`) + ON DELETE CASCADE + ON UPDATE CASCADE, + CONSTRAINT `fk_pnf_resource_to_workflow__workflow1` + FOREIGN KEY (`WORKFLOW_ID`) + REFERENCES `catalogdb`.`workflow` (`ID`) + ON DELETE CASCADE + ON UPDATE CASCADE) +ENGINE = InnoDB +DEFAULT CHARACTER SET = latin1; + CREATE TABLE IF NOT EXISTS `catalogdb`.`activity_spec` ( `ID` INT(11) NOT NULL AUTO_INCREMENT, `NAME` VARCHAR(200) NOT NULL, diff --git a/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V6.2__AddNfValidData.sql b/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V6.2__AddNfValidData.sql new file mode 100644 index 0000000000..93dde1341e --- /dev/null +++ b/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V6.2__AddNfValidData.sql @@ -0,0 +1,5 @@ +USE catalogdb; + +ALTER TABLE vnf_resource_customization +ADD IF NOT EXISTS NF_DATA_VALID tinyint(1) DEFAULT 0; + diff --git a/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V7.0__AddActivatedForOrchestrationStatus.sql b/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V7.0__AddActivatedForOrchestrationStatus.sql new file mode 100644 index 0000000000..30b5010c7c --- /dev/null +++ b/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V7.0__AddActivatedForOrchestrationStatus.sql @@ -0,0 +1,47 @@ +INSERT INTO orchestration_status_state_transition_directive(RESOURCE_TYPE, ORCHESTRATION_STATUS, TARGET_ACTION, FLOW_DIRECTIVE) +VALUES + +('CONFIGURATION', 'ACTIVATED', 'UNASSIGN', 'FAIL'), +('CONFIGURATION', 'ACTIVATED', 'ASSIGN', 'SILENT_SUCCESS'), +('CONFIGURATION', 'ACTIVATED', 'ACTIVATE', 'SILENT_SUCCESS'), +('CONFIGURATION', 'ACTIVATED', 'DEACTIVATE', 'CONTINUE'), + +('NETWORK', 'ACTIVATED', 'ASSIGN', 'SILENT_SUCCESS'), +('NETWORK', 'ACTIVATED', 'UNASSIGN', 'FAIL'), +('NETWORK', 'ACTIVATED', 'ACTIVATE', 'SILENT_SUCCESS'), +('NETWORK', 'ACTIVATED', 'DEACTIVATE', 'CONTINUE'), +('NETWORK', 'ACTIVATED', 'CREATE', 'SILENT_SUCCESS'), +('NETWORK', 'ACTIVATED', 'DELETE', 'FAIL'), +('NETWORK', 'ACTIVATED', 'UPDATE', 'CONTINUE'), +('NETWORK_COLLECTION', 'ACTIVATED', 'CREATE', 'FAIL'), +('NETWORK_COLLECTION', 'ACTIVATED', 'DELETE', 'CONTINUE'), +('NETWORK_COLLECTION', 'ACTIVATED', 'ACTIVATE', 'SILENT_SUCCESS'), + +('NO_VALIDATE', 'ACTIVATED', 'CUSTOM', 'CONTINUE'), + +('SERVICE', 'ACTIVATED', 'ASSIGN', 'SILENT_SUCCESS'), +('SERVICE', 'ACTIVATED', 'UNASSIGN', 'FAIL'), +('SERVICE', 'ACTIVATED', 'ACTIVATE', 'SILENT_SUCCESS'), +('SERVICE', 'ACTIVATED', 'DEACTIVATE', 'CONTINUE'), +('SERVICE', 'ACTIVATED', 'CHANGE_MODEL', 'CONTINUE'), + +('VF_MODULE', 'ACTIVATED', 'ASSIGN', 'SILENT_SUCCESS'), +('VF_MODULE', 'ACTIVATED', 'UNASSIGN', 'FAIL'), +('VF_MODULE', 'ACTIVATED', 'ACTIVATE', 'SILENT_SUCCESS'), +('VF_MODULE', 'ACTIVATED', 'DEACTIVATE', 'CONTINUE'), +('VF_MODULE', 'ACTIVATED', 'CHANGE_MODEL', 'CONTINUE'), +('VF_MODULE', 'ACTIVATED', 'CREATE', 'SILENT_SUCCESS'), +('VF_MODULE', 'ACTIVATED', 'DELETE', 'FAIL'), + +('VNF', 'ACTIVATED', 'ASSIGN', 'SILENT_SUCCESS'), +('VNF', 'ACTIVATED', 'UNASSIGN', 'FAIL'), +('VNF', 'ACTIVATED', 'ACTIVATE', 'SILENT_SUCCESS'), +('VNF', 'ACTIVATED', 'DEACTIVATE', 'CONTINUE'), +('VNF', 'ACTIVATED', 'CHANGE_MODEL', 'CONTINUE'), + +('VOLUME_GROUP', 'ACTIVATED', 'ASSIGN', 'SILENT_SUCCESS'), +('VOLUME_GROUP', 'ACTIVATED', 'UNASSIGN', 'FAIL'), +('VOLUME_GROUP', 'ACTIVATED', 'ACTIVATE', 'SILENT_SUCCESS'), +('VOLUME_GROUP', 'ACTIVATED', 'DEACTIVATE', 'CONTINUE'), +('VOLUME_GROUP', 'ACTIVATED', 'CREATE', 'SILENT_SUCCESS'), +('VOLUME_GROUP', 'ACTIVATED', 'DELETE', 'FAIL');
\ No newline at end of file diff --git a/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V7.1__UpdatedCloudSiteTable.sql b/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V7.1__UpdatedCloudSiteTable.sql new file mode 100644 index 0000000000..ea0af2315c --- /dev/null +++ b/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V7.1__UpdatedCloudSiteTable.sql @@ -0,0 +1,5 @@ +use catalogdb; + +ALTER TABLE cloud_sites + ADD COLUMN IF NOT EXISTS SUPPORT_FABRIC bit(1) + NOT NULL DEFAULT 1 diff --git a/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V7.2__UpdateCloudSiteTableSupportFabric.sql b/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V7.2__UpdateCloudSiteTableSupportFabric.sql new file mode 100644 index 0000000000..6578b5a297 --- /dev/null +++ b/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V7.2__UpdateCloudSiteTableSupportFabric.sql @@ -0,0 +1,3 @@ +use catalogdb; + +UPDATE cloud_sites SET SUPPORT_FABRIC = b'0' WHERE CLOUD_VERSION != '1.0.0';
\ No newline at end of file diff --git a/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V7.3__UpdateVnfcCustResourceInputLength.sql b/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V7.3__UpdateVnfcCustResourceInputLength.sql new file mode 100644 index 0000000000..66c01538f7 --- /dev/null +++ b/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V7.3__UpdateVnfcCustResourceInputLength.sql @@ -0,0 +1,4 @@ +use catalogdb; + +ALTER TABLE vnfc_customization + MODIFY IF EXISTS RESOURCE_INPUT varchar(20000);
\ No newline at end of file diff --git a/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V8.1__AddControllerActorAndBlueprint.sql b/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V8.1__AddControllerActorAndBlueprint.sql new file mode 100644 index 0000000000..5560dcc0de --- /dev/null +++ b/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V8.1__AddControllerActorAndBlueprint.sql @@ -0,0 +1,23 @@ +use catalogdb; + +ALTER TABLE service +ADD CONTROLLER_ACTOR varchar(200) null; + +ALTER TABLE service +ADD CDS_BLUEPRINT_NAME varchar(200) null; + +ALTER TABLE service +ADD CDS_BLUEPRINT_VERSION varchar(20) null; + +ALTER TABLE service +ADD SKIP_POST_INSTANTIATION_CONFIGURATION boolean default true; + +ALTER TABLE vnf_resource_customization +ADD CONTROLLER_ACTOR varchar(200) null; + +ALTER TABLE pnf_resource_customization +ADD CONTROLLER_ACTOR varchar(200) null; + +ALTER TABLE vf_module_customization +ADD SKIP_POST_INSTANTIATION_CONFIGURATION boolean default true; + diff --git a/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V8.2__AddScopeAndActionColumnsInOrchestrationFlowReference.sql b/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V8.2__AddScopeAndActionColumnsInOrchestrationFlowReference.sql new file mode 100644 index 0000000000..19bfb0f1e1 --- /dev/null +++ b/adapters/mso-catalog-db-adapter/src/main/resources/db/migration/V8.2__AddScopeAndActionColumnsInOrchestrationFlowReference.sql @@ -0,0 +1,5 @@ +use catalogdb; + +ALTER TABLE orchestration_flow_reference +ADD SCOPE VARCHAR (200) DEFAULT NULL, +ADD ACTION VARCHAR (200) DEFAULT NULL;
\ No newline at end of file diff --git a/adapters/mso-catalog-db-adapter/src/test/java/org/onap/so/adapters/catalogdb/catalogrest/CatalogDBRestTest.java b/adapters/mso-catalog-db-adapter/src/test/java/org/onap/so/adapters/catalogdb/catalogrest/CatalogDBRestTest.java index 145ba50583..69a23a0eba 100644 --- a/adapters/mso-catalog-db-adapter/src/test/java/org/onap/so/adapters/catalogdb/catalogrest/CatalogDBRestTest.java +++ b/adapters/mso-catalog-db-adapter/src/test/java/org/onap/so/adapters/catalogdb/catalogrest/CatalogDBRestTest.java @@ -21,22 +21,13 @@ package org.onap.so.adapters.catalogdb.catalogrest; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.onap.so.logger.MdcConstants.ENDTIME; -import static org.onap.so.logger.MdcConstants.INVOCATION_ID; -import static org.onap.so.logger.MdcConstants.PARTNERNAME; -import static org.onap.so.logger.MdcConstants.RESPONSECODE; -import static org.onap.so.logger.MdcConstants.RESPONSEDESC; -import static org.onap.so.logger.MdcConstants.SERVICE_NAME; -import static org.onap.so.logger.MdcConstants.STATUSCODE; import java.io.IOException; -import java.util.Map; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.json.JSONException; import org.junit.Test; -import org.onap.logging.ref.slf4j.ONAPLogConstants; import org.onap.so.adapters.catalogdb.CatalogDbAdapterBaseTest; +import org.onap.so.db.catalog.beans.ServiceRecipe; import org.skyscreamer.jsonassert.JSONAssert; import org.skyscreamer.jsonassert.JSONCompareMode; import org.springframework.boot.test.web.client.TestRestTemplate; @@ -45,13 +36,14 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.web.util.UriComponentsBuilder; -import ch.qos.logback.classic.spi.ILoggingEvent; public class CatalogDBRestTest extends CatalogDbAdapterBaseTest { private static final String ECOMP_MSO_CATALOG_V2_VF_MODULES = "ecomp/mso/catalog/v2/vfModules"; + private static final String SERVICE_RECIPE = "serviceRecipe"; + private static final String ECOMP_MSO_CATALOG_V2_SERVICE_ALLOTTED_RESOURCES = "ecomp/mso/catalog/v2/serviceAllottedResources"; @@ -106,26 +98,6 @@ public class CatalogDBRestTest extends CatalogDbAdapterBaseTest { restTemplate.exchange(createURLWithPort("/manage/health"), HttpMethod.GET, entity, String.class); assertEquals(Response.Status.OK.getStatusCode(), response.getStatusCode().value()); - for (ILoggingEvent logEvent : TestAppender.events) - if (logEvent.getLoggerName().equals("org.onap.so.logging.spring.interceptor.LoggingInterceptor") - && logEvent.getMarker() != null && logEvent.getMarker().getName().equals("ENTRY")) { - Map<String, String> mdc = logEvent.getMDCPropertyMap(); - assertNotNull(mdc.get(ONAPLogConstants.MDCs.INSTANCE_UUID)); - assertNotNull(mdc.get(ONAPLogConstants.MDCs.REQUEST_ID)); - assertNotNull(mdc.get(ONAPLogConstants.MDCs.INVOCATION_ID)); - assertEquals("", mdc.get(ONAPLogConstants.MDCs.PARTNER_NAME)); - assertEquals("/manage/health", mdc.get(ONAPLogConstants.MDCs.SERVICE_NAME)); - assertEquals("INPROGRESS", mdc.get(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE)); - } else if (logEvent.getLoggerName().equals("org.onap.so.logging.spring.interceptor.LoggingInterceptor") - && logEvent.getMarker() != null && logEvent.getMarker().getName().equals("EXIT")) { - Map<String, String> mdc = logEvent.getMDCPropertyMap(); - assertNotNull(mdc.get(ONAPLogConstants.MDCs.REQUEST_ID)); - assertNotNull(mdc.get(ONAPLogConstants.MDCs.INVOCATION_ID)); - assertEquals("200", mdc.get(ONAPLogConstants.MDCs.RESPONSE_CODE)); - assertEquals("", mdc.get(ONAPLogConstants.MDCs.PARTNER_NAME)); - assertEquals("/manage/health", mdc.get(ONAPLogConstants.MDCs.SERVICE_NAME)); - assertEquals("COMPLETED", mdc.get(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE)); - } } /* Service Resources Endpoint */ @@ -812,31 +784,25 @@ public class CatalogDBRestTest extends CatalogDbAdapterBaseTest { assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatusCode().value()); JSONAssert.assertEquals(badQueryParamResponse, response.getBody().toString(), false); + } + @Test + public void testCreateServiceRecipe() throws JSONException { + ServiceRecipe recipe = new ServiceRecipe(); + recipe.setAction("action"); + recipe.setDescription("description"); + recipe.setOrchestrationUri("http://test"); + recipe.setRecipeTimeout(120); + recipe.setServiceModelUUID(serviceUUID); + HttpEntity<ServiceRecipe> entity = new HttpEntity<ServiceRecipe>(recipe, headers); + headers.set("Accept", MediaType.APPLICATION_JSON); + + UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(createURLWithPort(SERVICE_RECIPE)); + + ResponseEntity<String> response = + restTemplate.exchange(builder.toUriString(), HttpMethod.POST, entity, String.class); - for (ILoggingEvent logEvent : TestAppender.events) - if (logEvent.getLoggerName().equals("org.onap.so.logging.jaxrs.filter.jersey.JaxRsFilterLogging") - && logEvent.getMarker().getName().equals("ENTRY")) { - Map<String, String> mdc = logEvent.getMDCPropertyMap(); - assertNotNull(mdc.get(ONAPLogConstants.MDCs.ENTRY_TIMESTAMP)); - assertNotNull(mdc.get(ONAPLogConstants.MDCs.REQUEST_ID)); - assertNotNull(mdc.get(INVOCATION_ID)); - assertEquals("UNKNOWN", mdc.get(PARTNERNAME)); - assertEquals("v2/vfModules", mdc.get(SERVICE_NAME)); - assertEquals("INPROGRESS", mdc.get(STATUSCODE)); - } else if (logEvent.getLoggerName().equals("org.onap.so.logging.jaxrs.filter.jersey.JaxRsFilterLogging") - && logEvent.getMarker().getName().equals("EXIT")) { - Map<String, String> mdc = logEvent.getMDCPropertyMap(); - assertNotNull(mdc.get(ONAPLogConstants.MDCs.ENTRY_TIMESTAMP)); - assertNotNull(mdc.get(ENDTIME)); - assertNotNull(mdc.get(ONAPLogConstants.MDCs.REQUEST_ID)); - assertNotNull(mdc.get(INVOCATION_ID)); - assertEquals("500", mdc.get(RESPONSECODE)); - assertEquals("UNKNOWN", mdc.get(PARTNERNAME)); - assertEquals("v2/vfModules", mdc.get(SERVICE_NAME)); - assertEquals("ERROR", mdc.get(STATUSCODE)); - assertNotNull(mdc.get(RESPONSEDESC)); - } + assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatusCode().value()); } private String createURLWithPort(String uri) { diff --git a/adapters/mso-catalog-db-adapter/src/test/java/org/onap/so/adapters/catalogdb/catalogrest/QueryServiceVnfTest.java b/adapters/mso-catalog-db-adapter/src/test/java/org/onap/so/adapters/catalogdb/catalogrest/QueryServiceVnfTest.java new file mode 100644 index 0000000000..b71808b2c8 --- /dev/null +++ b/adapters/mso-catalog-db-adapter/src/test/java/org/onap/so/adapters/catalogdb/catalogrest/QueryServiceVnfTest.java @@ -0,0 +1,36 @@ +package org.onap.so.adapters.catalogdb.catalogrest; + +import static org.junit.Assert.assertEquals; +import org.json.JSONException; +import org.junit.Test; + + +public class QueryServiceVnfTest extends QueryServiceVnfs { + + private QueryServiceVnfs queryServiceVnf = new QueryServiceVnfs(); + + private final String invalidJSON = + "\"{\\\\\\\"nf_function\\\\\\\":\\\\\\\"DO_STUFF\\\\\\\",\\\"_image_name\\\\\\\":\\\\\\\"test_image\\\""; + + private final String validJSON = "\"{\"nf_function\":\"DO_STUFF\",\"image_name\":\"test_image\"}"; + + @Test + public void test_IsValidJsonTrue() throws JSONException { + boolean isValidJson = queryServiceVnf.isJSONValid(validJSON); + assertEquals(true, isValidJson); + } + + @Test + public void test_IsValidJsonFalse() throws JSONException { + boolean isValidJson = queryServiceVnf.isJSONValid(invalidJSON); + assertEquals(false, isValidJson); + } + + @Test + public void test_IsValidJsonNull() throws JSONException { + boolean isValidJson = queryServiceVnf.isJSONValid(null); + assertEquals(false, isValidJson); + } + + +} diff --git a/adapters/mso-catalog-db-adapter/src/test/java/org/onap/so/adapters/catalogdb/catalogrest/ServiceMapperTest.java b/adapters/mso-catalog-db-adapter/src/test/java/org/onap/so/adapters/catalogdb/catalogrest/ServiceMapperTest.java index 8decd77656..d46fd9c7ba 100644 --- a/adapters/mso-catalog-db-adapter/src/test/java/org/onap/so/adapters/catalogdb/catalogrest/ServiceMapperTest.java +++ b/adapters/mso-catalog-db-adapter/src/test/java/org/onap/so/adapters/catalogdb/catalogrest/ServiceMapperTest.java @@ -67,6 +67,7 @@ public class ServiceMapperTest { testService.setModelVersion("modelVersion"); testService.setServiceType("serviceType"); testService.setServiceRole("serviceRole"); + testService.getVnfCustomizations().add(getTestVnfCustomization()); return testService; } diff --git a/adapters/mso-catalog-db-adapter/src/test/java/org/onap/so/db/catalog/client/CatalogDbClientTest.java b/adapters/mso-catalog-db-adapter/src/test/java/org/onap/so/db/catalog/client/CatalogDbClientTest.java index a955a2c3ce..707a2a45af 100644 --- a/adapters/mso-catalog-db-adapter/src/test/java/org/onap/so/db/catalog/client/CatalogDbClientTest.java +++ b/adapters/mso-catalog-db-adapter/src/test/java/org/onap/so/db/catalog/client/CatalogDbClientTest.java @@ -22,15 +22,15 @@ package org.onap.so.db.catalog.client; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.util.List; import java.util.UUID; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; -import org.onap.so.adapters.catalogdb.CatalogDBApplication; import org.onap.so.adapters.catalogdb.CatalogDbAdapterBaseTest; import org.onap.so.db.catalog.beans.AuthenticationType; import org.onap.so.db.catalog.beans.CloudIdentity; @@ -56,10 +56,7 @@ import org.onap.so.db.catalog.beans.macro.NorthBoundRequest; import org.onap.so.db.catalog.beans.macro.RainyDayHandlerStatus; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit4.SpringRunner; public class CatalogDbClientTest extends CatalogDbAdapterBaseTest { @@ -74,6 +71,8 @@ public class CatalogDbClientTest extends CatalogDbAdapterBaseTest { @Autowired CatalogDbClientPortChanger client; + + @Before public void initialize() { client.wiremockPort = String.valueOf(port); @@ -88,7 +87,7 @@ public class CatalogDbClientTest extends CatalogDbAdapterBaseTest { public void testGetRainyDayHandler_Regex() { RainyDayHandlerStatus rainyDayHandlerStatus = client.getRainyDayHandlerStatus("AssignServiceInstanceBB", "*", "*", "*", "*", "The Flavor ID (nd.c6r16d20) could not be found.", "*"); - Assert.assertEquals("Rollback", rainyDayHandlerStatus.getPolicy()); + assertEquals("Rollback", rainyDayHandlerStatus.getPolicy()); } @Test @@ -97,105 +96,105 @@ public class CatalogDbClientTest extends CatalogDbAdapterBaseTest { "*", "*", "*", "resources.lba_0_dmz_vmi_0: Unknown id: Error: oper 1 url /fqname-to-id body {\"fq_name\": [\"zrdm6bvota05-dmz_sec_group\"], \"type\": \"security-group\"} response Name ['zrdm6bvota05-dmz_sec_group'] not found", "*"); - Assert.assertEquals("Rollback", rainyDayHandlerStatus.getPolicy()); + assertEquals("Rollback", rainyDayHandlerStatus.getPolicy()); } @Test public void testGetCloudSiteHappyPath() throws Exception { CloudSite cloudSite = client.getCloudSite(MTN13); - Assert.assertNotNull(cloudSite); - Assert.assertNotNull(cloudSite.getIdentityService()); - Assert.assertEquals("MDT13", cloudSite.getClli()); - Assert.assertEquals("mtn13", cloudSite.getRegionId()); - Assert.assertEquals("MTN13", cloudSite.getIdentityServiceId()); + assertNotNull(cloudSite); + assertNotNull(cloudSite.getIdentityService()); + assertEquals("MDT13", cloudSite.getClli()); + assertEquals("mtn13", cloudSite.getRegionId()); + assertEquals("MTN13", cloudSite.getIdentityServiceId()); } @Test public void testGetCloudSiteNotFound() throws Exception { CloudSite cloudSite = client.getCloudSite(UUID.randomUUID().toString()); - Assert.assertNull(cloudSite); + assertNull(cloudSite); } @Test public void testGetCloudifyManagerHappyPath() throws Exception { CloudifyManager cloudifyManager = client.getCloudifyManager("mtn13"); - Assert.assertNotNull(cloudifyManager); - Assert.assertEquals("http://localhost:28090/v2.0", cloudifyManager.getCloudifyUrl()); + assertNotNull(cloudifyManager); + assertEquals("http://localhost:28090/v2.0", cloudifyManager.getCloudifyUrl()); } @Test public void testGetCloudifyManagerNotFound() throws Exception { CloudifyManager cloudifyManager = client.getCloudifyManager(UUID.randomUUID().toString()); - Assert.assertNull(cloudifyManager); + assertNull(cloudifyManager); } @Test public void testGetCloudSiteByClliAndAicVersionHappyPath() throws Exception { CloudSite cloudSite = client.getCloudSiteByClliAndAicVersion("MDT13", "2.5"); - Assert.assertNotNull(cloudSite); + assertNotNull(cloudSite); } @Test public void testGetCloudSiteByClliAndAicVersionNotFound() throws Exception { CloudSite cloudSite = client.getCloudSiteByClliAndAicVersion("MDT13", "232496239746328"); - Assert.assertNull(cloudSite); + assertNull(cloudSite); } @Test public void testGetServiceByID() throws Exception { Service serviceByID = client.getServiceByID("5df8b6de-2083-11e7-93ae-92361f002671"); - Assert.assertNotNull(serviceByID); - Assert.assertEquals("MSOTADevInfra_vSAMP10a_Service", serviceByID.getModelName()); - Assert.assertEquals("NA", serviceByID.getServiceType()); - Assert.assertEquals("NA", serviceByID.getServiceRole()); + assertNotNull(serviceByID); + assertEquals("MSOTADevInfra_vSAMP10a_Service", serviceByID.getModelName()); + assertEquals("NA", serviceByID.getServiceType()); + assertEquals("NA", serviceByID.getServiceRole()); } @Test public void testGetServiceByIDNotFound() throws Exception { Service serviceByID = client.getServiceByID(UUID.randomUUID().toString()); - Assert.assertNull(serviceByID); + assertNull(serviceByID); } @Test public void testGetVfModuleByModelUUID() throws Exception { VfModule vfModule = client.getVfModuleByModelUUID("20c4431c-246d-11e7-93ae-92361f002671"); - Assert.assertNotNull(vfModule); - Assert.assertNotNull(vfModule.getVfModuleCustomization()); - Assert.assertEquals("78ca26d0-246d-11e7-93ae-92361f002671", vfModule.getModelInvariantUUID()); - Assert.assertEquals("vSAMP10aDEV::base::module-0", vfModule.getModelName()); + assertNotNull(vfModule); + assertNotNull(vfModule.getVfModuleCustomization()); + assertEquals("78ca26d0-246d-11e7-93ae-92361f002671", vfModule.getModelInvariantUUID()); + assertEquals("vSAMP10aDEV::base::module-0", vfModule.getModelName()); } @Test public void testGetVfModuleByModelUUIDNotFound() throws Exception { VfModule vfModule = client.getVfModuleByModelUUID(UUID.randomUUID().toString()); - Assert.assertNull(vfModule); + assertNull(vfModule); } @Test public void testGetVnfResourceByModelUUID() throws Exception { VnfResource vnfResource = client.getVnfResourceByModelUUID("ff2ae348-214a-11e7-93ae-92361f002671"); - Assert.assertNotNull(vnfResource); - Assert.assertEquals("vSAMP10a", vnfResource.getModelName()); + assertNotNull(vnfResource); + assertEquals("vSAMP10a", vnfResource.getModelName()); } @Test public void testGetVnfResourceByModelUUIDNotFound() throws Exception { VnfResource vnfResource = client.getVnfResourceByModelUUID(UUID.randomUUID().toString()); - Assert.assertNull(vnfResource); + assertNull(vnfResource); } @Test public void testGetVnfResourceCustomizationByModelCustomizationUUID() { VnfResourceCustomization vnfResourceCustomization = client.getVnfResourceCustomizationByModelCustomizationUUID("68dc9a92-214c-11e7-93ae-92361f002671"); - Assert.assertNotNull(vnfResourceCustomization); - Assert.assertEquals("vSAMP", vnfResourceCustomization.getNfRole()); - Assert.assertNotNull(vnfResourceCustomization.getModelCustomizationUUID()); - Assert.assertNotNull(vnfResourceCustomization.getVnfResources()); - Assert.assertNotNull(vnfResourceCustomization.getVfModuleCustomizations()); - Assert.assertEquals("vSAMP10a", vnfResourceCustomization.getVnfResources().getModelName()); + assertNotNull(vnfResourceCustomization); + assertEquals("vSAMP", vnfResourceCustomization.getNfRole()); + assertNotNull(vnfResourceCustomization.getModelCustomizationUUID()); + assertNotNull(vnfResourceCustomization.getVnfResources()); + assertNotNull(vnfResourceCustomization.getVfModuleCustomizations()); + assertEquals("vSAMP10a", vnfResourceCustomization.getVnfResources().getModelName()); assertTrue("skip post instantiation configuration", vnfResourceCustomization.isSkipPostInstConf()); } @@ -203,15 +202,15 @@ public class CatalogDbClientTest extends CatalogDbAdapterBaseTest { public void testGetVnfResourceCustomizationByModelCustomizationUUINotFound() { VnfResourceCustomization vnfResourceCustomization = client.getVnfResourceCustomizationByModelCustomizationUUID(UUID.randomUUID().toString()); - Assert.assertNull(vnfResourceCustomization); + assertNull(vnfResourceCustomization); } @Test public void testGetInstanceGroupByModelUUID() { InstanceGroup instanceGroup = client.getInstanceGroupByModelUUID("0c8692ef-b9c0-435d-a738-edf31e71f38b"); - Assert.assertNotNull(instanceGroup); - Assert.assertEquals("network_collection_resource_1806..NetworkCollection..0", instanceGroup.getModelName()); - Assert.assertEquals("org.openecomp.resource.cr.NetworkCollectionResource1806", + assertNotNull(instanceGroup); + assertEquals("network_collection_resource_1806..NetworkCollection..0", instanceGroup.getModelName()); + assertEquals("org.openecomp.resource.cr.NetworkCollectionResource1806", instanceGroup.getToscaNodeType().toString()); } @@ -219,33 +218,33 @@ public class CatalogDbClientTest extends CatalogDbAdapterBaseTest { public void testGetVfModuleCustomizationByModelCuztomizationUUID() { VfModuleCustomization vfModuleCustomization = client.getVfModuleCustomizationByModelCuztomizationUUID("cb82ffd8-252a-11e7-93ae-92361f002671"); - Assert.assertNotNull(vfModuleCustomization); - Assert.assertNotNull(vfModuleCustomization.getModelCustomizationUUID()); - Assert.assertEquals("base", vfModuleCustomization.getLabel()); + assertNotNull(vfModuleCustomization); + assertNotNull(vfModuleCustomization.getModelCustomizationUUID()); + assertEquals("base", vfModuleCustomization.getLabel()); } @Test public void testGetVfModuleCustomizationByModelCuztomizationUUIDNotFound() { VfModuleCustomization vfModuleCustomization = client.getVfModuleCustomizationByModelCuztomizationUUID(UUID.randomUUID().toString()); - Assert.assertNull(vfModuleCustomization); + assertNull(vfModuleCustomization); } @Test public void testGetNetworkResourceCustomizationByModelCustomizationUUID() { NetworkResourceCustomization networkResourceCustomization = client.getNetworkResourceCustomizationByModelCustomizationUUID("3bdbb104-476c-483e-9f8b-c095b3d308ac"); - Assert.assertNotNull(networkResourceCustomization); - Assert.assertNotNull(networkResourceCustomization.getModelCustomizationUUID()); - Assert.assertEquals("CONTRAIL30_GNDIRECT 9", networkResourceCustomization.getModelInstanceName()); - Assert.assertNotNull(networkResourceCustomization.getNetworkResource()); + assertNotNull(networkResourceCustomization); + assertNotNull(networkResourceCustomization.getModelCustomizationUUID()); + assertEquals("CONTRAIL30_GNDIRECT 9", networkResourceCustomization.getModelInstanceName()); + assertNotNull(networkResourceCustomization.getNetworkResource()); } @Test public void testGetNetworkResourceCustomizationByModelCustomizationUUIDNotFound() { NetworkResourceCustomization networkResourceCustomization = client.getNetworkResourceCustomizationByModelCustomizationUUID(UUID.randomUUID().toString()); - Assert.assertNull(networkResourceCustomization); + assertNull(networkResourceCustomization); } @Test @@ -253,10 +252,10 @@ public class CatalogDbClientTest extends CatalogDbAdapterBaseTest { VfModuleCustomization vfModuleCustomization = client.getVfModuleCustomizationByModelCustomizationUUIDAndVfModuleModelUUID( "cb82ffd8-252a-11e7-93ae-92361f002672", "20c4431c-246d-11e7-93ae-92361f002672"); - Assert.assertNotNull(vfModuleCustomization); - Assert.assertNotNull(vfModuleCustomization.getModelCustomizationUUID()); - Assert.assertNotNull(vfModuleCustomization.getVfModule()); - Assert.assertEquals("base", vfModuleCustomization.getLabel()); + assertNotNull(vfModuleCustomization); + assertNotNull(vfModuleCustomization.getModelCustomizationUUID()); + assertNotNull(vfModuleCustomization.getVfModule()); + assertEquals("base", vfModuleCustomization.getLabel()); } @Test @@ -264,44 +263,43 @@ public class CatalogDbClientTest extends CatalogDbAdapterBaseTest { VfModuleCustomization vfModuleCustomization = client.getVfModuleCustomizationByModelCustomizationUUIDAndVfModuleModelUUID( "cb82ffd8-252a-11e7-93ae-92361f002672", UUID.randomUUID().toString()); - Assert.assertNull(vfModuleCustomization); + assertNull(vfModuleCustomization); } @Test public void testGetFirstByServiceModelUUIDAndAction() { ServiceRecipe serviceRecipe = client.getFirstByServiceModelUUIDAndAction("4694a55f-58b3-4f17-92a5-796d6f5ffd0d", "createInstance"); - Assert.assertNotNull(serviceRecipe); - Assert.assertNotNull(serviceRecipe.getServiceModelUUID()); - Assert.assertNotNull(serviceRecipe.getAction()); - Assert.assertEquals("/mso/async/services/CreateGenericALaCarteServiceInstance", - serviceRecipe.getOrchestrationUri()); - Assert.assertEquals("MSOTADevInfra aLaCarte", serviceRecipe.getDescription()); + assertNotNull(serviceRecipe); + assertNotNull(serviceRecipe.getServiceModelUUID()); + assertNotNull(serviceRecipe.getAction()); + assertEquals("/mso/async/services/CreateGenericALaCarteServiceInstance", serviceRecipe.getOrchestrationUri()); + assertEquals("MSOTADevInfra aLaCarte", serviceRecipe.getDescription()); } @Test public void testGetFirstByServiceModelUUIDAndActionNotFound() { ServiceRecipe serviceRecipe = client.getFirstByServiceModelUUIDAndAction("5df8b6de-2083-11e7-93ae-92361f002671", UUID.randomUUID().toString()); - Assert.assertNull(serviceRecipe); + assertNull(serviceRecipe); } @Test public void testGetFirstVnfResourceByModelInvariantUUIDAndModelVersion() { VnfResource vnfResource = client .getFirstVnfResourceByModelInvariantUUIDAndModelVersion("2fff5b20-214b-11e7-93ae-92361f002671", "2.0"); - Assert.assertNotNull(vnfResource); - Assert.assertNotNull(vnfResource.getModelInvariantId()); - Assert.assertNotNull(vnfResource.getModelVersion()); - Assert.assertNotNull(vnfResource.getHeatTemplates()); - Assert.assertEquals("vSAMP10a", vnfResource.getModelName()); + assertNotNull(vnfResource); + assertNotNull(vnfResource.getModelInvariantId()); + assertNotNull(vnfResource.getModelVersion()); + assertNotNull(vnfResource.getHeatTemplates()); + assertEquals("vSAMP10a", vnfResource.getModelName()); } @Test public void testGetFirstVnfResourceByModelInvariantUUIDAndModelVersionNotFound() { VnfResource vnfResource = client.getFirstVnfResourceByModelInvariantUUIDAndModelVersion( "2fff5b20-214b-11e7-93ae-92361f002671", UUID.randomUUID().toString()); - Assert.assertNull(vnfResource); + assertNull(vnfResource); } @Test @@ -310,29 +308,28 @@ public class CatalogDbClientTest extends CatalogDbAdapterBaseTest { vnfr.setModelUUID("ff2ae348-214a-11e7-93ae-92361f002671"); VnfResourceCustomization firstVnfResourceCustomizationByModelInstanceNameAndVnfResources = client.getFirstVnfResourceCustomizationByModelInstanceNameAndVnfResources("vSAMP10a 1", vnfr); - Assert.assertNotNull(firstVnfResourceCustomizationByModelInstanceNameAndVnfResources); - Assert.assertEquals("vSAMP", firstVnfResourceCustomizationByModelInstanceNameAndVnfResources.getNfRole()); - Assert.assertEquals("vSAMP10a 1", + assertNotNull(firstVnfResourceCustomizationByModelInstanceNameAndVnfResources); + assertEquals("vSAMP", firstVnfResourceCustomizationByModelInstanceNameAndVnfResources.getNfRole()); + assertEquals("vSAMP10a 1", firstVnfResourceCustomizationByModelInstanceNameAndVnfResources.getModelInstanceName()); - Assert.assertNotNull(firstVnfResourceCustomizationByModelInstanceNameAndVnfResources.getVnfResources()); - Assert.assertNotNull( - firstVnfResourceCustomizationByModelInstanceNameAndVnfResources.getVfModuleCustomizations()); + assertNotNull(firstVnfResourceCustomizationByModelInstanceNameAndVnfResources.getVnfResources()); + assertNotNull(firstVnfResourceCustomizationByModelInstanceNameAndVnfResources.getVfModuleCustomizations()); } @Test public void testGetFirstVnfRecipeByNfRoleAndAction() { VnfRecipe vnfRecipe = client.getFirstVnfRecipeByNfRoleAndAction("GR-API-DEFAULT", "createInstance"); - Assert.assertNotNull(vnfRecipe); - Assert.assertNotNull(vnfRecipe.getNfRole()); - Assert.assertNotNull(vnfRecipe.getAction()); - Assert.assertEquals("Gr api recipe to create vnf", vnfRecipe.getDescription()); - Assert.assertEquals("/mso/async/services/WorkflowActionBB", vnfRecipe.getOrchestrationUri()); + assertNotNull(vnfRecipe); + assertNotNull(vnfRecipe.getNfRole()); + assertNotNull(vnfRecipe.getAction()); + assertEquals("Gr api recipe to create vnf", vnfRecipe.getDescription()); + assertEquals("/mso/async/services/WorkflowActionBB", vnfRecipe.getOrchestrationUri()); } @Test public void testGetFirstVnfRecipeByNfRoleAndActionNotFound() { VnfRecipe vnfRecipe = client.getFirstVnfRecipeByNfRoleAndAction(UUID.randomUUID().toString(), "createInstance"); - Assert.assertNull(vnfRecipe); + assertNull(vnfRecipe); } @Test @@ -340,12 +337,12 @@ public class CatalogDbClientTest extends CatalogDbAdapterBaseTest { VnfComponentsRecipe vnfComponentsRecipe = client.getFirstVnfComponentsRecipeByVfModuleModelUUIDAndVnfComponentTypeAndAction( "20c4431c-246d-11e7-93ae-92361f002671", "volumeGroup", "createInstance"); - Assert.assertNotNull(vnfComponentsRecipe); - Assert.assertNotNull(vnfComponentsRecipe.getAction()); - Assert.assertNotNull(vnfComponentsRecipe.getVfModuleModelUUID()); - Assert.assertNotNull(vnfComponentsRecipe.getVnfComponentType()); - Assert.assertEquals("Gr api recipe to create volume-group", vnfComponentsRecipe.getDescription()); - Assert.assertEquals("/mso/async/services/WorkflowActionBB", vnfComponentsRecipe.getOrchestrationUri()); + assertNotNull(vnfComponentsRecipe); + assertNotNull(vnfComponentsRecipe.getAction()); + assertNotNull(vnfComponentsRecipe.getVfModuleModelUUID()); + assertNotNull(vnfComponentsRecipe.getVnfComponentType()); + assertEquals("Gr api recipe to create volume-group", vnfComponentsRecipe.getDescription()); + assertEquals("/mso/async/services/WorkflowActionBB", vnfComponentsRecipe.getOrchestrationUri()); } @@ -355,80 +352,79 @@ public class CatalogDbClientTest extends CatalogDbAdapterBaseTest { VnfComponentsRecipe vnfComponentsRecipe = client.getFirstVnfComponentsRecipeByVfModuleModelUUIDAndVnfComponentTypeAndAction( UUID.randomUUID().toString(), "volumeGroup", "createInstance"); - Assert.assertNull(vnfComponentsRecipe); + assertNull(vnfComponentsRecipe); } @Test public void testGetFirstVnfComponentsRecipeByVnfComponentTypeAndAction() { VnfComponentsRecipe vnfComponentsRecipe = client.getFirstVnfComponentsRecipeByVnfComponentTypeAndAction("volumeGroup", "createInstance"); - Assert.assertNotNull(vnfComponentsRecipe); - Assert.assertNotNull(vnfComponentsRecipe.getAction()); - Assert.assertNotNull(vnfComponentsRecipe.getVnfComponentType()); - Assert.assertEquals("VID_DEFAULT recipe t", vnfComponentsRecipe.getDescription()); - Assert.assertEquals("/mso/async/services/CreateVfModuleVolumeInfraV1", - vnfComponentsRecipe.getOrchestrationUri()); + assertNotNull(vnfComponentsRecipe); + assertNotNull(vnfComponentsRecipe.getAction()); + assertNotNull(vnfComponentsRecipe.getVnfComponentType()); + assertEquals("VID_DEFAULT recipe t", vnfComponentsRecipe.getDescription()); + assertEquals("/mso/async/services/CreateVfModuleVolumeInfraV1", vnfComponentsRecipe.getOrchestrationUri()); } @Test public void testGetServiceByModelVersionAndModelInvariantUUID() { Service service = client.getServiceByModelVersionAndModelInvariantUUID("2.0", "9647dfc4-2083-11e7-93ae-92361f002671"); - Assert.assertNotNull(service); - Assert.assertNotNull(service.getModelVersion()); - Assert.assertNotNull(service.getModelInvariantUUID()); - Assert.assertEquals("MSOTADevInfra_vSAMP10a_Service", service.getModelName()); - Assert.assertEquals("NA", service.getServiceRole()); + assertNotNull(service); + assertNotNull(service.getModelVersion()); + assertNotNull(service.getModelInvariantUUID()); + assertEquals("MSOTADevInfra_vSAMP10a_Service", service.getModelName()); + assertEquals("NA", service.getServiceRole()); } @Test public void testGetServiceByModelVersionAndModelInvariantUUIDNotFound() { Service service = client.getServiceByModelVersionAndModelInvariantUUID("2.0", UUID.randomUUID().toString()); - Assert.assertNull(service); + assertNull(service); } @Test public void testGetVfModuleByModelInvariantUUIDAndModelVersion() { VfModule vfModule = client.getVfModuleByModelInvariantUUIDAndModelVersion("78ca26d0-246d-11e7-93ae-92361f002671", "2"); - Assert.assertNotNull(vfModule); - Assert.assertNotNull(vfModule.getModelVersion()); - Assert.assertNotNull(vfModule.getModelInvariantUUID()); - Assert.assertEquals("vSAMP10aDEV::base::module-0", vfModule.getModelName()); - Assert.assertEquals("vSAMP10a DEV Base", vfModule.getDescription()); + assertNotNull(vfModule); + assertNotNull(vfModule.getModelVersion()); + assertNotNull(vfModule.getModelInvariantUUID()); + assertEquals("vSAMP10aDEV::base::module-0", vfModule.getModelName()); + assertEquals("vSAMP10a DEV Base", vfModule.getDescription()); } @Test public void testGetVfModuleByModelInvariantUUIDAndModelVersionNotFound() { VfModule vfModule = client.getVfModuleByModelInvariantUUIDAndModelVersion(UUID.randomUUID().toString(), "2"); - Assert.assertNull(vfModule); + assertNull(vfModule); } @Test public void testGetServiceByModelInvariantUUIDOrderByModelVersionDesc() { List<Service> serviceList = client.getServiceByModelInvariantUUIDOrderByModelVersionDesc("9647dfc4-2083-11e7-93ae-92361f002671"); - Assert.assertFalse(serviceList.isEmpty()); - Assert.assertEquals(2, serviceList.size()); + assertFalse(serviceList.isEmpty()); + assertEquals(2, serviceList.size()); Service service = serviceList.get(0); - Assert.assertEquals("2.0", service.getModelVersion()); + assertEquals("2.0", service.getModelVersion()); } @Test public void testGetServiceByModelInvariantUUIDOrderByModelVersionDescNotFound() { List<Service> serviceList = client.getServiceByModelInvariantUUIDOrderByModelVersionDesc(UUID.randomUUID().toString()); - Assert.assertTrue(serviceList.isEmpty()); + assertTrue(serviceList.isEmpty()); } @Test public void testGetVfModuleByModelInvariantUUIDOrderByModelVersionDesc() { List<VfModule> moduleList = client.getVfModuleByModelInvariantUUIDOrderByModelVersionDesc("78ca26d0-246d-11e7-93ae-92361f002671"); - Assert.assertFalse(moduleList.isEmpty()); - Assert.assertEquals(2, moduleList.size()); + assertFalse(moduleList.isEmpty()); + assertEquals(2, moduleList.size()); VfModule module = moduleList.get(0); - Assert.assertEquals("vSAMP10a DEV Base", module.getDescription()); + assertEquals("vSAMP10a DEV Base", module.getDescription()); } @Test @@ -454,20 +450,20 @@ public class CatalogDbClientTest extends CatalogDbAdapterBaseTest { cloudSite.setIdentityService(cloudIdentity); localClient.postCloudSite(cloudSite); CloudSite getCloudSite = this.client.getCloudSite("MTN6"); - Assert.assertNotNull(getCloudSite); - Assert.assertNotNull(getCloudSite.getIdentityService()); - Assert.assertEquals("TESTCLLI", getCloudSite.getClli()); - Assert.assertEquals("regionId", getCloudSite.getRegionId()); - Assert.assertEquals("RANDOMID", getCloudSite.getIdentityServiceId()); + assertNotNull(getCloudSite); + assertNotNull(getCloudSite.getIdentityService()); + assertEquals("TESTCLLI", getCloudSite.getClli()); + assertEquals("regionId", getCloudSite.getRegionId()); + assertEquals("RANDOMID", getCloudSite.getIdentityServiceId()); } @Test public void testGetHomingInstance() { HomingInstance homingInstance = client.getHomingInstance("5df8b6de-2083-11e7-93ae-92361f232671"); - Assert.assertNotNull(homingInstance); - Assert.assertNotNull(homingInstance.getCloudOwner()); - Assert.assertNotNull(homingInstance.getCloudRegionId()); - Assert.assertNotNull(homingInstance.getOofDirectives()); + assertNotNull(homingInstance); + assertNotNull(homingInstance.getCloudOwner()); + assertNotNull(homingInstance.getCloudRegionId()); + assertNotNull(homingInstance.getOofDirectives()); } @Test @@ -491,43 +487,43 @@ public class CatalogDbClientTest extends CatalogDbAdapterBaseTest { + "\"id\": \"vsink\"\n" + "}\n" + "]\n" + "}"); localClient.postHomingInstance(homingInstance); HomingInstance getHomingInstance = this.client.getHomingInstance("5df8d6be-2083-11e7-93ae-92361f232671"); - Assert.assertNotNull(getHomingInstance); - Assert.assertNotNull(getHomingInstance.getCloudRegionId()); - Assert.assertNotNull(getHomingInstance.getCloudOwner()); - Assert.assertEquals("CloudOwner-1", getHomingInstance.getCloudOwner()); - Assert.assertEquals("CloudRegionOne", getHomingInstance.getCloudRegionId()); + assertNotNull(getHomingInstance); + assertNotNull(getHomingInstance.getCloudRegionId()); + assertNotNull(getHomingInstance.getCloudOwner()); + assertEquals("CloudOwner-1", getHomingInstance.getCloudOwner()); + assertEquals("CloudRegionOne", getHomingInstance.getCloudRegionId()); } @Test public void testGetServiceByModelName() { Service service = client.getServiceByModelName("MSOTADevInfra_Test_Service"); - Assert.assertNotNull(service); - Assert.assertNotNull(service.getModelVersion()); - Assert.assertNotNull(service.getModelInvariantUUID()); - Assert.assertEquals("MSOTADevInfra_Test_Service", service.getModelName()); - Assert.assertEquals("NA", service.getServiceRole()); + assertNotNull(service); + assertNotNull(service.getModelVersion()); + assertNotNull(service.getModelInvariantUUID()); + assertEquals("MSOTADevInfra_Test_Service", service.getModelName()); + assertEquals("NA", service.getServiceRole()); } @Test public void testGetServiceByModelNameNotFound() { Service service = client.getServiceByModelName("Not_Found"); - Assert.assertNull(service); + assertNull(service); } @Test public void testGetServiceByModelUUID() { Service service = client.getServiceByModelUUID("5df8b6de-2083-11e7-93ae-92361f002679"); - Assert.assertNotNull(service); - Assert.assertNotNull(service.getModelVersion()); - Assert.assertNotNull(service.getModelInvariantUUID()); - Assert.assertEquals("5df8b6de-2083-11e7-93ae-92361f002679", service.getModelUUID()); - Assert.assertEquals("NA", service.getServiceRole()); + assertNotNull(service); + assertNotNull(service.getModelVersion()); + assertNotNull(service.getModelInvariantUUID()); + assertEquals("5df8b6de-2083-11e7-93ae-92361f002679", service.getModelUUID()); + assertEquals("NA", service.getServiceRole()); } @Test public void testGetServiceByModelUUIDNotFound() { Service service = client.getServiceByModelUUID("Not_Found"); - Assert.assertNull(service); + assertNull(service); } @Test @@ -539,53 +535,52 @@ public class CatalogDbClientTest extends CatalogDbAdapterBaseTest { northBoundRequest.setCloudOwner("my-custom-cloud-owner"); client.getNorthBoundRequestByActionAndIsALaCarteAndRequestScopeAndCloudOwner("createService", "service", true, "my-custom-cloud-owner"); - Assert.assertNotNull(northBoundRequest); - Assert.assertEquals("createService", northBoundRequest.getAction()); - Assert.assertEquals("service", northBoundRequest.getRequestScope()); - Assert.assertEquals(true, northBoundRequest.getIsAlacarte()); - Assert.assertEquals("my-custom-cloud-owner", northBoundRequest.getCloudOwner()); + assertNotNull(northBoundRequest); + assertEquals("createService", northBoundRequest.getAction()); + assertEquals("service", northBoundRequest.getRequestScope()); + assertEquals(true, northBoundRequest.getIsAlacarte()); + assertEquals("my-custom-cloud-owner", northBoundRequest.getCloudOwner()); } @Test public void testFindServiceRecipeByActionAndServiceModelUUID() { ServiceRecipe serviceRecipe = client.findServiceRecipeByActionAndServiceModelUUID("createInstance", "4694a55f-58b3-4f17-92a5-796d6f5ffd0d"); - Assert.assertNotNull(serviceRecipe); - Assert.assertNotNull(serviceRecipe.getServiceModelUUID()); - Assert.assertNotNull(serviceRecipe.getAction()); - Assert.assertEquals("/mso/async/services/CreateGenericALaCarteServiceInstance", - serviceRecipe.getOrchestrationUri()); - Assert.assertEquals("MSOTADevInfra aLaCarte", serviceRecipe.getDescription()); + assertNotNull(serviceRecipe); + assertNotNull(serviceRecipe.getServiceModelUUID()); + assertNotNull(serviceRecipe.getAction()); + assertEquals("/mso/async/services/CreateGenericALaCarteServiceInstance", serviceRecipe.getOrchestrationUri()); + assertEquals("MSOTADevInfra aLaCarte", serviceRecipe.getDescription()); } @Test public void testFindServiceRecipeByActionAndServiceModelUUIDNotFound() { ServiceRecipe serviceRecipe = client.findServiceRecipeByActionAndServiceModelUUID("not_found", "5df8b6de-2083-11e7-93ae-test"); - Assert.assertNull(serviceRecipe); + assertNull(serviceRecipe); } @Test public void testFindExternalToInternalServiceByServiceName() { ExternalServiceToInternalService externalServiceToInternalService = client.findExternalToInternalServiceByServiceName("MySpecialServiceName"); - Assert.assertNotNull(externalServiceToInternalService); - Assert.assertNotNull(externalServiceToInternalService.getServiceName()); - Assert.assertNotNull(externalServiceToInternalService.getServiceModelUUID()); - Assert.assertEquals("MySpecialServiceName", externalServiceToInternalService.getServiceName()); + assertNotNull(externalServiceToInternalService); + assertNotNull(externalServiceToInternalService.getServiceName()); + assertNotNull(externalServiceToInternalService.getServiceModelUUID()); + assertEquals("MySpecialServiceName", externalServiceToInternalService.getServiceName()); } @Test public void testFindExternalToInternalServiceByServiceNameNotFound() { ExternalServiceToInternalService externalServiceToInternalService = client.findExternalToInternalServiceByServiceName("Not_Found"); - Assert.assertNull(externalServiceToInternalService); + assertNull(externalServiceToInternalService); } @Test public void getPnfResourceByModelUUID_validUuid_expectedOutput() { PnfResource pnfResource = client.getPnfResourceByModelUUID("ff2ae348-214a-11e7-93ae-92361f002680"); - Assert.assertNotNull(pnfResource); + assertNotNull(pnfResource); assertEquals("PNFResource modelUUID", "ff2ae348-214a-11e7-93ae-92361f002680", pnfResource.getModelUUID()); assertEquals("PNFResource modelInvariantUUID", "2fff5b20-214b-11e7-93ae-92361f002680", pnfResource.getModelInvariantUUID()); @@ -596,7 +591,7 @@ public class CatalogDbClientTest extends CatalogDbAdapterBaseTest { @Test public void getPnfResourceByModelUUID_invalidUuid_NullOutput() { PnfResource pnfResource = client.getPnfResourceByModelUUID(UUID.randomUUID().toString()); - Assert.assertNull(pnfResource); + assertNull(pnfResource); } @Test @@ -620,7 +615,7 @@ public class CatalogDbClientTest extends CatalogDbAdapterBaseTest { public void getPnfResourceCustomizationByModelCustomizationUUID_invalidUuid_nullOutput() { PnfResourceCustomization pnfResourceCustomization = client.getPnfResourceCustomizationByModelCustomizationUUID(UUID.randomUUID().toString()); - Assert.assertNull(pnfResourceCustomization); + assertNull(pnfResourceCustomization); } @Test @@ -651,6 +646,53 @@ public class CatalogDbClientTest extends CatalogDbAdapterBaseTest { } @Test + public void testGetServiceTopologyById() throws Exception { + org.onap.so.rest.catalog.beans.Service serviceByID = + client.getServiceModelInformation("5df8b6de-2083-11e7-93ae-92361f002671", "2"); + assertNotNull(serviceByID); + assertEquals("MSOTADevInfra_vSAMP10a_Service", serviceByID.getModelName()); + assertEquals("NA", serviceByID.getServiceType()); + assertEquals("NA", serviceByID.getServiceRole()); + } + + @Test + public void testGetServices() throws Exception { + List<org.onap.so.rest.catalog.beans.Service> services = client.getServices(); + assertEquals(false, services.isEmpty()); + } + + @Test + public void testVnf() throws Exception { + org.onap.so.rest.catalog.beans.Vnf vnf = client.getVnfModelInformation("5df8b6de-2083-11e7-93ae-92361f002671", + "68dc9a92-214c-11e7-93ae-92361f002671", "0"); + assertNotNull(vnf); + assertEquals("vSAMP10a", vnf.getModelName()); + assertEquals(false, vnf.getNfDataValid()); + assertEquals("vSAMP", vnf.getNfFunction()); + assertEquals("vSAMP", vnf.getNfNamingCode()); + assertEquals("vSAMP", vnf.getNfRole()); + assertEquals("vSAMP", vnf.getNfType()); + + vnf.setNfDataValid(true); + vnf.setNfFunction("nfFunction"); + vnf.setNfRole("nfRole"); + vnf.setNfType("nfType"); + vnf.setNfNamingCode("nfNamingCode"); + + client.updateVnf("5df8b6de-2083-11e7-93ae-92361f002671", vnf); + vnf = client.getVnfModelInformation("5df8b6de-2083-11e7-93ae-92361f002671", + "68dc9a92-214c-11e7-93ae-92361f002671", "0"); + assertEquals("vSAMP10a", vnf.getModelName()); + assertEquals(true, vnf.getNfDataValid()); + assertEquals("nfFunction", vnf.getNfFunction()); + assertEquals("nfNamingCode", vnf.getNfNamingCode()); + assertEquals("nfRole", vnf.getNfRole()); + assertEquals("nfType", vnf.getNfType()); + + + } + + @Test public void getWorkflowByArtifactUUID_validUuid_expectedOutput() { Workflow workflow = client.findWorkflowByArtifactUUID("5b0c4322-643d-4c9f-b184-4516049e99b1"); assertEquals("artifactName", "testingWorkflow.bpmn", workflow.getArtifactName()); @@ -659,7 +701,7 @@ public class CatalogDbClientTest extends CatalogDbAdapterBaseTest { @Test public void getWorkflowByArtifactUUID_invalidUuid_nullOutput() { Workflow workflow = client.findWorkflowByArtifactUUID(UUID.randomUUID().toString()); - Assert.assertNull(workflow); + assertNull(workflow); } @Test @@ -674,7 +716,7 @@ public class CatalogDbClientTest extends CatalogDbAdapterBaseTest { @Test public void getWorkflowByModelUUID_invalidUuid_nullOutput() { Workflow workflow = client.findWorkflowByArtifactUUID(UUID.randomUUID().toString()); - Assert.assertNull(workflow); + assertNull(workflow); } @Test @@ -689,7 +731,15 @@ public class CatalogDbClientTest extends CatalogDbAdapterBaseTest { @Test public void getWorkflowBySource_invalidSource_nullOutput() { List<Workflow> workflow = client.findWorkflowBySource("abc"); - Assert.assertNull(workflow); + assertNull(workflow); } + @Test + public void getCloudSites() { + List<CloudSite> cloudSites = client.getCloudSites(); + assertNotNull(cloudSites); + assertNotEquals(0, cloudSites.size()); + } + + } diff --git a/adapters/mso-catalog-db-adapter/src/test/resources/ExpectedService.json b/adapters/mso-catalog-db-adapter/src/test/resources/ExpectedService.json index cc5145f0e3..2dc83c8963 100644 --- a/adapters/mso-catalog-db-adapter/src/test/resources/ExpectedService.json +++ b/adapters/mso-catalog-db-adapter/src/test/resources/ExpectedService.json @@ -23,6 +23,7 @@ "toscaNodeType": "toscaNodeType", "nfFunction": "nfFunction", "nfRole": "nfRole", + "nfType": "nfType", "nfNamingCode": "nfNamingCode", "multiStageDesign": "multiStageDesign", "orchestrationMode": "orchestrationMode", diff --git a/adapters/mso-openstack-adapters/pom.xml b/adapters/mso-openstack-adapters/pom.xml index 7ffcd8308c..f0c066aa05 100644 --- a/adapters/mso-openstack-adapters/pom.xml +++ b/adapters/mso-openstack-adapters/pom.xml @@ -153,6 +153,9 @@ <executions> <execution> <id>original</id> + <configuration> + <skip>false</skip> + </configuration> </execution> </executions> </plugin> @@ -243,12 +246,12 @@ <dependency> <groupId>org.pacesys</groupId> <artifactId>openstack4j-core</artifactId> - <version>3.1.0</version> + <version>3.2.0</version> </dependency> <dependency> <groupId>org.pacesys.openstack4j.connectors</groupId> <artifactId>openstack4j-httpclient</artifactId> - <version>3.1.0</version> + <version>3.2.0</version> </dependency> <dependency> diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AbstractAuditService.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AbstractAuditService.java index 8edce124ec..0c05df959f 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AbstractAuditService.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AbstractAuditService.java @@ -22,19 +22,18 @@ package org.onap.so.adapters.audit; import java.util.Optional; -import org.camunda.bpm.client.task.ExternalTask; -import org.onap.logging.ref.slf4j.ONAPLogConstants; import org.onap.so.objects.audit.AAIObjectAudit; import org.onap.so.objects.audit.AAIObjectAuditList; +import org.onap.so.utils.ExternalTaskUtils; +import org.onap.logging.filter.base.ONAPComponents; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.slf4j.MDC; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; @Component -public abstract class AbstractAuditService { +public abstract class AbstractAuditService extends ExternalTaskUtils { private static final Logger logger = LoggerFactory.getLogger(AbstractAuditService.class); @@ -81,23 +80,4 @@ public abstract class AbstractAuditService { return false; } } - - protected String[] getRetrySequence() { - return env.getProperty("mso.workflow.topics.retrySequence", String[].class); - } - - protected void setupMDC(ExternalTask externalTask) { - logger.info(ONAPLogConstants.Markers.ENTRY, "Entering"); - String msoRequestId = externalTask.getVariable("mso-request-id"); - if (msoRequestId != null && !msoRequestId.isEmpty()) { - MDC.put(ONAPLogConstants.MDCs.REQUEST_ID, msoRequestId); - } - MDC.put(ONAPLogConstants.MDCs.SERVICE_NAME, externalTask.getTopicName()); - } - - protected long calculateRetryDelay(int currentRetries) { - int retrySequence = getRetrySequence().length - currentRetries; - long retryMultiplier = Long.parseLong(env.getProperty("mso.workflow.topics.retryMultiplier", "6000")); - return Integer.parseInt(getRetrySequence()[retrySequence]) * retryMultiplier; - } } diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditCreateStackService.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditCreateStackService.java index 1e5b6de857..43b362cbaf 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditCreateStackService.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditCreateStackService.java @@ -30,11 +30,11 @@ import org.camunda.bpm.client.task.ExternalTaskService; import org.onap.logging.ref.slf4j.ONAPLogConstants; import org.onap.so.audit.beans.AuditInventory; import org.onap.so.client.graphinventory.GraphInventoryCommonObjectMapperProvider; +import org.onap.so.externaltasks.logging.AuditMDCSetup; import org.onap.so.objects.audit.AAIObjectAuditList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; @Component @@ -46,16 +46,16 @@ public class AuditCreateStackService extends AbstractAuditService { public HeatStackAudit heatStackAudit; @Autowired - public Environment environment; + private AuditMDCSetup mdcSetup; protected void executeExternalTask(ExternalTask externalTask, ExternalTaskService externalTaskService) { - setupMDC(externalTask); + mdcSetup.setupMDC(externalTask); AuditInventory auditInventory = externalTask.getVariable("auditInventory"); Map<String, Object> variables = new HashMap<>(); boolean success = false; try { - logger.info("Executing External Task Audit Inventory, Retry Number: {} \n {}", auditInventory, - externalTask.getRetries()); + Integer retryCount = externalTask.getRetries(); + logger.info("Executing External Task Audit Inventory, Retry Number: {} \n {}", auditInventory, retryCount); Optional<AAIObjectAuditList> auditListOpt = heatStackAudit.auditHeatStack(auditInventory.getCloudRegion(), auditInventory.getCloudOwner(), auditInventory.getTenantId(), auditInventory.getHeatStackName()); if (auditListOpt.isPresent()) { @@ -69,29 +69,35 @@ public class AuditCreateStackService extends AbstractAuditService { logger.error("Error during audit of stack", e); } variables.put("auditIsSuccessful", success); + mdcSetup.setElapsedTime(); + String externalTaskId = externalTask.getId(); if (success) { externalTaskService.complete(externalTask, variables); - logger.debug("The External Task Id: {} Successful", externalTask.getId()); + mdcSetup.setResponseCode(ONAPLogConstants.ResponseStatus.COMPLETE.toString()); + logger.debug("The External Task Id: {} Successful", externalTaskId); logger.info(ONAPLogConstants.Markers.EXIT, "Exiting"); + mdcSetup.clearClientMDCs(); } else { - if (externalTask.getRetries() == null) { + Integer retryCount = externalTask.getRetries(); + if (retryCount == null) { logger.debug("The External Task Id: {} Failed, Setting Retries to Default Start Value: {}", - externalTask.getId(), getRetrySequence().length); + externalTaskId, getRetrySequence().length); externalTaskService.handleFailure(externalTask, UNABLE_TO_FIND_ALL_V_SERVERS_AND_L_INTERACES_IN_A_AI, UNABLE_TO_FIND_ALL_V_SERVERS_AND_L_INTERACES_IN_A_AI, getRetrySequence().length, 10000); - } else if (externalTask.getRetries() != null && externalTask.getRetries() - 1 == 0) { - logger.debug("The External Task Id: {} Failed, All Retries Exhausted", externalTask.getId()); + } else if (retryCount == 1) { externalTaskService.complete(externalTask, variables); + mdcSetup.setResponseCode(ONAPLogConstants.ResponseStatus.ERROR.toString()); + logger.debug("The External Task Id: {} Failed, All Retries Exhausted", externalTaskId); logger.info(ONAPLogConstants.Markers.EXIT, "Exiting"); + mdcSetup.clearClientMDCs(); } else { logger.debug("The External Task Id: {} Failed, Decrementing Retries: {} , Retry Delay: ", - externalTask.getId(), externalTask.getRetries() - 1, - calculateRetryDelay(externalTask.getRetries())); + externalTaskId, retryCount - 1, calculateRetryDelay(retryCount)); externalTaskService.handleFailure(externalTask, UNABLE_TO_FIND_ALL_V_SERVERS_AND_L_INTERACES_IN_A_AI, - UNABLE_TO_FIND_ALL_V_SERVERS_AND_L_INTERACES_IN_A_AI, externalTask.getRetries() - 1, - calculateRetryDelay(externalTask.getRetries())); + UNABLE_TO_FIND_ALL_V_SERVERS_AND_L_INTERACES_IN_A_AI, retryCount - 1, + calculateRetryDelay(retryCount)); } - logger.debug("The External Task Id: {} Failed", externalTask.getId()); + logger.debug("The External Task Id: {} Failed", externalTaskId); } } diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditDeleteStackService.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditDeleteStackService.java index 0aa4f9bdc3..da5e8bb3a2 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditDeleteStackService.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditDeleteStackService.java @@ -28,6 +28,7 @@ import org.camunda.bpm.client.task.ExternalTaskService; import org.onap.logging.ref.slf4j.ONAPLogConstants; import org.onap.so.audit.beans.AuditInventory; import org.onap.so.client.graphinventory.GraphInventoryCommonObjectMapperProvider; +import org.onap.so.externaltasks.logging.AuditMDCSetup; import org.onap.so.objects.audit.AAIObjectAuditList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -44,6 +45,9 @@ public class AuditDeleteStackService extends AbstractAuditService { protected HeatStackAudit heatStackAudit; @Autowired + private AuditMDCSetup mdcSetup; + + @Autowired protected AuditVServer auditVservers; @Autowired @@ -53,12 +57,13 @@ public class AuditDeleteStackService extends AbstractAuditService { protected Environment env; protected void executeExternalTask(ExternalTask externalTask, ExternalTaskService externalTaskService) { - setupMDC(externalTask); + mdcSetup.setupMDC(externalTask); AuditInventory auditInventory = externalTask.getVariable("auditInventory"); Map<String, Object> variables = new HashMap<>(); boolean success = false; try { - logger.info("Executing External Task Delete Audit Inventory. Retry Number: {}", externalTask.getRetries()); + Integer retryCount = externalTask.getRetries(); + logger.info("Executing External Task Delete Audit Inventory. Retry Number: {}", retryCount); Optional<AAIObjectAuditList> auditListOpt = auditDataService.getStackDataFromRequestDb(auditInventory); if (auditListOpt.isPresent()) { auditVservers.auditVservers(auditListOpt.get()); @@ -77,29 +82,35 @@ public class AuditDeleteStackService extends AbstractAuditService { logger.error("Error during audit of stack", e); } variables.put("auditIsSuccessful", success); + mdcSetup.setElapsedTime(); + String externalTaskId = externalTask.getId(); if (success) { externalTaskService.complete(externalTask, variables); - logger.debug("The External Task Id: {} Successful", externalTask.getId()); + mdcSetup.setResponseCode(ONAPLogConstants.ResponseStatus.COMPLETE.toString()); + logger.debug("The External Task Id: {} Successful", externalTaskId); logger.info(ONAPLogConstants.Markers.EXIT, "Exiting"); + mdcSetup.clearClientMDCs(); } else { - if (externalTask.getRetries() == null) { + Integer retryCount = externalTask.getRetries(); + if (retryCount == null) { logger.debug("The External Task Id: {} Failed, Setting Retries to Default Start Value: {}", - externalTask.getId(), getRetrySequence().length); + externalTaskId, getRetrySequence().length); externalTaskService.handleFailure(externalTask, UNABLE_TO_FIND_ALL_V_SERVERS_AND_L_INTERACES_IN_A_AI, UNABLE_TO_FIND_ALL_V_SERVERS_AND_L_INTERACES_IN_A_AI, getRetrySequence().length, 10000); - } else if (externalTask.getRetries() != null && externalTask.getRetries() - 1 == 0) { - logger.debug("The External Task Id: {} Failed, All Retries Exhausted", externalTask.getId()); + } else if (retryCount == 1) { externalTaskService.complete(externalTask, variables); + mdcSetup.setResponseCode(ONAPLogConstants.ResponseStatus.ERROR.toString()); + logger.debug("The External Task Id: {} Failed, All Retries Exhausted", externalTaskId); logger.info(ONAPLogConstants.Markers.EXIT, "Exiting"); + mdcSetup.clearClientMDCs(); } else { logger.debug("The External Task Id: {} Failed, Decrementing Retries: {} , Retry Delay: ", - externalTask.getId(), externalTask.getRetries() - 1, - calculateRetryDelay(externalTask.getRetries())); + externalTaskId, retryCount - 1, calculateRetryDelay(retryCount)); externalTaskService.handleFailure(externalTask, UNABLE_TO_FIND_ALL_V_SERVERS_AND_L_INTERACES_IN_A_AI, - UNABLE_TO_FIND_ALL_V_SERVERS_AND_L_INTERACES_IN_A_AI, externalTask.getRetries() - 1, - calculateRetryDelay(externalTask.getRetries())); + UNABLE_TO_FIND_ALL_V_SERVERS_AND_L_INTERACES_IN_A_AI, retryCount - 1, + calculateRetryDelay(retryCount)); } - logger.debug("The External Task Id: {} Failed", externalTask.getId()); + logger.debug("The External Task Id: {} Failed", externalTaskId); } } diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditQueryStackService.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditQueryStackService.java index 2ef7d5b325..8699f8b953 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditQueryStackService.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditQueryStackService.java @@ -7,6 +7,7 @@ import org.camunda.bpm.client.task.ExternalTask; import org.camunda.bpm.client.task.ExternalTaskService; import org.onap.logging.ref.slf4j.ONAPLogConstants; import org.onap.so.audit.beans.AuditInventory; +import org.onap.so.externaltasks.logging.AuditMDCSetup; import org.onap.so.objects.audit.AAIObjectAuditList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,47 +23,56 @@ public class AuditQueryStackService extends AbstractAuditService { protected HeatStackAudit heatStackAudit; @Autowired + private AuditMDCSetup mdcSetup; + + @Autowired protected AuditDataService auditDataService; protected void executeExternalTask(ExternalTask externalTask, ExternalTaskService externalTaskService) { - setupMDC(externalTask); + mdcSetup.setupMDC(externalTask); AuditInventory auditInventory = externalTask.getVariable("auditInventory"); boolean success = false; Map<String, Object> variables = new HashMap<>(); try { + Integer retryCount = externalTask.getRetries(); logger.info("Executing External Task Query Audit Inventory. Audit Inventory: {} \n Retry Number: {}", - auditInventory.toString(), externalTask.getRetries()); + auditInventory.toString(), retryCount); Optional<AAIObjectAuditList> auditList = heatStackAudit.queryHeatStack(auditInventory.getCloudOwner(), auditInventory.getCloudRegion(), auditInventory.getTenantId(), auditInventory.getHeatStackName()); if (auditList.isPresent()) { + mdcSetup.setResponseCode(ONAPLogConstants.ResponseStatus.COMPLETE.toString()); success = true; auditDataService.writeStackDataToRequestDb(auditInventory, auditList.get()); } + mdcSetup.setElapsedTime(); + String externalTaskId = externalTask.getId(); if (success) { externalTaskService.complete(externalTask, variables); - logger.debug("The External Task {} was Successful", externalTask.getId()); + mdcSetup.setResponseCode(ONAPLogConstants.ResponseStatus.COMPLETE.toString()); + logger.debug("The External Task {} was Successful", externalTaskId); logger.info(ONAPLogConstants.Markers.EXIT, "Exiting"); + mdcSetup.clearClientMDCs(); } else { - if (externalTask.getRetries() == null) { + if (retryCount == null) { logger.debug("The External Task {} Failed. Setting Retries to Default Start Value: {}", - externalTask.getId(), getRetrySequence().length); + externalTaskId, getRetrySequence().length); externalTaskService.handleFailure(externalTask, UNABLE_TO_FIND_V_SERVERS_IN_OPENSTACK, UNABLE_TO_FIND_V_SERVERS_IN_OPENSTACK, getRetrySequence().length, 10000); - } else if (externalTask.getRetries() != null && externalTask.getRetries() - 1 == 0) { - logger.debug("The External Task {} Failed. All Retries Exhausted", externalTask.getId()); + } else if (retryCount == 1) { externalTaskService.complete(externalTask, variables); + mdcSetup.setResponseCode(ONAPLogConstants.ResponseStatus.ERROR.toString()); + logger.debug("The External Task {} Failed. All Retries Exhausted", externalTaskId); logger.info(ONAPLogConstants.Markers.EXIT, "Exiting"); + mdcSetup.clearClientMDCs(); } else { logger.debug("The External Task {} Failed. Decrementing Retries to {} , Retry Delay: ", - externalTask.getId(), externalTask.getRetries() - 1, - calculateRetryDelay(externalTask.getRetries())); + externalTaskId, retryCount - 1, calculateRetryDelay(retryCount)); externalTaskService.handleFailure(externalTask, UNABLE_TO_FIND_V_SERVERS_IN_OPENSTACK, - UNABLE_TO_FIND_V_SERVERS_IN_OPENSTACK, externalTask.getRetries() - 1, - calculateRetryDelay(externalTask.getRetries())); + UNABLE_TO_FIND_V_SERVERS_IN_OPENSTACK, retryCount - 1, calculateRetryDelay(retryCount)); } - logger.debug("The External Task {} Failed", externalTask.getId()); + logger.debug("The External Task {} Failed", externalTaskId); } } catch (Exception e) { logger.error("Error during audit query of stack", e); diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditStackService.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditStackService.java index 6a42456715..fb7e925d88 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditStackService.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditStackService.java @@ -20,13 +20,9 @@ package org.onap.so.adapters.audit; -import java.security.GeneralSecurityException; import javax.annotation.PostConstruct; import org.camunda.bpm.client.ExternalTaskClient; -import org.camunda.bpm.client.backoff.ExponentialBackoffStrategy; -import org.camunda.bpm.client.interceptor.ClientRequestInterceptor; -import org.camunda.bpm.client.interceptor.auth.BasicAuthProvider; -import org.onap.so.utils.CryptoUtils; +import org.onap.so.utils.ExternalTaskServiceUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -56,10 +52,13 @@ public class AuditStackService { @Autowired private AuditQueryStackService auditQueryStack; + @Autowired + private ExternalTaskServiceUtils externalTaskServiceUtils; + @PostConstruct - public void auditAddAAIInventory() { - for (int i = 0; i < getMaxClients(); i++) { - ExternalTaskClient client = createExternalTaskClient(); + public void auditAddAAIInventory() throws Exception { + for (int i = 0; i < externalTaskServiceUtils.getMaxClients(); i++) { + ExternalTaskClient client = externalTaskServiceUtils.createExternalTaskClient(); client.subscribe("InventoryAddAudit") .lockDuration(Long.parseLong(env.getProperty("mso.audit.lock-time", DEFAULT_AUDIT_LOCK_TIME))) .handler(auditCreateStack::executeExternalTask).open(); @@ -67,9 +66,9 @@ public class AuditStackService { } @PostConstruct - public void auditDeleteAAIInventory() { - for (int i = 0; i < getMaxClients(); i++) { - ExternalTaskClient client = createExternalTaskClient(); + public void auditDeleteAAIInventory() throws Exception { + for (int i = 0; i < externalTaskServiceUtils.getMaxClients(); i++) { + ExternalTaskClient client = externalTaskServiceUtils.createExternalTaskClient(); client.subscribe("InventoryDeleteAudit") .lockDuration(Long.parseLong(env.getProperty("mso.audit.lock-time", DEFAULT_AUDIT_LOCK_TIME))) .handler(auditDeleteStack::executeExternalTask).open(); @@ -77,35 +76,13 @@ public class AuditStackService { } @PostConstruct - public void auditQueryInventory() { - for (int i = 0; i < getMaxClients(); i++) { - ExternalTaskClient client = createExternalTaskClient(); + public void auditQueryInventory() throws Exception { + for (int i = 0; i < externalTaskServiceUtils.getMaxClients(); i++) { + ExternalTaskClient client = externalTaskServiceUtils.createExternalTaskClient(); client.subscribe("InventoryQueryAudit") .lockDuration(Long.parseLong(env.getProperty("mso.audit.lock-time", DEFAULT_AUDIT_LOCK_TIME))) .handler(auditQueryStack::executeExternalTask).open(); } } - protected ExternalTaskClient createExternalTaskClient() { - ClientRequestInterceptor interceptor = createClientRequestInterceptor(); - return ExternalTaskClient.create().baseUrl(env.getRequiredProperty("mso.workflow.endpoint")).maxTasks(1) - .addInterceptor(interceptor).asyncResponseTimeout(120000) - .backoffStrategy(new ExponentialBackoffStrategy(0, 0, 0)).build(); - } - - protected ClientRequestInterceptor createClientRequestInterceptor() { - String auth = ""; - try { - auth = CryptoUtils.decrypt(env.getRequiredProperty("mso.auth"), env.getRequiredProperty("mso.msoKey")); - } catch (IllegalStateException | GeneralSecurityException e) { - logger.error("Error Decrypting Password", e); - } - return new BasicAuthProvider(env.getRequiredProperty("mso.config.cadi.aafId"), auth); - } - - protected int getMaxClients() { - return Integer.parseInt(env.getProperty("workflow.topics.maxClients", DEFAULT_MAX_CLIENTS_FOR_TOPIC)); - } - - } diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditVServer.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditVServer.java index 14d83b3b06..35008b6120 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditVServer.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/audit/AuditVServer.java @@ -84,7 +84,7 @@ public class AuditVServer extends AbstractAudit { try { logger.debug("Vserver to Audit: {}", objectMapper.getMapper().writeValueAsString(vserver)); } catch (JsonProcessingException e) { - logger.error("Json parse exception: {}", e.getMessage()); + logger.error("Json parse exception: ", e); } }); diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/inventory/create/CreateInventoryService.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/inventory/create/CreateInventoryService.java index 49a9e7e171..5261f8ae19 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/inventory/create/CreateInventoryService.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/inventory/create/CreateInventoryService.java @@ -20,15 +20,9 @@ package org.onap.so.adapters.inventory.create; -import java.security.GeneralSecurityException; import javax.annotation.PostConstruct; import org.camunda.bpm.client.ExternalTaskClient; -import org.camunda.bpm.client.backoff.ExponentialBackoffStrategy; -import org.camunda.bpm.client.interceptor.ClientRequestInterceptor; -import org.camunda.bpm.client.interceptor.auth.BasicAuthProvider; -import org.onap.so.utils.CryptoUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.onap.so.utils.ExternalTaskServiceUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Profile; import org.springframework.core.env.Environment; @@ -38,27 +32,19 @@ import org.springframework.stereotype.Component; @Profile("!test") public class CreateInventoryService { - private static final Logger logger = LoggerFactory.getLogger(CreateInventoryService.class); - @Autowired public Environment env; @Autowired private CreateInventoryTask createInventory; + @Autowired + private ExternalTaskServiceUtils externalTaskServiceUtils; + @PostConstruct - public void auditAAIInventory() { - String auth = ""; - try { - auth = CryptoUtils.decrypt(env.getRequiredProperty("mso.auth"), env.getRequiredProperty("mso.msoKey")); - } catch (IllegalStateException | GeneralSecurityException e) { - logger.error("Error Decrypting Password", e); - } - ClientRequestInterceptor interceptor = - new BasicAuthProvider(env.getRequiredProperty("mso.config.cadi.aafId"), auth); - ExternalTaskClient client = ExternalTaskClient.create() - .baseUrl(env.getRequiredProperty("mso.workflow.endpoint")).maxTasks(1).addInterceptor(interceptor) - .asyncResponseTimeout(120000).backoffStrategy(new ExponentialBackoffStrategy(0, 0, 0)).build(); + public void auditAAIInventory() throws Exception { + + ExternalTaskClient client = externalTaskServiceUtils.createExternalTaskClient(); client.subscribe("InventoryCreate") .lockDuration(Long.parseLong(env.getProperty("mso.audit.lock-time", "60000"))) .handler(createInventory::executeExternalTask).open(); diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/inventory/create/CreateInventoryTask.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/inventory/create/CreateInventoryTask.java index a6c61704ad..3d2d1d2aa3 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/inventory/create/CreateInventoryTask.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/inventory/create/CreateInventoryTask.java @@ -26,16 +26,16 @@ import org.camunda.bpm.client.task.ExternalTask; import org.camunda.bpm.client.task.ExternalTaskService; import org.onap.logging.ref.slf4j.ONAPLogConstants; import org.onap.so.client.graphinventory.GraphInventoryCommonObjectMapperProvider; +import org.onap.so.externaltasks.logging.AuditMDCSetup; import org.onap.so.objects.audit.AAIObjectAuditList; +import org.onap.so.utils.ExternalTaskUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.slf4j.MDC; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; @Component -public class CreateInventoryTask { +public class CreateInventoryTask extends ExternalTaskUtils { private static final String UNABLE_TO_WRITE_ALL_INVENTORY_TO_A_AI = "Unable to write all inventory to A&AI"; @@ -47,24 +47,28 @@ public class CreateInventoryTask { CreateAAIInventory createInventory; @Autowired - public Environment env; + private AuditMDCSetup mdcSetup; protected void executeExternalTask(ExternalTask externalTask, ExternalTaskService externalTaskService) { - setupMDC(externalTask); + mdcSetup.setupMDC(externalTask); boolean success = true; boolean inventoryException = false; String auditInventoryString = externalTask.getVariable("auditInventoryResult"); AAIObjectAuditList auditInventory = null; + String externalTaskId = externalTask.getId(); try { GraphInventoryCommonObjectMapperProvider objectMapper = new GraphInventoryCommonObjectMapperProvider(); auditInventory = objectMapper.getMapper().readValue(auditInventoryString, AAIObjectAuditList.class); } catch (Exception e) { + mdcSetup.setResponseCode(ONAPLogConstants.ResponseStatus.ERROR.toString()); logger.error("Error Parsing Audit Results", e); } + mdcSetup.setElapsedTime(); if (auditInventory != null) { + Integer retryCount = externalTask.getRetries(); try { logger.info("Executing External Task Create Inventory, Retry Number: {} \n {}", auditInventory, - externalTask.getRetries()); + retryCount); createInventory.createInventory(auditInventory); } catch (InventoryException e) { logger.error("Error during inventory of stack", e); @@ -74,58 +78,39 @@ public class CreateInventoryTask { logger.error("Error during inventory of stack", e); success = false; } + mdcSetup.setElapsedTime(); if (success) { externalTaskService.complete(externalTask); - logger.debug("The External Task Id: {} Successful", externalTask.getId()); + mdcSetup.setResponseCode(ONAPLogConstants.ResponseStatus.COMPLETE.toString()); + logger.debug("The External Task Id: {} Successful", externalTaskId); logger.info(ONAPLogConstants.Markers.EXIT, "Exiting"); + mdcSetup.clearClientMDCs(); } else if (inventoryException) { - logger.debug("The External Task Id: {} Failed, Retry not needed", externalTask.getId()); + mdcSetup.setResponseCode(ONAPLogConstants.ResponseStatus.ERROR.toString()); + logger.debug("The External Task Id: {} Failed, Retry not needed", externalTaskId); externalTaskService.handleBpmnError(externalTask, AAI_INVENTORY_FAILURE); } else { - if (externalTask.getRetries() == null) { + if (retryCount == null) { logger.debug("The External Task Id: {} Failed, Setting Retries to Default Start Value: {}", - externalTask.getId(), getRetrySequence().length); + externalTaskId, getRetrySequence().length); externalTaskService.handleFailure(externalTask, UNABLE_TO_WRITE_ALL_INVENTORY_TO_A_AI, UNABLE_TO_WRITE_ALL_INVENTORY_TO_A_AI, getRetrySequence().length, 10000); - } else if (externalTask.getRetries() != null && externalTask.getRetries() - 1 == 0) { - logger.debug("The External Task Id: {} Failed, All Retries Exhausted", externalTask.getId()); + } else if (retryCount != null && retryCount - 1 == 0) { externalTaskService.handleBpmnError(externalTask, AAI_INVENTORY_FAILURE); + mdcSetup.setResponseCode(ONAPLogConstants.ResponseStatus.ERROR.toString()); + logger.debug("The External Task Id: {} Failed, All Retries Exhausted", externalTaskId); logger.info(ONAPLogConstants.Markers.EXIT, "Exiting"); } else { logger.debug("The External Task Id: {} Failed, Decrementing Retries: {} , Retry Delay: ", - externalTask.getId(), externalTask.getRetries() - 1, - calculateRetryDelay(externalTask.getRetries())); + externalTaskId, retryCount - 1, calculateRetryDelay(retryCount)); externalTaskService.handleFailure(externalTask, UNABLE_TO_WRITE_ALL_INVENTORY_TO_A_AI, - UNABLE_TO_WRITE_ALL_INVENTORY_TO_A_AI, externalTask.getRetries() - 1, - calculateRetryDelay(externalTask.getRetries())); + UNABLE_TO_WRITE_ALL_INVENTORY_TO_A_AI, retryCount - 1, calculateRetryDelay(retryCount)); } - logger.debug("The External Task Id: {} Failed", externalTask.getId()); + logger.debug("The External Task Id: {} Failed", externalTaskId); } } else { - logger.debug("The External Task Id: {} Failed, No Audit Results Written", externalTask.getId()); + logger.debug("The External Task Id: {} Failed, No Audit Results Written", externalTaskId); externalTaskService.handleBpmnError(externalTask, AAI_INVENTORY_FAILURE); } } - - private void setupMDC(ExternalTask externalTask) { - try { - logger.info(ONAPLogConstants.Markers.ENTRY, "Entering"); - MDC.put(ONAPLogConstants.MDCs.SERVICE_NAME, externalTask.getTopicName()); - String msoRequestId = externalTask.getVariable("mso-request-id"); - if (msoRequestId != null && !msoRequestId.isEmpty()) - MDC.put(ONAPLogConstants.MDCs.REQUEST_ID, msoRequestId); - } catch (Exception e) { - logger.error("Error in setting up MDC", e); - } - } - - protected long calculateRetryDelay(int currentRetries) { - int retrySequence = getRetrySequence().length - currentRetries; - long retryMultiplier = Long.parseLong(env.getProperty("mso.workflow.topics.retryMultiplier", "6000")); - return Integer.parseInt(getRetrySequence()[retrySequence]) * retryMultiplier; - } - - public String[] getRetrySequence() { - return env.getProperty("mso.workflow.topics.retrySequence", String[].class); - } } diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapterImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapterImpl.java index 4c115271f0..ef04ee9c13 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapterImpl.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/MsoNetworkAdapterImpl.java @@ -24,8 +24,6 @@ package org.onap.so.adapters.network; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -33,7 +31,6 @@ import java.util.Map; import java.util.Optional; import javax.jws.WebService; import javax.xml.ws.Holder; -import org.onap.so.logger.LoggingAnchor; import org.onap.so.adapters.network.beans.ContrailPolicyRef; import org.onap.so.adapters.network.beans.ContrailPolicyRefSeq; import org.onap.so.adapters.network.beans.ContrailSubnet; @@ -51,6 +48,7 @@ import org.onap.so.db.catalog.data.repository.NetworkResourceRepository; import org.onap.so.db.catalog.utils.MavenLikeVersioning; import org.onap.so.entity.MsoRequest; import org.onap.so.logger.ErrorCode; +import org.onap.so.logger.LoggingAnchor; import org.onap.so.logger.MessageEnum; import org.onap.so.openstack.beans.HeatStatus; import org.onap.so.openstack.beans.NetworkInfo; @@ -74,6 +72,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; @Component @Transactional @@ -91,6 +91,7 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { private static final String CREATE_NETWORK_CONTEXT = "CreateNetwork"; private static final String NEUTRON_MODE = "NEUTRON"; private static final String CLOUD_OWNER = "CloudOwner"; + private static final String LOG_DEBUG_MSG = "Got Network definition from Catalog: {}"; private static final Logger logger = LoggerFactory.getLogger(MsoNetworkAdapterImpl.class); @@ -230,7 +231,7 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { } catch (MsoException me) { logger.error( "{} {} Exception while querying network {} for CloudSite {} from Tenant {} from OpenStack ", - MessageEnum.RA_QUERY_NETWORK_EXC, ErrorCode.BusinessProcesssError.getValue(), networkName, + MessageEnum.RA_QUERY_NETWORK_EXC, ErrorCode.BusinessProcessError.getValue(), networkName, cloudSiteId, tenantId, me); me.addContext(CREATE_NETWORK_CONTEXT); throw new NetworkException(me); @@ -292,7 +293,7 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { throw new NetworkException(error, MsoExceptionCategory.INTERNAL); } - logger.debug("Got HEAT Template from DB: {}", heatTemplate.toString()); + logger.debug("Got HEAT Template from DB: {}", heatTemplate); // "Fix" the template if it has CR/LF (getting this from Oracle) String template = heatTemplate.getHeatTemplate(); @@ -309,7 +310,6 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { // First, look up to see if the Network already exists (by name). // For HEAT orchestration of networks, the stack name will always match the network name StackInfo heatStack = null; - long queryNetworkStarttime = System.currentTimeMillis(); try { heatStack = heat.queryStack(cloudSiteId, CLOUD_OWNER, tenantId, networkName); } catch (MsoException me) { @@ -426,7 +426,8 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { if (backout == null) backout = true; heatStack = heat.createStack(cloudSiteId, CLOUD_OWNER, tenantId, networkName, null, template, - stackParams, true, heatTemplate.getTimeoutMinutes(), null, null, null, backout.booleanValue()); + stackParams, true, heatTemplate.getTimeoutMinutes(), null, null, null, backout.booleanValue(), + failIfExists); } catch (MsoException me) { me.addContext(CREATE_NETWORK_CONTEXT); logger.error("{} {} Exception creating network type {} in {}/{} ", MessageEnum.RA_CREATE_NETWORK_EXC, @@ -462,13 +463,13 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { } } } + networkRollback.setNeutronNetworkId((String) outputs.get(NETWORK_ID)); } subnetIdMap.value = sMap; rollback.value = networkRollback; // Populate remaining rollback info and response parameters. networkRollback.setNetworkStackId(heatStack.getCanonicalName()); - networkRollback.setNeutronNetworkId((String) heatStack.getOutputs().get(NETWORK_ID)); networkRollback.setNetworkCreated(true); networkRollback.setNetworkType(networkType); @@ -562,13 +563,12 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { // Verify that the Network exists // For Neutron-based orchestration, the networkId is the Neutron Network UUID. NetworkInfo netInfo = null; - long queryNetworkStarttime = System.currentTimeMillis(); try { netInfo = neutron.queryNetwork(networkId, tenantId, cloudSiteId); } catch (MsoException me) { me.addContext(UPDATE_NETWORK_CONTEXT); logger.error("{} {} Exception - queryNetwork query {} in {}/{} ", MessageEnum.RA_QUERY_NETWORK_EXC, - ErrorCode.BusinessProcesssError.getValue(), networkId, cloudSiteId, tenantId, me); + ErrorCode.BusinessProcessError.getValue(), networkId, cloudSiteId, tenantId, me); throw new NetworkException(me); } @@ -576,7 +576,7 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { String error = String.format("Update Nework: Network %s does not exist in %s/%s", networkId, cloudSiteId, tenantId); logger.error(LoggingAnchor.THREE, MessageEnum.RA_NETWORK_NOT_FOUND, - ErrorCode.BusinessProcesssError.getValue(), error); + ErrorCode.BusinessProcessError.getValue(), error); // Does not exist. Throw an exception (can't update a non-existent network) throw new NetworkException(error, MsoExceptionCategory.USERDATA); } @@ -606,7 +606,6 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { // First, look up to see that the Network already exists. // For Heat-based orchestration, the networkId is the network Stack ID. StackInfo heatStack = null; - long queryStackStarttime = System.currentTimeMillis(); try { heatStack = heat.queryStack(cloudSiteId, CLOUD_OWNER, tenantId, networkName); } catch (MsoException me) { @@ -656,7 +655,7 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { throw new NetworkException(error, MsoExceptionCategory.INTERNAL); } - logger.debug("Got HEAT Template from DB: {}", heatTemplate.toString()); + logger.debug("Got HEAT Template from DB: {}", heatTemplate); // "Fix" the template if it has CR/LF (getting this from Oracle) String template = heatTemplate.getHeatTemplate(); @@ -726,7 +725,6 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { // Update the network stack // Ignore MsoStackNotFound exception because we already checked. - long updateStackStarttime = System.currentTimeMillis(); try { heatStack = heatWithUpdate.updateStack(cloudSiteId, CLOUD_OWNER, tenantId, networkId, template, stackParams, true, heatTemplate.getTimeoutMinutes()); @@ -798,12 +796,11 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { } } if (networkCust != null) { - logger.debug("Got Network Customization definition from Catalog: {}", networkCust.toString()); + logger.debug("Got Network Customization definition from Catalog: {}", networkCust); networkResource = networkCust.getNetworkResource(); } else if (collectionNetworkCust != null) { - logger.debug("Retrieved Collection Network Resource Customization from Catalog: {}", - collectionNetworkCust.toString()); + logger.debug("Retrieved Collection Network Resource Customization from Catalog: {}", collectionNetworkCust); networkResource = collectionNetworkCust.getNetworkResource(); } if (networkResource == null) { @@ -814,7 +811,7 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { throw new NetworkException(error, MsoExceptionCategory.USERDATA); } - logger.debug("Got Network definition from Catalog: {}", networkResource.toString()); + logger.debug(LOG_DEBUG_MSG, networkResource); String mode = networkResource.getOrchestrationMode(); NetworkType neutronNetworkType = NetworkType.valueOf(networkResource.getNeutronNetworkType()); @@ -842,8 +839,8 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { } else { String error = String.format( "Network Type:%s Version_Min:%s Version_Max:%s not supported on Cloud:%s with AIC_Version:%s", - networkType, networkType, networkResource.getAicVersionMin(), networkResource.getAicVersionMax(), - cloudSiteId, cloudSite.getCloudVersion()); + networkType, networkResource.getAicVersionMin(), networkResource.getAicVersionMax(), cloudSiteId, + cloudSite.getCloudVersion()); logger.error(LoggingAnchor.THREE, MessageEnum.RA_CONFIG_EXC, ErrorCode.DataError.getValue(), error); throw new NetworkException(error, MsoExceptionCategory.USERDATA); } @@ -891,9 +888,6 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { logger.debug("*** QUERY Network with Network: {} in {}/{}", networkNameOrId, cloudSiteId, tenantId); - // Will capture execution time for metrics - long startTime = System.currentTimeMillis(); - if (commonUtils.isNullOrEmpty(cloudSiteId) || commonUtils.isNullOrEmpty(tenantId) || commonUtils.isNullOrEmpty(networkNameOrId)) { @@ -915,10 +909,9 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { // Use MsoNeutronUtils for all NEUTRON commands String mode; - String neutronId; + String neutronId = null; // Try Heat first, since networks may be named the same as the Heat stack StackInfo heatStack = null; - long queryStackStarttime = System.currentTimeMillis(); try { heatStack = heat.queryStack(cloudSiteId, CLOUD_OWNER, tenantId, networkNameOrId); } catch (MsoException me) { @@ -931,12 +924,12 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { // Populate the outputs based on the returned Stack information if (heatStack != null && heatStack.getStatus() != HeatStatus.NOTFOUND) { // Found it. Get the neutronNetworkId for further query + Map<String, String> sMap = new HashMap<>(); Map<String, Object> outputs = heatStack.getOutputs(); - neutronId = (String) outputs.get(NETWORK_ID); mode = "HEAT"; - - Map<String, String> sMap = new HashMap<>(); if (outputs != null) { + neutronId = (String) outputs.get(NETWORK_ID); + for (String key : outputs.keySet()) { if (key != null && key.startsWith("subnet_id_")) // multiples subnet_%aaid% outputs { @@ -960,7 +953,6 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { // Query directly against the Neutron Network for the details // no RouteTargets available for ContrailV2 in neutron net-show // networkId is heatStackId - long queryNetworkStarttime = System.currentTimeMillis(); try { NetworkInfo netInfo = neutron.queryNetwork(neutronId, tenantId, cloudSiteId); if (netInfo != null) { @@ -1015,13 +1007,7 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { @Override public void deleteNetwork(String cloudSiteId, String tenantId, String networkType, String modelCustomizationUuid, String networkId, MsoRequest msoRequest, Holder<Boolean> networkDeleted) throws NetworkException { - logger.debug("*** DELETE Network adapter with Network: {} in {}/{}", networkId, cloudSiteId, tenantId); - - // Will capture execution time for metrics - long startTime = System.currentTimeMillis(); - - if (commonUtils.isNullOrEmpty(cloudSiteId) || commonUtils.isNullOrEmpty(tenantId) || commonUtils.isNullOrEmpty(networkId)) { String error = "Missing mandatory parameter cloudSiteId, tenantId or networkId"; @@ -1031,7 +1017,6 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { // Retrieve the Network Resource definition NetworkResource networkResource = null; - if (commonUtils.isNullOrEmpty(modelCustomizationUuid)) { if (!commonUtils.isNullOrEmpty(networkType)) { networkResource = networkResourceRepo.findFirstByModelNameOrderByModelVersionDesc(networkType); @@ -1043,20 +1028,23 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { networkResource = nrc.getNetworkResource(); } } + + int timeoutMinutes = 118; String mode = ""; if (networkResource != null) { - logger.debug("Got Network definition from Catalog: {}", networkResource.toString()); - + logger.debug(LOG_DEBUG_MSG, networkResource.toString()); mode = networkResource.getOrchestrationMode(); + networkResource.getHeatTemplate().getTimeoutMinutes(); + HeatTemplate heat = networkResource.getHeatTemplate(); + if (heat != null && heat.getTimeoutMinutes() != null) { + if (heat.getTimeoutMinutes() < 118) { + timeoutMinutes = heat.getTimeoutMinutes(); + } + } } if (NEUTRON_MODE.equals(mode)) { - - // Use MsoNeutronUtils for all NEUTRON commands - long deleteNetworkStarttime = System.currentTimeMillis(); try { - // The deleteNetwork function in MsoNeutronUtils returns success if the network - // was not found. So don't bother to query first. boolean deleted = neutron.deleteNetwork(networkId, tenantId, cloudSiteId); networkDeleted.value = deleted; } catch (MsoException me) { @@ -1065,21 +1053,10 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { ErrorCode.DataError.getValue(), networkId, cloudSiteId, tenantId, me); throw new NetworkException(me); } - } else { // DEFAULT to ("HEAT".equals (mode)) - long deleteStackStarttime = System.currentTimeMillis(); - + } else { try { - // The deleteStack function in MsoHeatUtils returns NOTFOUND if the stack was not found or if the stack - // was deleted. - // So query first to report back if stack WAS deleted or just NOTOFUND - StackInfo heatStack = null; - heatStack = heat.queryStack(cloudSiteId, CLOUD_OWNER, tenantId, networkId); - if (heatStack != null && heatStack.getStatus() != HeatStatus.NOTFOUND) { - heat.deleteStack(tenantId, CLOUD_OWNER, cloudSiteId, networkId, true); - networkDeleted.value = true; - } else { - networkDeleted.value = false; - } + heat.deleteStack(tenantId, CLOUD_OWNER, cloudSiteId, networkId, true, timeoutMinutes); + networkDeleted.value = true; } catch (MsoException me) { me.addContext("DeleteNetwork"); logger.error("{} {} Delete Network (heat): {} in {}/{} ", MessageEnum.RA_DELETE_NETWORK_EXC, @@ -1087,10 +1064,6 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { throw new NetworkException(me); } } - - - // On success, nothing is returned. - return; } /** @@ -1103,9 +1076,6 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { */ @Override public void rollbackNetwork(NetworkRollback rollback) throws NetworkException { - // Will capture execution time for metrics - long startTime = System.currentTimeMillis(); - if (rollback == null) { logger.error("{} {} rollback is null", MessageEnum.RA_ROLLBACK_NULL, ErrorCode.DataError.getValue()); return; @@ -1119,8 +1089,6 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { String modelCustomizationUuid = rollback.getModelCustomizationUuid(); logger.debug("*** ROLLBACK Network {} in {}/{}", networkId, cloudSiteId, tenantId); - - // Retrieve the Network Resource definition NetworkResource networkResource = null; if (commonUtils.isNullOrEmpty(modelCustomizationUuid)) { @@ -1132,44 +1100,34 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { String mode = ""; if (networkResource != null) { - logger.debug("Got Network definition from Catalog: {}", networkResource.toString()); + logger.debug(LOG_DEBUG_MSG, networkResource); mode = networkResource.getOrchestrationMode(); } if (rollback.getNetworkCreated()) { - // Rolling back a newly created network, so delete it. if (NEUTRON_MODE.equals(mode)) { - // Use MsoNeutronUtils for all NEUTRON commands - long deleteNetworkStarttime = System.currentTimeMillis(); try { - // The deleteNetwork function in MsoNeutronUtils returns success if the network - // was not found. So don't bother to query first. neutron.deleteNetwork(networkId, tenantId, cloudSiteId); } catch (MsoException me) { me.addContext("RollbackNetwork"); logger.error("{} {} Exception - Rollback Network (neutron): {} in {}/{} ", - MessageEnum.RA_DELETE_NETWORK_EXC, ErrorCode.BusinessProcesssError.getValue(), networkId, + MessageEnum.RA_DELETE_NETWORK_EXC, ErrorCode.BusinessProcessError.getValue(), networkId, cloudSiteId, tenantId, me); throw new NetworkException(me); } - } else { // DEFAULT to if ("HEAT".equals (mode)) - long deleteStackStarttime = System.currentTimeMillis(); + } else { try { - // The deleteStack function in MsoHeatUtils returns success if the stack - // was not found. So don't bother to query first. - heat.deleteStack(tenantId, CLOUD_OWNER, cloudSiteId, networkId, true); + heat.deleteStack(tenantId, CLOUD_OWNER, cloudSiteId, networkId, true, 120); } catch (MsoException me) { me.addContext("RollbackNetwork"); logger.error("{} {} Exception - Rollback Network (heat): {} in {}/{} ", - MessageEnum.RA_DELETE_NETWORK_EXC, ErrorCode.BusinessProcesssError.getValue(), networkId, + MessageEnum.RA_DELETE_NETWORK_EXC, ErrorCode.BusinessProcessError.getValue(), networkId, cloudSiteId, tenantId, me); throw new NetworkException(me); } } } - - return; } private String validateNetworkParams(NetworkType neutronNetworkType, String networkName, String physicalNetwork, @@ -1312,7 +1270,7 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { } } else { String error = "Null pFqdns at start of mergePolicyRefs"; - logger.error(LoggingAnchor.THREE, MessageEnum.RA_MARSHING_ERROR, ErrorCode.BusinessProcesssError.getValue(), + logger.error(LoggingAnchor.THREE, MessageEnum.RA_MARSHING_ERROR, ErrorCode.BusinessProcessError.getValue(), error); throw new MsoAdapterException(error); } @@ -1325,7 +1283,7 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { logger.debug("Json PolicyRefs Data:{}", jsonString); } catch (Exception e) { String error = "Error creating JsonNode for policyRefs Data"; - logger.error(LoggingAnchor.THREE, MessageEnum.RA_MARSHING_ERROR, ErrorCode.BusinessProcesssError.getValue(), + logger.error(LoggingAnchor.THREE, MessageEnum.RA_MARSHING_ERROR, ErrorCode.BusinessProcessError.getValue(), error, e); throw new MsoAdapterException(error); } @@ -1388,9 +1346,9 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { // Resource Property List<ContrailSubnet> cslist = new ArrayList<>(); for (Subnet subnet : subnets) { - logger.debug("Input Subnet:{}", subnet.toString()); + logger.debug("Input Subnet:{}", subnet); ContrailSubnet cs = new ContrailSubnetMapper(subnet).map(); - logger.debug("Contrail Subnet:{}", cs.toString()); + logger.debug("Contrail Subnet:{}", cs); cslist.add(cs); } @@ -1430,7 +1388,7 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { * make these optional + " ip_version: %ipversion%\n" + " enable_dhcp: %enabledhcp%\n" + * " gateway_ip: %gatewayip%\n" + " allocation_pools:\n" + " - start: %poolstart%\n" + * " end: %poolend%\n"; - * + * */ String outputTempl = " subnet_id_%subnetId%:\n" + " description: Openstack subnet identifier\n" @@ -1477,13 +1435,19 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { } if (subnet.getAllocationPools() != null) { - curR = curR + " allocation_pools:\n"; + StringBuilder tempBuf = new StringBuilder(); + tempBuf.append(curR); + tempBuf.append(" allocation_pools:\n"); for (Pool pool : subnet.getAllocationPools()) { if (!commonUtils.isNullOrEmpty(pool.getStart()) && !commonUtils.isNullOrEmpty(pool.getEnd())) { - curR = curR + " - start: " + pool.getStart() + "\n"; - curR = curR + " end: " + pool.getEnd() + "\n"; + tempBuf.append(" - start: "); + tempBuf.append(pool.getStart()); + tempBuf.append("\n end: "); + tempBuf.append(pool.getEnd()); + tempBuf.append("\n"); } } + curR = tempBuf.toString(); } resourcesBuf.append(curR); @@ -1492,7 +1456,6 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { curO = curO.replace("%subnetId%", subnet.getSubnetId()); outputsBuf.append(curO); - } // append resources and outputs in heatTemplate logger.debug("Tempate initial:{}", heatTemplate); @@ -1516,30 +1479,34 @@ public class MsoNetworkAdapterImpl implements MsoNetworkAdapter { logger.debug("Subnet_Ipam Output JSON String:{} {}", obj.getClass(), jStr); JsonNode rootNode = mapper.readTree(jStr); - for (JsonNode sNode : rootNode.path("ipam_subnets")) { - logger.debug("Output Subnet Node {}", sNode.toString()); - String name = sNode.path("subnet_name").textValue(); - String uuid = sNode.path("subnet_uuid").textValue(); - String aaiId = name; // default - // try to find aaiId for name in input subnetList - if (subnets != null) { - for (Subnet subnet : subnets) { - if (subnet != null && !commonUtils.isNullOrEmpty(subnet.getSubnetName())) { - if (subnet.getSubnetName().equals(name)) { + if (rootNode != null) { + for (JsonNode sNode : rootNode.path("ipam_subnets")) { + logger.debug("Output Subnet Node {}", sNode); + String name = sNode.path("subnet_name").textValue(); + String uuid = sNode.path("subnet_uuid").textValue(); + String aaiId = name; // default + // try to find aaiId for name in input subnetList + if (subnets != null) { + for (Subnet subnet : subnets) { + if (subnet != null && !commonUtils.isNullOrEmpty(subnet.getSubnetName()) + && subnet.getSubnetName().equals(name)) { aaiId = subnet.getSubnetId(); break; } } } + sMap.put(aaiId, uuid); // bpmn needs aaid to uuid map } - sMap.put(aaiId, uuid); // bpmn needs aaid to uuid map + } else { + logger.error("{} {} null rootNode - cannot get subnet-uuids", MessageEnum.RA_MARSHING_ERROR, + ErrorCode.DataError.getValue()); } } catch (Exception e) { logger.error("{} {} Exception getting subnet-uuids ", MessageEnum.RA_MARSHING_ERROR, ErrorCode.DataError.getValue(), e); } - logger.debug("Return sMap {}", sMap.toString()); + logger.debug("Return sMap {}", sMap); return sMap; } diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/NetworkAdapterRest.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/NetworkAdapterRest.java index 4eb5d5637f..0c37837880 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/NetworkAdapterRest.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/network/NetworkAdapterRest.java @@ -124,7 +124,7 @@ public class NetworkAdapterRest { } catch (Exception e) { // problem handling create, send generic failure as sync resp to caller logger.error("{} {} Exception while create network ", MessageEnum.RA_CREATE_NETWORK_EXC, - ErrorCode.BusinessProcesssError.getValue(), e); + ErrorCode.BusinessProcessError.getValue(), e); return Response.serverError().build(); } // send sync response (ACK) to caller @@ -286,7 +286,7 @@ public class NetworkAdapterRest { } catch (Exception e) { // problem handling create, send generic failure as sync resp to caller logger.error("{} {} Exception while delete network ", MessageEnum.RA_DELETE_NETWORK_EXC, - ErrorCode.BusinessProcesssError.getValue(), e); + ErrorCode.BusinessProcessError.getValue(), e); return Response.serverError().build(); } // send sync response (ACK) to caller @@ -403,7 +403,7 @@ public class NetworkAdapterRest { return Response.status(respStatus).entity(new GenericEntity<QueryNetworkResponse>(resp) {}).build(); } catch (NetworkException e) { logger.error("{} {} Exception when query VNF ", MessageEnum.RA_QUERY_VNF_ERR, - ErrorCode.BusinessProcesssError.getValue(), e); + ErrorCode.BusinessProcessError.getValue(), e); QueryNetworkError err = new QueryNetworkError(); err.setMessage(e.getMessage()); err.setCategory(MsoExceptionCategory.INTERNAL); @@ -436,7 +436,7 @@ public class NetworkAdapterRest { } catch (Exception e) { // problem handling create, send generic failure as sync resp to caller logger.error("{} {} Exception in rollbackNetwork ", MessageEnum.RA_ROLLBACK_NULL, - ErrorCode.BusinessProcesssError.getValue(), e); + ErrorCode.BusinessProcessError.getValue(), e); return Response.serverError().build(); } // send sync response (ACK) to caller @@ -529,7 +529,7 @@ public class NetworkAdapterRest { } catch (Exception e) { // problem handling create, send generic failure as sync resp to caller logger.error("{} {} Exception in updateNetwork ", MessageEnum.RA_UPDATE_NETWORK_ERR, - ErrorCode.BusinessProcesssError.getValue(), e); + ErrorCode.BusinessProcessError.getValue(), e); return Response.serverError().build(); } // send sync response (ACK) to caller diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/MsoOpenstackAdaptersApplication.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/MsoOpenstackAdaptersApplication.java index 436836491d..d9a83e6a9a 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/MsoOpenstackAdaptersApplication.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/MsoOpenstackAdaptersApplication.java @@ -21,7 +21,7 @@ package org.onap.so.adapters.openstack; import java.util.concurrent.Executor; -import org.onap.so.logging.jaxrs.filter.MDCTaskDecorator; +import org.onap.logging.filter.spring.MDCTaskDecorator; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/WebSecurityConfigImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/WebSecurityConfigImpl.java deleted file mode 100644 index 97e43d9828..0000000000 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/WebSecurityConfigImpl.java +++ /dev/null @@ -1,50 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * ONAP - SO - * ================================================================================ - * Copyright (C) 2017 - 2018 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Modifications Copyright (C) 2018 IBM. - * ================================================================================ - * 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 org.onap.so.adapters.openstack; - -import org.onap.so.security.MSOSpringFirewall; -import org.onap.so.security.WebSecurityConfig; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.builders.WebSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.web.firewall.StrictHttpFirewall; -import org.springframework.util.StringUtils; - -@EnableWebSecurity -public class WebSecurityConfigImpl extends WebSecurityConfig { - - @Override - protected void configure(HttpSecurity http) throws Exception { - http.csrf().disable().authorizeRequests().antMatchers("/manage/health", "/manage/info").permitAll() - .antMatchers("/**").hasAnyRole(StringUtils.collectionToDelimitedString(getRoles(), ",")).and() - .httpBasic(); - } - - @Override - public void configure(WebSecurity web) throws Exception { - super.configure(web); - StrictHttpFirewall firewall = new MSOSpringFirewall(); - web.httpFirewall(firewall); - } - -} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/TenantAdapterRest.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/TenantAdapterRest.java index 6a38cc60e6..c782adec64 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/TenantAdapterRest.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tenant/TenantAdapterRest.java @@ -100,7 +100,7 @@ public class TenantAdapterRest { logger.debug("createTenant enter: {}", req.toJsonString()); String newTenantId = null; - TenantRollback tenantRollback = new TenantRollback(); + TenantRollback tenantRollback; try { Holder<String> htenant = new Holder<>(); diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/ValetClient.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/ValetClient.java index 3c073af6ba..d75824357f 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/ValetClient.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/valet/ValetClient.java @@ -50,7 +50,6 @@ import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; -import org.onap.so.client.RestTemplateConfig; import javax.inject.Provider; @Component diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/BpelRestClient.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/BpelRestClient.java index 62e9d562a6..662ce33022 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/BpelRestClient.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/BpelRestClient.java @@ -216,7 +216,7 @@ public class BpelRestClient { if (totalretries >= retryCount) { debug("Retried " + totalretries + " times, giving up."); logger.error("{} {} Could not deliver response to BPEL after {} tries: {}", - MessageEnum.RA_SEND_VNF_NOTIF_ERR, ErrorCode.BusinessProcesssError.getValue(), totalretries, + MessageEnum.RA_SEND_VNF_NOTIF_ERR, ErrorCode.BusinessProcessError.getValue(), totalretries, toBpelStr); return false; } @@ -273,7 +273,7 @@ public class BpelRestClient { } } catch (Exception e) { logger.error("{} {} Exception - Error sending Bpel notification: {} ", MessageEnum.RA_SEND_VNF_NOTIF_ERR, - ErrorCode.BusinessProcesssError.getValue(), toBpelStr, e); + ErrorCode.BusinessProcessError.getValue(), toBpelStr, e); lastResponseCode = 900; lastResponse = ""; } diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/CSAR.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/CSAR.java deleted file mode 100644 index 7786b872ef..0000000000 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/CSAR.java +++ /dev/null @@ -1,189 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * ONAP - SO - * ================================================================================ - * Copyright (C) 2017 - 2018 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * 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 org.onap.so.adapters.vnf; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintStream; -import java.util.ArrayList; -import java.util.List; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; -import org.onap.so.adapters.vdu.VduArtifact; -import org.onap.so.adapters.vdu.VduArtifact.ArtifactType; -import org.onap.so.adapters.vdu.VduModelInfo; -import org.onap.so.adapters.vnf.exceptions.VnfException; -import com.google.common.io.Files; - -/** - * The purpose of this class is to create a CSAR byte array from Vdu inputs for the purpose of forwarding to a TOSCA - * orchestrator. - * - * @author DeWayne - * - */ -public class CSAR { - private static final String MANIFEST_FILENAME = "MANIFEST.MF"; - private VduModelInfo vduModel; - - public CSAR(VduModelInfo model) { - this.vduModel = model; - } - - /** - * Creates a byte array representation of a CSAR corresponding to the VduBlueprint arg in the constructor. - * - * @return - * @throws VnfException - */ - public byte[] create() { - File dir = Files.createTempDir(); - - /** - * Create subdir - */ - File metadir = new File(dir.getAbsolutePath() + "/TOSCA-Metadata"); - if (!metadir.mkdir()) { - throw new RuntimeException("CSAR TOSCA-Metadata directory create failed"); - } - - /** - * Organize model info for consumption - */ - VduArtifact mainTemplate = null; - List<VduArtifact> extraFiles = new ArrayList<>(); - for (VduArtifact artifact : vduModel.getArtifacts()) { - if (artifact.getType() == ArtifactType.MAIN_TEMPLATE) { - mainTemplate = artifact; - } else { - extraFiles.add(artifact); - } - } - - if (mainTemplate == null) { // make a dummy to avoid null pointers - mainTemplate = new VduArtifact("", new byte[0], null); - } - - /** - * Write template files - */ - try (OutputStream ofs = new FileOutputStream(new File(dir, mainTemplate.getName())); - PrintStream mfstream = - new PrintStream(new File(metadir.getAbsolutePath() + '/' + MANIFEST_FILENAME));) { - ofs.write(mainTemplate.getContent()); - - /** - * Write other files - */ - if (!extraFiles.isEmpty()) { - for (VduArtifact artifact : extraFiles) { - try (OutputStream out = new FileOutputStream(new File(dir, artifact.getName()));) { - out.write(artifact.getContent()); - } - } - } - - - /** - * Create manifest - */ - mfstream.println("TOSCA-Meta-File-Version: 1.0"); - mfstream.println("CSAR-Version: 1.1"); - mfstream.println("Created-by: ONAP"); - mfstream.println("Entry-Definitions: " + mainTemplate.getName()); - - /** - * ZIP it up - */ - ByteArrayOutputStream zipbytes = new ByteArrayOutputStream(); - ZipOutputStream zos = new ZipOutputStream(zipbytes); - compressTree(zos, "", dir, dir); - zos.close(); - return zipbytes.toByteArray(); - - } catch (Exception e) { - throw new RuntimeException("Failed to create CSAR: " + e.getMessage()); - } finally { - /** - * Clean up tmpdir - */ - deleteDirectory(dir); - } - } - - /** - * Private methods - */ - - /** - * Compresses (ZIPs) a directory tree - * - * @param dir - * @throws IOException - */ - private void compressTree(ZipOutputStream zos, String path, File basedir, File dir) throws IOException { - if (!dir.isDirectory()) - return; - - for (File f : dir.listFiles()) { - if (f.isDirectory()) { - String newpath = path + f.getName() + '/'; - ZipEntry entry = new ZipEntry(newpath); - zos.putNextEntry(entry); - zos.closeEntry(); - compressTree(zos, newpath, basedir, f); - } else { - ZipEntry ze = new ZipEntry( - f.getAbsolutePath().substring(basedir.getAbsolutePath().length() + 1).replaceAll("\\\\", "/")); - zos.putNextEntry(ze); - // read the file and write to ZipOutputStream - try (FileInputStream fis = new FileInputStream(f);) { - byte[] buffer = new byte[1024]; - int len; - while ((len = fis.read(buffer)) > 0) { - zos.write(buffer, 0, len); - } - } - zos.closeEntry(); - } - } - } - - private boolean deleteDirectory(File directory) { - if (directory.exists()) { - File[] files = directory.listFiles(); - if (null != files) { - for (int i = 0; i < files.length; i++) { - if (files[i].isDirectory()) { - deleteDirectory(files[i]); - } else { - files[i].delete(); - } - } - } - } - return (directory.delete()); - } -} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapter.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapter.java index f6ea2261d7..0074dca03c 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapter.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapter.java @@ -121,6 +121,9 @@ public interface MsoVnfAdapter { @WebParam(name = "cloudOwner") @XmlElement(required = false) String cloudOwner, @WebParam(name = "tenantId") @XmlElement(required = true) String tenantId, @WebParam(name = "vfName") @XmlElement(required = true) String vfName, + @WebParam(name = "vnfId") @XmlElement(required = true) String vnfId, + @WebParam(name = "vfModuleId") @XmlElement(required = true) String vfModuleId, + @WebParam(name = "modelCustomizationUuid") @XmlElement(required = false) String modelCustomizationUuid, @WebParam(name = "request") MsoRequest msoRequest, @WebParam(name = "vfModuleOutputs", mode = Mode.OUT) Holder<Map<String, String>> vfModuleOutputs) throws VnfException; diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterAsyncImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterAsyncImpl.java index 6713c2d069..e925e6037c 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterAsyncImpl.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterAsyncImpl.java @@ -135,7 +135,7 @@ public class MsoVnfAdapterAsyncImpl implements MsoVnfAdapterAsync { vnfRollback); } catch (VnfException e) { logger.error("{} {} VnfException in createVnfA ", MessageEnum.RA_CREATE_VNF_ERR, - ErrorCode.BusinessProcesssError.getValue(), e); + ErrorCode.BusinessProcessError.getValue(), e); org.onap.so.adapters.vnf.async.client.MsoExceptionCategory exCat = null; String eMsg = null; try { @@ -144,7 +144,7 @@ public class MsoVnfAdapterAsyncImpl implements MsoVnfAdapterAsync { .fromValue(e.getFaultInfo().getCategory().name()); } catch (Exception e1) { logger.error("{} {} Exception - Fault info ", MessageEnum.RA_FAULT_INFO_EXC, - ErrorCode.BusinessProcesssError.getValue(), e1); + ErrorCode.BusinessProcessError.getValue(), e1); } // Build and send Asynchronous error response try { @@ -152,7 +152,7 @@ public class MsoVnfAdapterAsyncImpl implements MsoVnfAdapterAsync { notifyPort.createVnfNotification(messageId, false, exCat, eMsg, null, null, null); } catch (Exception e1) { logger.error("{} {} Exception sending createVnf notification ", MessageEnum.RA_SEND_VNF_NOTIF_ERR, - ErrorCode.BusinessProcesssError.getValue(), e1); + ErrorCode.BusinessProcessError.getValue(), e1); } logger.info(LoggingAnchor.ONE, MessageEnum.RA_ASYNC_CREATE_VNF_COMPLETE); return; @@ -165,7 +165,7 @@ public class MsoVnfAdapterAsyncImpl implements MsoVnfAdapterAsync { copyVrb(vnfRollback)); } catch (Exception e) { logger.error("{} {} Exception sending createVnf notification ", MessageEnum.RA_SEND_VNF_NOTIF_ERR, - ErrorCode.BusinessProcesssError.getValue(), e); + ErrorCode.BusinessProcessError.getValue(), e); } logger.info("{} createVnfA", MessageEnum.RA_ASYNC_CREATE_VNF_COMPLETE); return; @@ -191,7 +191,7 @@ public class MsoVnfAdapterAsyncImpl implements MsoVnfAdapterAsync { volumeGroupHeatStackId, inputs, msoRequest, outputs, vnfRollback); } catch (VnfException e) { logger.error(EXCEPTION_UPDATEVNF_NOTIFICATION, MessageEnum.RA_UPDATE_VNF_ERR, - ErrorCode.BusinessProcesssError.getValue(), e); + ErrorCode.BusinessProcessError.getValue(), e); org.onap.so.adapters.vnf.async.client.MsoExceptionCategory exCat = null; String eMsg = null; try { @@ -200,7 +200,7 @@ public class MsoVnfAdapterAsyncImpl implements MsoVnfAdapterAsync { .fromValue(e.getFaultInfo().getCategory().name()); } catch (Exception e1) { logger.error("{} {} Exception - fault info ", MessageEnum.RA_FAULT_INFO_EXC, - ErrorCode.BusinessProcesssError.getValue(), e1); + ErrorCode.BusinessProcessError.getValue(), e1); } // Build and send Asynchronous error response try { @@ -208,7 +208,7 @@ public class MsoVnfAdapterAsyncImpl implements MsoVnfAdapterAsync { notifyPort.updateVnfNotification(messageId, false, exCat, eMsg, null, null); } catch (Exception e1) { logger.error(EXCEPTION_UPDATEVNF_NOTIFICATION, MessageEnum.RA_SEND_VNF_NOTIF_ERR, - ErrorCode.BusinessProcesssError.getValue(), e1); + ErrorCode.BusinessProcessError.getValue(), e1); } logger.info(UPDATE_VNFA, MessageEnum.RA_ASYNC_UPDATE_VNF_COMPLETE); return; @@ -221,7 +221,7 @@ public class MsoVnfAdapterAsyncImpl implements MsoVnfAdapterAsync { copyVrb(vnfRollback)); } catch (Exception e) { logger.error(EXCEPTION_UPDATEVNF_NOTIFICATION, MessageEnum.RA_SEND_VNF_NOTIF_ERR, - ErrorCode.BusinessProcesssError.getValue(), e); + ErrorCode.BusinessProcessError.getValue(), e); } logger.info(UPDATE_VNFA, MessageEnum.RA_ASYNC_UPDATE_VNF_COMPLETE); return; @@ -261,7 +261,7 @@ public class MsoVnfAdapterAsyncImpl implements MsoVnfAdapterAsync { outputs); } catch (VnfException e) { logger.error("{} {} Exception sending queryVnfA notification ", MessageEnum.RA_QUERY_VNF_ERR, - ErrorCode.BusinessProcesssError.getValue(), e); + ErrorCode.BusinessProcessError.getValue(), e); org.onap.so.adapters.vnf.async.client.MsoExceptionCategory exCat = null; String eMsg = null; try { @@ -270,7 +270,7 @@ public class MsoVnfAdapterAsyncImpl implements MsoVnfAdapterAsync { .fromValue(e.getFaultInfo().getCategory().name()); } catch (Exception e1) { logger.error("{} {} Exception - fault info ", MessageEnum.RA_FAULT_INFO_EXC, - ErrorCode.BusinessProcesssError.getValue(), e1); + ErrorCode.BusinessProcessError.getValue(), e1); } // Build and send Asynchronous error response try { @@ -278,7 +278,7 @@ public class MsoVnfAdapterAsyncImpl implements MsoVnfAdapterAsync { notifyPort.queryVnfNotification(messageId, false, exCat, eMsg, null, null, null, null); } catch (Exception e1) { logger.error("{} {} Exception sending queryVnf notification ", MessageEnum.RA_SEND_VNF_NOTIF_ERR, - ErrorCode.BusinessProcesssError.getValue(), e1); + ErrorCode.BusinessProcessError.getValue(), e1); } logger.info("{} queryVnfA", MessageEnum.RA_ASYNC_QUERY_VNF_COMPLETE); return; @@ -298,7 +298,7 @@ public class MsoVnfAdapterAsyncImpl implements MsoVnfAdapterAsync { copyQueryOutputs(outputs)); } catch (Exception e) { logger.error("{} {} Exception sending queryVnf notification ", MessageEnum.RA_SEND_VNF_NOTIF_ERR, - ErrorCode.BusinessProcesssError.getValue(), e); + ErrorCode.BusinessProcessError.getValue(), e); } logger.info("{} queryVnfA", MessageEnum.RA_ASYNC_QUERY_VNF_COMPLETE); @@ -331,7 +331,7 @@ public class MsoVnfAdapterAsyncImpl implements MsoVnfAdapterAsync { vnfAdapter.deleteVnf(cloudSiteId, cloudOwner, tenantId, vnfName, msoRequest); } catch (VnfException e) { logger.error("{} {} Exception sending deleteVnfA notification ", MessageEnum.RA_DELETE_VNF_ERR, - ErrorCode.BusinessProcesssError.getValue(), e); + ErrorCode.BusinessProcessError.getValue(), e); org.onap.so.adapters.vnf.async.client.MsoExceptionCategory exCat = null; String eMsg = null; try { @@ -340,7 +340,7 @@ public class MsoVnfAdapterAsyncImpl implements MsoVnfAdapterAsync { .fromValue(e.getFaultInfo().getCategory().name()); } catch (Exception e1) { logger.error("{} {} Exception - fault info ", MessageEnum.RA_FAULT_INFO_EXC, - ErrorCode.BusinessProcesssError.getValue(), e1); + ErrorCode.BusinessProcessError.getValue(), e1); } // Build and send Asynchronous error response try { @@ -348,7 +348,7 @@ public class MsoVnfAdapterAsyncImpl implements MsoVnfAdapterAsync { notifyPort.deleteVnfNotification(messageId, false, exCat, eMsg); } catch (Exception e1) { logger.error("{} {} Exception sending deleteVnfA notification ", MessageEnum.RA_SEND_VNF_NOTIF_ERR, - ErrorCode.BusinessProcesssError.getValue(), e1); + ErrorCode.BusinessProcessError.getValue(), e1); } logger.info("{} deleteVnfA", MessageEnum.RA_ASYNC_DELETE_VNF_COMPLETE); return; @@ -362,7 +362,7 @@ public class MsoVnfAdapterAsyncImpl implements MsoVnfAdapterAsync { } catch (Exception e) { logger.error("{} {} Exception sending deleteVnfA notification ", MessageEnum.RA_SEND_VNF_NOTIF_ERR, - ErrorCode.BusinessProcesssError.getValue(), e); + ErrorCode.BusinessProcessError.getValue(), e); } logger.info("{} deleteVnfA", MessageEnum.RA_ASYNC_DELETE_VNF_COMPLETE); @@ -391,7 +391,7 @@ public class MsoVnfAdapterAsyncImpl implements MsoVnfAdapterAsync { vnfAdapter.rollbackVnf(rollback); } catch (VnfException e) { logger.error("{} {} Exception sending rollbackVnfA notification ", MessageEnum.RA_ROLLBACK_VNF_ERR, - ErrorCode.BusinessProcesssError.getValue(), e); + ErrorCode.BusinessProcessError.getValue(), e); org.onap.so.adapters.vnf.async.client.MsoExceptionCategory exCat = null; String eMsg = null; try { @@ -400,7 +400,7 @@ public class MsoVnfAdapterAsyncImpl implements MsoVnfAdapterAsync { .fromValue(e.getFaultInfo().getCategory().name()); } catch (Exception e1) { logger.error("{} {} Exception - fault info ", MessageEnum.RA_FAULT_INFO_EXC, - ErrorCode.BusinessProcesssError.getValue(), e1); + ErrorCode.BusinessProcessError.getValue(), e1); } // Build and send Asynchronous error response try { @@ -408,7 +408,7 @@ public class MsoVnfAdapterAsyncImpl implements MsoVnfAdapterAsync { notifyPort.rollbackVnfNotification(messageId, false, exCat, eMsg); } catch (Exception e1) { logger.error("{} {} Exception sending rollbackVnfA notification ", MessageEnum.RA_SEND_VNF_NOTIF_ERR, - ErrorCode.BusinessProcesssError.getValue(), e1); + ErrorCode.BusinessProcessError.getValue(), e1); } logger.info("{} rollbackVnfA", MessageEnum.RA_ASYNC_ROLLBACK_VNF_COMPLETE); return; @@ -421,7 +421,7 @@ public class MsoVnfAdapterAsyncImpl implements MsoVnfAdapterAsync { notifyPort.rollbackVnfNotification(messageId, true, null, null); } catch (Exception e) { logger.error("{} {} Exception sending rollbackVnfA notification ", MessageEnum.RA_SEND_VNF_NOTIF_ERR, - ErrorCode.BusinessProcesssError.getValue(), e); + ErrorCode.BusinessProcessError.getValue(), e); } logger.info("{} rollbackVnfA", MessageEnum.RA_ASYNC_ROLLBACK_VNF_COMPLETE); @@ -519,17 +519,17 @@ public class MsoVnfAdapterAsyncImpl implements MsoVnfAdapterAsync { warWsdlLoc = Thread.currentThread().getContextClassLoader().getResource("VnfAdapterNotify.wsdl"); } catch (Exception e) { logger.error("{} {} Exception - WSDL not found ", MessageEnum.RA_WSDL_NOT_FOUND, - ErrorCode.BusinessProcesssError.getValue(), e); + ErrorCode.BusinessProcessError.getValue(), e); } if (warWsdlLoc == null) { logger.error("{} {} WSDL not found", MessageEnum.RA_WSDL_NOT_FOUND, - ErrorCode.BusinessProcesssError.getValue()); + ErrorCode.BusinessProcessError.getValue()); } else { try { logger.debug("VnfAdpaterNotify.wsdl location:{}", warWsdlLoc.toURI().toString()); } catch (Exception e) { logger.error("{} {} Exception - WSDL URL convention ", MessageEnum.RA_WSDL_URL_CONVENTION_EXC, - ErrorCode.BusinessProcesssError.getValue(), e); + ErrorCode.BusinessProcessError.getValue(), e); } } @@ -545,7 +545,7 @@ public class MsoVnfAdapterAsyncImpl implements MsoVnfAdapterAsync { epUrl = new URL(notificationUrl); } catch (MalformedURLException e1) { logger.error("{} {} MalformedURLException ", MessageEnum.RA_INIT_NOTIF_EXC, - ErrorCode.BusinessProcesssError.getValue(), e1); + ErrorCode.BusinessProcessError.getValue(), e1); } if (null != epUrl) { @@ -567,7 +567,7 @@ public class MsoVnfAdapterAsyncImpl implements MsoVnfAdapterAsync { headers.put("Authorization", Collections.singletonList(basicAuth)); } catch (Exception e) { logger.error("{} {} Exception - Unable to set authorization in callback request ", - MessageEnum.RA_SET_CALLBACK_AUTH_EXC, ErrorCode.BusinessProcesssError.getValue(), e); + MessageEnum.RA_SET_CALLBACK_AUTH_EXC, ErrorCode.BusinessProcessError.getValue(), e); } return notifyPort; diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterImpl.java index 1d73bf21c9..4b908004df 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterImpl.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterImpl.java @@ -25,18 +25,13 @@ package org.onap.so.adapters.vnf; -import java.io.File; -import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.concurrent.TimeUnit; import javax.jws.WebService; import javax.xml.ws.Holder; -import org.onap.so.logger.LoggingAnchor; import org.apache.commons.collections.CollectionUtils; import org.onap.so.adapters.valet.GenericValetResponse; import org.onap.so.adapters.valet.ValetClient; @@ -47,7 +42,6 @@ import org.onap.so.adapters.valet.beans.ValetDeleteResponse; import org.onap.so.adapters.valet.beans.ValetRollbackResponse; import org.onap.so.adapters.valet.beans.ValetStatus; import org.onap.so.adapters.valet.beans.ValetUpdateResponse; -import org.onap.so.adapters.vnf.exceptions.VnfAlreadyExists; import org.onap.so.adapters.vnf.exceptions.VnfException; import org.onap.so.adapters.vnf.exceptions.VnfNotFound; import org.onap.so.client.aai.AAIResourcesClient; @@ -65,9 +59,11 @@ import org.onap.so.db.catalog.data.repository.VFModuleCustomizationRepository; import org.onap.so.db.catalog.data.repository.VnfResourceRepository; import org.onap.so.db.catalog.utils.MavenLikeVersioning; import org.onap.so.entity.MsoRequest; +import org.onap.so.heatbridge.HeatBridgeException; import org.onap.so.heatbridge.HeatBridgeApi; import org.onap.so.heatbridge.HeatBridgeImpl; import org.onap.so.logger.ErrorCode; +import org.onap.so.logger.LoggingAnchor; import org.onap.so.logger.MessageEnum; import org.onap.so.openstack.beans.HeatStatus; import org.onap.so.openstack.beans.StackInfo; @@ -80,6 +76,10 @@ import org.onap.so.openstack.exceptions.MsoHeatNotFoundException; import org.onap.so.openstack.utils.MsoHeatEnvironmentEntry; import org.onap.so.openstack.utils.MsoHeatUtils; import org.onap.so.openstack.utils.MsoHeatUtilsWithUpdate; +import org.openstack4j.model.compute.Flavor; +import org.openstack4j.model.compute.Image; +import org.openstack4j.model.compute.Server; +import org.openstack4j.model.heat.Resource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -89,10 +89,6 @@ import org.springframework.transaction.annotation.Transactional; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import org.openstack4j.model.compute.Flavor; -import org.openstack4j.model.compute.Image; -import org.openstack4j.model.compute.Server; -import org.openstack4j.model.heat.Resource; @WebService(serviceName = "VnfAdapter", endpointInterface = "org.onap.so.adapters.vnf.MsoVnfAdapter", targetNamespace = "http://org.onap.so/vnf") @@ -133,7 +129,7 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { @Autowired private MsoHeatUtilsWithUpdate heatU; @Autowired - private MsoHeatUtils heat; + private MsoHeatUtils msoHeatUtils; @Autowired private ValetClient vci; @@ -264,7 +260,7 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { StackInfo heatStack; try { - heatStack = heat.queryStack(cloudSiteId, cloudOwner, tenantId, vnfName); + heatStack = msoHeatUtils.queryStack(cloudSiteId, cloudOwner, tenantId, vnfName); } catch (MsoException me) { me.addContext("QueryVNF"); // Failed to query the Stack due to an openstack exception. @@ -317,7 +313,7 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { logger.debug("Deleting VNF {} in {}", vnfName, cloudSiteId + "/" + tenantId); try { - heat.deleteStack(tenantId, cloudOwner, cloudSiteId, vnfName, true); + msoHeatUtils.deleteStack(tenantId, cloudOwner, cloudSiteId, vnfName, true, 118); } catch (MsoException me) { me.addContext(DELETE_VNF); // Failed to query the Stack due to an openstack exception. @@ -360,7 +356,7 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { // of NOTFOUND (on success) or FAILED (on error). Also, MsoOpenstackException // could be thrown. try { - heat.deleteStack(tenantId, cloudOwner, cloudSiteId, vnfId, true); + msoHeatUtils.deleteStack(tenantId, cloudOwner, cloudSiteId, vnfId, true, 118); } catch (MsoException me) { // Failed to rollback the Stack due to an openstack exception. // Convert to a generic VnfException @@ -415,34 +411,6 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { return new HashMap<>(stringInputs); } - protected boolean callHeatbridge(String heatStackId) { - String executionDir = "/usr/local/lib/python2.7/dist-packages/heatbridge"; - String openstackIdentityUrl = "", username = "", password = "", tenant = "", region = "", owner = ""; - long waitTimeMs = 10000L; - try { - String[] cmdarray = {"/usr/bin/python", "HeatBridgeMain.py", openstackIdentityUrl, username, password, - tenant, region, owner, heatStackId}; - String[] envp = null; - File dir = new File(executionDir); - logger.debug("Calling HeatBridgeMain.py in {} with arguments {}", dir, Arrays.toString(cmdarray)); - Runtime r = Runtime.getRuntime(); - Process p = r.exec(cmdarray, envp, dir); - boolean wait = p.waitFor(waitTimeMs, TimeUnit.MILLISECONDS); - - logger.debug(" HeatBridgeMain.py returned {} with code {}", wait, p.exitValue()); - return wait && p.exitValue() == 0; - } catch (IOException e) { - logger.debug(" HeatBridgeMain.py failed with IO Exception! {}", e); - return false; - } catch (RuntimeException e) { - logger.debug(" HeatBridgeMain.py failed during runtime! {}", e); - return false; - } catch (Exception e) { - logger.debug(" HeatBridgeMain.py failed for unknown reasons! {}", e); - return false; - } - } - private void heatbridge(StackInfo heatStack, String cloudOwner, String cloudSiteId, String tenantId, String genericVnfName, String vfModuleId) { try { @@ -453,13 +421,17 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { List<String> oobMgtNetNames = new ArrayList<>(); - HeatBridgeApi heatBridgeClient = - new HeatBridgeImpl(new AAIResourcesClient(), cloudIdentity, cloudOwner, cloudSiteId, tenantId); + HeatBridgeApi heatBridgeClient = new HeatBridgeImpl(new AAIResourcesClient(), cloudIdentity, cloudOwner, + cloudSiteId, cloudSite.getRegionId(), tenantId); + + heatBridgeClient.authenticate(); List<Resource> stackResources = heatBridgeClient.queryNestedHeatStackResources(heatStackId); List<Server> osServers = heatBridgeClient.getAllOpenstackServers(stackResources); + heatBridgeClient.createPserversAndPinterfacesIfNotPresentInAai(stackResources); + List<Image> osImages = heatBridgeClient.extractOpenstackImagesFromServers(osServers); List<Flavor> osFlavors = heatBridgeClient.extractOpenstackFlavorsFromServers(osServers); @@ -633,97 +605,13 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { vfRollback.setIsBase(isBaseRequest); vfRollback.setModelCustomizationUuid(mcu); - // Put data into A&AI through Heatstack - if (enableBridge != null && enableBridge) { - callHeatbridge(baseVfHeatStackId); - } - - StackInfo heatStack = null; - try { - heatStack = heat.queryStack(cloudSiteId, cloudOwner, tenantId, vfModuleName); - } catch (MsoException me) { - String error = "Create VF Module: Query " + vfModuleName + " in " + cloudOwner + "/" + cloudSiteId + "/" - + tenantId + ": " + me; - logger.error(LoggingAnchor.NINE, MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudOwner, - cloudSiteId, tenantId, OPENSTACK, QUERY_STACK, ErrorCode.DataError.getValue(), - "Exception - " + QUERY_STACK, me); - logger.debug(error); - // Failed to query the Stack due to an openstack exception. - // Convert to a generic VnfException - me.addContext(CREATE_VFM_MODULE); - throw new VnfException(me); - } - // more precise handling/messaging if the stack already exists - if (heatStack != null && heatStack.getStatus() != HeatStatus.NOTFOUND) { - // INIT, CREATED, NOTFOUND, FAILED, BUILDING, DELETING, UNKNOWN, UPDATING, UPDATED - HeatStatus status = heatStack.getStatus(); - if (status == HeatStatus.INIT || status == HeatStatus.BUILDING || status == HeatStatus.DELETING - || status == HeatStatus.UPDATING) { - // fail - it's in progress - return meaningful error - String error = CREATE_VF_STACK + " " + vfModuleName + " already exists and has status " - + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId - + "; please wait for it to complete, or fix manually."; - logger.error(LoggingAnchor.NINE, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner, - cloudSiteId, tenantId, OPENSTACK, QUERY_STACK, ErrorCode.DataError.getValue(), - STACK + " " + vfModuleName + " already exists"); - logger.debug(error); - throw new VnfAlreadyExists(vfModuleName, cloudOwner, cloudSiteId, tenantId, - heatStack.getCanonicalName()); - } - if (status == HeatStatus.FAILED) { - // fail - it exists and is in a FAILED state - String error = CREATE_VF_STACK + " " + vfModuleName + " already exists and is in FAILED state in " - + cloudOwner + "/" + cloudSiteId + "/" + tenantId + "; requires manual intervention."; - logger.error(LoggingAnchor.NINE, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner, - cloudSiteId, tenantId, OPENSTACK, QUERY_STACK, ErrorCode.DataError.getValue(), - STACK + " " + vfModuleName + " already exists and is " + "in FAILED state"); - logger.debug(error); - throw new VnfAlreadyExists(vfModuleName, cloudOwner, cloudSiteId, tenantId, - heatStack.getCanonicalName()); - } - if (status == HeatStatus.UNKNOWN || status == HeatStatus.UPDATED) { - // fail - it exists and is in a FAILED state - String error = CREATE_VF_STACK + " " + vfModuleName + " already exists and has status " - + status.toString() + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId - + "; requires manual intervention."; - logger.error(LoggingAnchor.NINE, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, cloudOwner, - cloudSiteId, tenantId, OPENSTACK, QUERY_STACK, ErrorCode.DataError.getValue(), - STACK + " " + vfModuleName + " already exists and is " + "in UPDATED or UNKNOWN state"); - logger.debug(error); - throw new VnfAlreadyExists(vfModuleName, cloudOwner, cloudSiteId, tenantId, - heatStack.getCanonicalName()); - } - if (status == HeatStatus.CREATED) { - // fail - it exists - if (failIfExists != null && failIfExists) { - String error = CREATE_VF_STACK + " " + vfModuleName + " already exists in " + cloudOwner + "/" - + cloudSiteId + "/" + tenantId; - logger.error(LoggingAnchor.NINE, MessageEnum.RA_VNF_ALREADY_EXIST.toString(), vfModuleName, - cloudOwner, cloudSiteId, tenantId, OPENSTACK, QUERY_STACK, ErrorCode.DataError.getValue(), - STACK + " " + vfModuleName + " already exists"); - logger.debug(error); - throw new VnfAlreadyExists(vfModuleName, cloudOwner, cloudSiteId, tenantId, - heatStack.getCanonicalName()); - } else { - logger.debug("Found Existing stack, status={}", heatStack.getStatus()); - // Populate the outputs from the existing stack. - vnfId.value = heatStack.getCanonicalName(); - outputs.value = copyStringOutputs(heatStack.getOutputs()); - rollback.value = vfRollback; // Default rollback - no updates performed - } - } - return; - - } - // handle a nestedStackId if sent- this one would be for the volume - so applies to both Vf and Vnf StackInfo nestedHeatStack = null; - Map<String, Object> nestedVolumeOutputs = null; if (nestedStackId != null) { try { logger.debug("Querying for nestedStackId = {}", nestedStackId); - nestedHeatStack = heat.queryStack(cloudSiteId, cloudOwner, tenantId, nestedStackId); + nestedHeatStack = msoHeatUtils.queryStack(cloudSiteId, cloudOwner, tenantId, nestedStackId); } catch (MsoException me) { // Failed to query the Stack due to an openstack exception. // Convert to a generic VnfException @@ -731,7 +619,7 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { String error = "Create VFModule: Attached heatStack ID Query " + nestedStackId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me; logger.error(LoggingAnchor.NINE, MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudOwner, - cloudSiteId, tenantId, OPENSTACK, QUERY_STACK, ErrorCode.BusinessProcesssError.getValue(), + cloudSiteId, tenantId, OPENSTACK, QUERY_STACK, ErrorCode.BusinessProcessError.getValue(), "MsoException trying to query nested stack", me); logger.debug("ERROR trying to query nested stack= {}", error); throw new VnfException(me); @@ -740,8 +628,7 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { String error = "Create VFModule: Attached heatStack ID DOES NOT EXIST " + nestedStackId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + " " + USER_ERROR; logger.error(LoggingAnchor.TEN, MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudOwner, - cloudSiteId, tenantId, error, OPENSTACK, QUERY_STACK, - ErrorCode.BusinessProcesssError.getValue(), + cloudSiteId, tenantId, error, OPENSTACK, QUERY_STACK, ErrorCode.BusinessProcessError.getValue(), "Create VFModule: Attached heatStack ID " + "DOES NOT EXIST"); logger.debug(error); throw new VnfException(error, MsoExceptionCategory.USERDATA); @@ -757,7 +644,7 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { if (nestedBaseStackId != null) { try { logger.debug("Querying for nestedBaseStackId = {}", nestedBaseStackId); - nestedBaseHeatStack = heat.queryStack(cloudSiteId, cloudOwner, tenantId, nestedBaseStackId); + nestedBaseHeatStack = msoHeatUtils.queryStack(cloudSiteId, cloudOwner, tenantId, nestedBaseStackId); } catch (MsoException me) { // Failed to query the Stack due to an openstack exception. // Convert to a generic VnfException @@ -765,7 +652,7 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { String error = "Create VFModule: Attached baseHeatStack ID Query " + nestedBaseStackId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me; logger.error(LoggingAnchor.NINE, MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudOwner, - cloudSiteId, tenantId, OPENSTACK, QUERY_STACK, ErrorCode.BusinessProcesssError.getValue(), + cloudSiteId, tenantId, OPENSTACK, QUERY_STACK, ErrorCode.BusinessProcessError.getValue(), "MsoException trying to query nested base stack", me); logger.debug("ERROR trying to query nested base stack= {}", error); throw new VnfException(me); @@ -774,8 +661,7 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { String error = "Create VFModule: Attached base heatStack ID DOES NOT EXIST " + nestedBaseStackId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + " " + USER_ERROR; logger.error(LoggingAnchor.TEN, MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, cloudOwner, - cloudSiteId, tenantId, error, OPENSTACK, QUERY_STACK, - ErrorCode.BusinessProcesssError.getValue(), + cloudSiteId, tenantId, error, OPENSTACK, QUERY_STACK, ErrorCode.BusinessProcessError.getValue(), "Create VFModule: Attached base heatStack ID DOES NOT EXIST"); logger.debug("Exception occurred", error); throw new VnfException(error, MsoExceptionCategory.USERDATA); @@ -786,7 +672,6 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { } try { - // Retrieve the VF VfModule vf = null; VnfResource vnfResource = null; VfModuleCustomization vfmc = null; @@ -908,7 +793,7 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { + VERSION_MAX + " :" + maxVersionVnf + " NOT supported on Cloud: " + cloudSiteId + " with AIC_Version:" + cloudSiteOpt.get().getCloudVersion(); logger.error(LoggingAnchor.FIVE, MessageEnum.RA_CONFIG_EXC.toString(), error, OPENSTACK, - ErrorCode.BusinessProcesssError.getValue(), "Exception - setVersion"); + ErrorCode.BusinessProcessError.getValue(), "Exception - setVersion"); logger.debug(error); throw new VnfException(error, MsoExceptionCategory.USERDATA); } @@ -981,7 +866,7 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { logger.debug("Contents of nestedTemplates - to be added to files: on stack:"); for (HeatTemplate entry : nestedTemplates) { nestedTemplatesChecked.put(entry.getTemplateName(), entry.getTemplateBody()); - logger.debug(entry.getTemplateName() + " -> " + entry.getTemplateBody()); + logger.debug("Adding Nested Template", entry.getTemplateName()); } } else { logger.debug("No nested templates found - nothing to do here"); @@ -1103,13 +988,13 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { // Step 1 - convert what we got as inputs (Map<String, String>) to a // Map<String, Object> - where the object matches the param type identified in the template // This will also not copy over params that aren't identified in the template - goldenInputs = heat.convertInputMap(inputs, heatTemplate); + goldenInputs = msoHeatUtils.convertInputMap(inputs, heatTemplate); // Step 2 - now simply add the outputs as we received them - no need to convert to string logger.debug("Now add in the base stack outputs if applicable"); - heat.copyBaseOutputsToInputs(goldenInputs, baseStackOutputs, parameterNames, aliasToParam); + msoHeatUtils.copyBaseOutputsToInputs(goldenInputs, baseStackOutputs, parameterNames, aliasToParam); // Step 3 - add the volume inputs if any logger.debug("Now add in the volume stack outputs if applicable"); - heat.copyBaseOutputsToInputs(goldenInputs, nestedVolumeOutputs, parameterNames, aliasToParam); + msoHeatUtils.copyBaseOutputsToInputs(goldenInputs, nestedVolumeOutputs, parameterNames, aliasToParam); for (HeatTemplateParam parm : heatTemplate.getParameters()) { logger.debug("Parameter:'" + parm.getParamName() + "', isRequired=" + parm.isRequired() + ", alias=" @@ -1182,15 +1067,19 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { // Have the tenant. Now deploy the stack itself // Ignore MsoTenantNotFound and MsoStackAlreadyExists exceptions // because we already checked for those. + + StackInfo heatStack = null; try { if (backout == null) { backout = true; } - if (heat != null) { - - heatStack = heat.createStack(cloudSiteId, cloudOwner, tenantId, vfModuleName, null, template, - goldenInputs, true, heatTemplate.getTimeoutMinutes(), newEnvironmentString, - nestedTemplatesChecked, heatFilesObjects, backout.booleanValue()); + if (failIfExists == null) { + failIfExists = false; + } + if (msoHeatUtils != null) { + heatStack = msoHeatUtils.createStack(cloudSiteId, cloudOwner, tenantId, vfModuleName, null, + template, goldenInputs, true, heatTemplate.getTimeoutMinutes(), newEnvironmentString, + nestedTemplatesChecked, heatFilesObjects, backout.booleanValue(), failIfExists); } else { throw new MsoHeatNotFoundException(); } @@ -1236,8 +1125,10 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { } } logger.debug("VF Module {} successfully created", vfModuleName); - // call heatbridge - heatbridge(heatStack, cloudOwner, cloudSiteId, tenantId, genericVnfName, vfModuleId); + if (enableBridge != null && enableBridge) { + // call heatbridge + heatbridge(heatStack, cloudOwner, cloudSiteId, tenantId, genericVnfName, vfModuleId); + } } catch (Exception e) { logger.debug("unhandled exception in create VF", e); throw new VnfException("Exception during create VF " + e.getMessage()); @@ -1245,17 +1136,12 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { } @Override - public void deleteVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfName, - MsoRequest msoRequest, Holder<Map<String, String>> outputs) throws VnfException { - - logger.debug("Deleting VF {} in ", vnfName, cloudOwner + "/" + cloudSiteId + "/" + tenantId); - // Will capture execution time for metrics - - // 1702 capture the output parameters on a delete - // so we'll need to query first + public void deleteVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfName, String vnfId, + String vfModuleId, String modelCustomizationUuid, MsoRequest msoRequest, + Holder<Map<String, String>> outputs) throws VnfException { Map<String, Object> stackOutputs; try { - stackOutputs = heat.queryStackForOutputs(cloudSiteId, cloudOwner, tenantId, vnfName); + stackOutputs = msoHeatUtils.queryStackForOutputs(cloudSiteId, cloudOwner, tenantId, vnfName); } catch (MsoException me) { // Failed to query the Stack due to an openstack exception. // Convert to a generic VnfException @@ -1281,8 +1167,32 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { msoRequest, failRequestOnValetFailure); } + int timeoutMinutes = 118; + VfModule vf = null; + VfModuleCustomization vfmc = null; + if (modelCustomizationUuid != null) { + vfmc = vfModuleCustomRepo.findFirstByModelCustomizationUUIDOrderByCreatedDesc(modelCustomizationUuid); + if (vfmc != null) { + vf = vfmc.getVfModule(); + } + if (vf != null) { + logger.trace("Found vfModuleCust entry {}", vfmc.toString()); + HeatTemplate heat = vf.getModuleHeatTemplate(); + if (heat != null && heat.getTimeoutMinutes() != null) { + if (heat.getTimeoutMinutes() < 118) { + timeoutMinutes = heat.getTimeoutMinutes(); + } + } + + } else { + logger.debug( + "Unable to find vfModuleCust with modelCustomizationUuid={} . Using default timeout for polling", + modelCustomizationUuid); + } + } + try { - heat.deleteStack(tenantId, cloudOwner, cloudSiteId, vnfName, true); + msoHeatUtils.deleteStack(tenantId, cloudOwner, cloudSiteId, vnfName, true, timeoutMinutes); } catch (MsoException me) { me.addContext(DELETE_VNF); // Failed to query the Stack due to an openstack exception. @@ -1317,9 +1227,12 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { logger.error("Exception encountered while sending Confirm to Valet ", e); } } - - // On success, nothing is returned. - return; + // call heatbridge delete + try { + new HeatBridgeImpl().deleteVfModuleData(vnfId, vfModuleId); + } catch (HeatBridgeException e) { + logger.error("Heatbridge failed to delete AAI data for vf-module: " + vfModuleId, e); + } } @Override @@ -1413,7 +1326,7 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { StackInfo heatStack; logger.debug("UpdateVfModule - querying for {}", vfModuleName); try { - heatStack = heat.queryStack(cloudSiteId, cloudOwner, tenantId, vfModuleName); + heatStack = msoHeatUtils.queryStack(cloudSiteId, cloudOwner, tenantId, vfModuleName); } catch (MsoException me) { // Failed to query the Stack due to an openstack exception. // Convert to a generic VnfException @@ -1448,7 +1361,7 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { if (nestedStackId != null) { try { logger.debug("Querying for nestedStackId = {}", nestedStackId); - nestedHeatStack = heat.queryStack(cloudSiteId, cloudOwner, tenantId, nestedStackId); + nestedHeatStack = msoHeatUtils.queryStack(cloudSiteId, cloudOwner, tenantId, nestedStackId); } catch (MsoException me) { // Failed to query the Stack due to an openstack exception. // Convert to a generic VnfException @@ -1471,7 +1384,7 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { } else { logger.debug("Found nested heat stack - copying values to inputs *later*"); nestedVolumeOutputs = nestedHeatStack.getOutputs(); - heat.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false); + msoHeatUtils.copyStringOutputsToInputs(inputs, nestedHeatStack.getOutputs(), false); } } // handle a nestedBaseStackId if sent - this is the stack ID of the base. @@ -1480,7 +1393,7 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { if (nestedBaseStackId != null) { try { logger.debug("Querying for nestedBaseStackId = {}", nestedBaseStackId); - nestedBaseHeatStack = heat.queryStack(cloudSiteId, cloudOwner, tenantId, nestedBaseStackId); + nestedBaseHeatStack = msoHeatUtils.queryStack(cloudSiteId, cloudOwner, tenantId, nestedBaseStackId); } catch (MsoException me) { // Failed to query the Stack due to an openstack exception. // Convert to a generic VnfException @@ -1503,14 +1416,10 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { } else { logger.debug("Found nested base heat stack - copying values to inputs *later*"); baseStackOutputs = nestedBaseHeatStack.getOutputs(); - heat.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false); + msoHeatUtils.copyStringOutputsToInputs(inputs, nestedBaseHeatStack.getOutputs(), false); } } - // Ready to deploy the new VNF - - - // Retrieve the VF definition VnfResource vnfResource = null; VfModule vf = null; @@ -1608,7 +1517,7 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { + minVersionVnf + " " + VERSION_MAX + " :" + maxVersionVnf + " NOT supported on Cloud: " + cloudSiteId + " with AIC_Version:" + aicV; logger.error(LoggingAnchor.FIVE, MessageEnum.RA_CONFIG_EXC.toString(), error, OPENSTACK, - ErrorCode.BusinessProcesssError.getValue(), "Exception - setVersion"); + ErrorCode.BusinessProcessError.getValue(), "Exception - setVersion"); logger.debug(error); throw new VnfException(error, MsoExceptionCategory.USERDATA); } @@ -1920,9 +1829,8 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { parsedVfModuleName = "unknown"; } sendResponseToValet = this.valetUpdateRequest(cloudSiteId, cloudOwner, tenantId, heatFilesObjects, - nestedTemplatesChecked, parsedVfModuleName, false, heatTemplate, newEnvironmentString, - (HashMap<String, Object>) goldenInputs, msoRequest, inputs, failRequestOnValetFailure, - valetModifiedParamsHolder); + nestedTemplatesChecked, parsedVfModuleName, false, heatTemplate, newEnvironmentString, goldenInputs, + msoRequest, inputs, failRequestOnValetFailure, valetModifiedParamsHolder); if (sendResponseToValet) { goldenInputs = valetModifiedParamsHolder.value; } @@ -2060,7 +1968,7 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { boolean valetSucceeded = false; String valetErrorMessage = "more detail not available"; try { - String keystoneUrl = heat.getCloudSiteKeystoneUrl(cloudSiteId); + String keystoneUrl = msoHeatUtils.getCloudSiteKeystoneUrl(cloudSiteId); Map<String, Object> files = this.combineGetFilesAndNestedTemplates(heatFilesObjects, nestedTemplatesChecked); HeatRequest heatRequest = new HeatRequest(vfModuleName, backout, heatTemplate.getTimeoutMinutes(), @@ -2122,7 +2030,7 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter { boolean valetSucceeded = false; String valetErrorMessage = "more detail not available"; try { - String keystoneUrl = heat.getCloudSiteKeystoneUrl(cloudSiteId); + String keystoneUrl = msoHeatUtils.getCloudSiteKeystoneUrl(cloudSiteId); Map<String, Object> files = this.combineGetFilesAndNestedTemplates(heatFilesObjects, nestedTemplatesChecked); HeatRequest heatRequest = new HeatRequest(vfModuleName, false, heatTemplate.getTimeoutMinutes(), diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfCloudifyAdapterImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfCloudifyAdapterImpl.java index f09fa34cb9..abaf881ba5 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfCloudifyAdapterImpl.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfCloudifyAdapterImpl.java @@ -601,7 +601,7 @@ public class MsoVnfCloudifyAdapterImpl implements MsoVnfAdapter { + vnfResource.getModelUUID() + " VersionMin=" + vnfMin + " VersionMax:" + vnfMax + " NOT supported on Cloud: " + cloudSiteId + " with AIC_Version:" + cloudSite.getCloudVersion(); logger.error(LoggingAnchor.FIVE, MessageEnum.RA_CONFIG_EXC.toString(), error, OPENSTACK, - ErrorCode.BusinessProcesssError.getValue(), "Exception - setVersion"); + ErrorCode.BusinessProcessError.getValue(), "Exception - setVersion"); logger.debug(error); throw new VnfException(error, MsoExceptionCategory.USERDATA); } @@ -725,7 +725,7 @@ public class MsoVnfCloudifyAdapterImpl implements MsoVnfAdapter { String error = "Create VFModule: Attached Volume Group DOES NOT EXIST " + volumeGroupId + " in " + cloudSiteId + "/" + tenantId + " USER ERROR"; logger.error(BRACKETS, MessageEnum.RA_QUERY_VNF_ERR.toString(), volumeGroupId, cloudSiteId, tenantId, - error, CLOUDIFY, "queryDeployment(volume)", ErrorCode.BusinessProcesssError.getValue(), + error, CLOUDIFY, "queryDeployment(volume)", ErrorCode.BusinessProcessError.getValue(), "Create VFModule: Attached Volume Group DOES NOT EXIST"); logger.debug(error); throw new VnfException(error, MsoExceptionCategory.USERDATA); @@ -774,7 +774,7 @@ public class MsoVnfCloudifyAdapterImpl implements MsoVnfAdapter { + cloudSiteId + "/" + tenantId + " USER ERROR"; logger.error(BRACKETS, MessageEnum.RA_QUERY_VNF_ERR.toString(), baseVfModuleId, cloudSiteId, tenantId, error, CLOUDIFY, "queryDeployment(Base)", - ErrorCode.BusinessProcesssError.getValue(), + ErrorCode.BusinessProcessError.getValue(), "Create VFModule: Base " + "Module DOES NOT EXIST"); logger.debug(error); throw new VnfException(error, MsoExceptionCategory.USERDATA); @@ -1081,8 +1081,9 @@ public class MsoVnfCloudifyAdapterImpl implements MsoVnfAdapter { } - public void deleteVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfName, - MsoRequest msoRequest, Holder<Map<String, String>> outputs) throws VnfException { + public void deleteVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vnfName, String vnfId, + String vfModuleId, String modelCustomizationUuid, MsoRequest msoRequest, + Holder<Map<String, String>> outputs) throws VnfException { logger.debug("Deleting VF " + vnfName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId); // 1702 capture the output parameters on a delete diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfPluginAdapterImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfPluginAdapterImpl.java index 41bcc8c481..b1f4055b3b 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfPluginAdapterImpl.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfPluginAdapterImpl.java @@ -643,7 +643,7 @@ public class MsoVnfPluginAdapterImpl implements MsoVnfAdapter { + " VersionMin=" + vnfMin + " VersionMax:" + vnfMax + " NOT supported on Cloud: " + cloudSiteId + " with AIC_Version:" + cloudSite.getCloudVersion(); logger.error(LoggingAnchor.FIVE, MessageEnum.RA_CONFIG_EXC.toString(), error, "OpenStack", - ErrorCode.BusinessProcesssError.getValue(), "Exception - setVersion"); + ErrorCode.BusinessProcessError.getValue(), "Exception - setVersion"); logger.debug(error); throw new VnfException(error, MsoExceptionCategory.USERDATA); } @@ -773,7 +773,7 @@ public class MsoVnfPluginAdapterImpl implements MsoVnfAdapter { + cloudOwner + "/" + cloudSiteId + "/" + tenantId + " USER ERROR"; logger.error(LoggingAnchor.TEN, MessageEnum.RA_QUERY_VNF_ERR.toString(), volumeGroupId, cloudOwner, cloudSiteId, tenantId, error, "VDU", "queryVdu(volume)", - ErrorCode.BusinessProcesssError.getValue(), + ErrorCode.BusinessProcessError.getValue(), "Create VFModule: Attached Volume Group " + "DOES NOT EXIST"); logger.debug(error); throw new VnfException(error, MsoExceptionCategory.USERDATA); @@ -822,7 +822,7 @@ public class MsoVnfPluginAdapterImpl implements MsoVnfAdapter { + "/" + cloudSiteId + "/" + tenantId + " USER ERROR"; logger.error(LoggingAnchor.TEN, MessageEnum.RA_QUERY_VNF_ERR.toString(), baseVfModuleId, cloudOwner, cloudSiteId, tenantId, error, "VDU", "queryVdu(Base)", - ErrorCode.BusinessProcesssError.getValue(), "Create VFModule: Base Module DOES NOT EXIST"); + ErrorCode.BusinessProcessError.getValue(), "Create VFModule: Base Module DOES NOT EXIST"); logger.debug(error); throw new VnfException(error, MsoExceptionCategory.USERDATA); } else { @@ -1072,8 +1072,9 @@ public class MsoVnfPluginAdapterImpl implements MsoVnfAdapter { } - public void deleteVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vfModuleId, - MsoRequest msoRequest, Holder<Map<String, String>> outputs) throws VnfException { + public void deleteVfModule(String cloudSiteId, String cloudOwner, String tenantId, String vfModuleId, String vnfId, + String aaiVfModuleId, String modelCustomizationUuid, MsoRequest msoRequest, + Holder<Map<String, String>> outputs) throws VnfException { logger.debug("Deleting VF Module " + vfModuleId + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId); diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRest.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRest.java index 8c871c742e..0fb11ebbf3 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRest.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRest.java @@ -130,7 +130,7 @@ public class VnfAdapterRest { } catch (Exception e) { // problem handling delete, send generic failure as sync resp to caller logger.error("", MessageEnum.RA_DELETE_VNF_ERR.toString(), "deleteVfModule", - ErrorCode.BusinessProcesssError.getValue(), "Exception in deleteVfModule", e); + ErrorCode.BusinessProcessError.getValue(), "Exception in deleteVfModule", e); return Response.serverError().build(); } // send sync response (ACK) to caller @@ -179,13 +179,14 @@ public class VnfAdapterRest { Holder<Map<String, String>> outputs = new Holder<>(); if (cloudsite != null && !cloudsite.equals(TESTING_KEYWORD)) { vnfAdapter.deleteVfModule(req.getCloudSiteId(), req.getCloudOwner(), req.getTenantId(), - req.getVfModuleStackId(), req.getMsoRequest(), outputs); + req.getVfModuleStackId(), req.getVnfId(), req.getVfModuleId(), + req.getModelCustomizationUuid(), req.getMsoRequest(), outputs); } response = new DeleteVfModuleResponse(req.getVnfId(), req.getVfModuleId(), Boolean.TRUE, req.getMessageId(), outputs.value); } catch (VnfException e) { logger.error(LoggingAnchor.THREE, MessageEnum.RA_DELETE_VNF_ERR.toString(), - ErrorCode.BusinessProcesssError.getValue(), "VnfException - Delete VNF Module", e); + ErrorCode.BusinessProcessError.getValue(), "VnfException - Delete VNF Module", e); eresp = new VfModuleExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.TRUE, req.getMessageId()); } @@ -243,7 +244,7 @@ public class VnfAdapterRest { return Response.status(respStatus).entity(new GenericEntity<QueryVfModuleResponse>(qryResp) {}).build(); } catch (VnfException e) { logger.error(LoggingAnchor.FIVE, MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, "queryVfModule", - ErrorCode.BusinessProcesssError.getValue(), "VnfException - queryVfModule", e); + ErrorCode.BusinessProcessError.getValue(), "VnfException - queryVfModule", e); VfModuleExceptionResponse excResp = new VfModuleExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.FALSE, null); return Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR) @@ -290,7 +291,7 @@ public class VnfAdapterRest { } catch (Exception e) { // problem handling create, send generic failure as sync resp to caller logger.error(LoggingAnchor.FOUR, MessageEnum.RA_CREATE_VNF_ERR, "createVfModule", - ErrorCode.BusinessProcesssError, "Exception - createVfModule", e); + ErrorCode.BusinessProcessError, "Exception - createVfModule", e); return Response.serverError().build(); } // send sync response (ACK) to caller @@ -405,7 +406,7 @@ public class VnfAdapterRest { } catch (Exception e) { // problem handling create, send generic failure as sync resp to caller logger.error(LoggingAnchor.FOUR, MessageEnum.RA_UPDATE_VNF_ERR.toString(), "updateVfModule", - ErrorCode.BusinessProcesssError.getValue(), "Exception - updateVfModule", e); + ErrorCode.BusinessProcessError.getValue(), "Exception - updateVfModule", e); return Response.serverError().build(); } // send sync response (ACK) to caller @@ -509,7 +510,7 @@ public class VnfAdapterRest { } catch (Exception e) { // problem handling create, send generic failure as sync resp to caller logger.error(LoggingAnchor.FOUR, MessageEnum.RA_ROLLBACK_VNF_ERR.toString(), "rollbackVfModule", - ErrorCode.BusinessProcesssError.getValue(), "Exception - rollbackVfModule", e); + ErrorCode.BusinessProcessError.getValue(), "Exception - rollbackVfModule", e); return Response.serverError().build(); } // send sync response (ACK) to caller @@ -560,7 +561,7 @@ public class VnfAdapterRest { vnfAdapter.rollbackVnf(vrb); response = new RollbackVfModuleResponse(Boolean.TRUE, req.getMessageId()); } catch (VnfException e) { - logger.error(LoggingAnchor.THREE, MessageEnum.RA_ROLLBACK_VNF_ERR, ErrorCode.BusinessProcesssError, + logger.error(LoggingAnchor.THREE, MessageEnum.RA_ROLLBACK_VNF_ERR, ErrorCode.BusinessProcessError, "Exception" + " - " + "rollbackVfModule", e); eresp = new VfModuleExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, false, req.getMessageId()); diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRestV2.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRestV2.java index 9a7354c40c..fcb570f3f5 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRestV2.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VnfAdapterRestV2.java @@ -140,7 +140,7 @@ public class VnfAdapterRestV2 { } catch (Exception e) { // problem handling delete, send generic failure as sync resp to caller logger.error(BRACKETS, MessageEnum.RA_DELETE_VNF_ERR.toString(), "deleteVfModule", - ErrorCode.BusinessProcesssError.getValue(), "Exception in deleteVfModule", e); + ErrorCode.BusinessProcessError.getValue(), "Exception in deleteVfModule", e); return Response.serverError().build(); } // send sync response (ACK) to caller @@ -195,13 +195,14 @@ public class VnfAdapterRestV2 { // Support different Adapter Implementations MsoVnfAdapter adapter = vnfAdapterRestUtils.getVnfAdapterImpl(mode, cloudsite); adapter.deleteVfModule(req.getCloudSiteId(), req.getCloudOwner(), req.getTenantId(), - req.getVfModuleStackId(), req.getMsoRequest(), outputs); + req.getVfModuleStackId(), req.getVnfId(), req.getVfModuleId(), + req.getModelCustomizationUuid(), req.getMsoRequest(), outputs); } response = new DeleteVfModuleResponse(req.getVnfId(), req.getVfModuleId(), Boolean.TRUE, req.getMessageId(), outputs.value); } catch (VnfException e) { logger.error(LoggingAnchor.THREE, MessageEnum.RA_DELETE_VNF_ERR.toString(), - ErrorCode.BusinessProcesssError.getValue(), "VnfException - " + "Delete VNF Module", e); + ErrorCode.BusinessProcessError.getValue(), "VnfException - " + "Delete VNF Module", e); eresp = new VfModuleExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.TRUE, req.getMessageId()); } @@ -271,7 +272,7 @@ public class VnfAdapterRestV2 { return Response.status(respStatus).entity(new GenericEntity<QueryVfModuleResponse>(qryResp) {}).build(); } catch (VnfException e) { logger.error(LoggingAnchor.FIVE, MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, "queryVfModule", - ErrorCode.BusinessProcesssError.getValue(), "VnfException - queryVfModule", e); + ErrorCode.BusinessProcessError.getValue(), "VnfException - queryVfModule", e); VfModuleExceptionResponse excResp = new VfModuleExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.FALSE, null); return Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR) @@ -320,7 +321,7 @@ public class VnfAdapterRestV2 { } catch (Exception e) { // problem handling create, send generic failure as sync resp to caller logger.error(BRACKETS, MessageEnum.RA_CREATE_VNF_ERR.toString(), "createVfModule", - ErrorCode.BusinessProcesssError.getValue(), "Exception - createVfModule", e); + ErrorCode.BusinessProcessError.getValue(), "Exception - createVfModule", e); return Response.serverError().build(); } // send sync response (ACK) to caller @@ -440,7 +441,7 @@ public class VnfAdapterRestV2 { } catch (Exception e) { // problem handling create, send generic failure as sync resp to caller logger.error(BRACKETS, MessageEnum.RA_UPDATE_VNF_ERR.toString(), "updateVfModule", - ErrorCode.BusinessProcesssError.getValue(), "Exception - updateVfModule", e); + ErrorCode.BusinessProcessError.getValue(), "Exception - updateVfModule", e); return Response.serverError().build(); } // send sync response (ACK) to caller @@ -555,7 +556,7 @@ public class VnfAdapterRestV2 { } catch (Exception e) { // problem handling create, send generic failure as sync resp to caller logger.error(BRACKETS, MessageEnum.RA_ROLLBACK_VNF_ERR.toString(), "rollbackVfModule", - ErrorCode.BusinessProcesssError.getValue(), "Exception - rollbackVfModule", e); + ErrorCode.BusinessProcessError.getValue(), "Exception - rollbackVfModule", e); return Response.serverError().build(); } // send sync response (ACK) to caller @@ -612,7 +613,7 @@ public class VnfAdapterRestV2 { response = new RollbackVfModuleResponse(Boolean.TRUE, req.getMessageId()); } catch (VnfException e) { logger.error(LoggingAnchor.THREE, MessageEnum.RA_ROLLBACK_VNF_ERR.toString(), - ErrorCode.BusinessProcesssError.getValue(), "Exception - rollbackVfModule", e); + ErrorCode.BusinessProcessError.getValue(), "Exception - rollbackVfModule", e); eresp = new VfModuleExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, false, req.getMessageId()); } diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VolumeAdapterRest.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VolumeAdapterRest.java index 87df7fdc37..c9e046ca43 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VolumeAdapterRest.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VolumeAdapterRest.java @@ -118,7 +118,7 @@ public class VolumeAdapterRest { } catch (Exception e) { // problem handling create, send generic failure as sync resp to caller logger.error("{} {} Exception - createVNFVolumes: ", MessageEnum.RA_CREATE_VNF_ERR, - ErrorCode.BusinessProcesssError.getValue(), e); + ErrorCode.BusinessProcessError.getValue(), e); return Response.serverError().build(); } // send sync response (ACK) to caller @@ -270,7 +270,7 @@ public class VolumeAdapterRest { } catch (Exception e) { // problem handling create, send generic failure as sync resp to caller logger.error("{} {} Exception - deleteVNFVolumes: ", MessageEnum.RA_DELETE_VNF_ERR, - ErrorCode.BusinessProcesssError.getValue(), e); + ErrorCode.BusinessProcessError.getValue(), e); return Response.serverError().build(); } // send sync response (ACK) to caller @@ -367,7 +367,7 @@ public class VolumeAdapterRest { } catch (Exception e) { // problem handling create, send generic failure as sync resp to caller logger.error("{} {} Exception - rollbackVNFVolumes: ", MessageEnum.RA_ROLLBACK_VNF_ERR, - ErrorCode.BusinessProcesssError.getValue(), e); + ErrorCode.BusinessProcessError.getValue(), e); return Response.serverError().build(); } // send sync response (ACK) to caller @@ -463,7 +463,7 @@ public class VolumeAdapterRest { } catch (Exception e) { // problem handling create, send generic failure as sync resp to caller logger.error("{} {} Exception - updateVNFVolumes: ", MessageEnum.RA_UPDATE_VNF_ERR, - ErrorCode.BusinessProcesssError.getValue(), e); + ErrorCode.BusinessProcessError.getValue(), e); return Response.serverError().build(); } // send sync response (ACK) to caller @@ -607,7 +607,7 @@ public class VolumeAdapterRest { return Response.status(respStatus).entity(new GenericEntity<QueryVolumeGroupResponse>(qryResp) {}).build(); } catch (VnfException e) { logger.error("{} {} AaiVolumeGroupId: {} VnfException - queryVNFVolumes", MessageEnum.RA_QUERY_VNF_ERR, - ErrorCode.BusinessProcesssError.getValue(), aaiVolumeGroupId, e); + ErrorCode.BusinessProcessError.getValue(), aaiVolumeGroupId, e); VolumeGroupExceptionResponse excResp = new VolumeGroupExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.FALSE, null); logger.debug("Query queryVNFVolumes exit"); diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VolumeAdapterRestV2.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VolumeAdapterRestV2.java index 77c9b1e2f5..2b7234aca6 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VolumeAdapterRestV2.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/VolumeAdapterRestV2.java @@ -105,7 +105,6 @@ public class VolumeAdapterRestV2 { @ApiResponse(code = 500, message = "create vnfVolume failed, examine entity object for details")}) public Response createVNFVolumes(@ApiParam(value = "mode", required = true) @QueryParam("mode") String mode, @ApiParam(value = "CreateVolumeGroupRequest", required = true) final CreateVolumeGroupRequest req) { - logger.debug("createVNFVolumes enter: {}", req.toJsonString()); CreateVNFVolumesTask task = new CreateVNFVolumesTask(req, mode); if (req.isSynchronous()) { // This is a synchronous request @@ -119,7 +118,7 @@ public class VolumeAdapterRestV2 { } catch (Exception e) { // problem handling create, send generic failure as sync resp to caller logger.error("{} {} Exception - createVNFVolumes: ", MessageEnum.RA_CREATE_VNF_ERR, - ErrorCode.BusinessProcesssError.getValue(), e); + ErrorCode.BusinessProcessError.getValue(), e); return Response.serverError().build(); } // send sync response (ACK) to caller @@ -254,7 +253,7 @@ public class VolumeAdapterRestV2 { } catch (Exception e) { // problem handling create, send generic failure as sync resp to caller logger.error("{} {} Exception - deleteVNFVolumes: ", MessageEnum.RA_DELETE_VNF_ERR, - ErrorCode.BusinessProcesssError.getValue(), e); + ErrorCode.BusinessProcessError.getValue(), e); return Response.serverError().build(); } // send sync response (ACK) to caller @@ -356,7 +355,7 @@ public class VolumeAdapterRestV2 { } catch (Exception e) { // problem handling create, send generic failure as sync resp to caller logger.error("{} {} Exception - rollbackVNFVolumes: ", MessageEnum.RA_ROLLBACK_VNF_ERR, - ErrorCode.BusinessProcesssError.getValue(), e); + ErrorCode.BusinessProcessError.getValue(), e); return Response.serverError().build(); } // send sync response (ACK) to caller @@ -456,7 +455,7 @@ public class VolumeAdapterRestV2 { } catch (Exception e) { // problem handling create, send generic failure as sync resp to caller logger.error("{} {} Exception - updateVNFVolumes: ", MessageEnum.RA_UPDATE_VNF_ERR, - ErrorCode.BusinessProcesssError.getValue(), e); + ErrorCode.BusinessProcessError.getValue(), e); return Response.serverError().build(); } // send sync response (ACK) to caller @@ -595,7 +594,7 @@ public class VolumeAdapterRestV2 { return Response.status(respStatus).entity(new GenericEntity<QueryVolumeGroupResponse>(qryResp) {}).build(); } catch (VnfException e) { logger.error("{} {} AaiVolumeGroupId: {} VnfException - queryVNFVolumes: ", MessageEnum.RA_QUERY_VNF_ERR, - ErrorCode.BusinessProcesssError.getValue(), aaiVolumeGroupId, e); + ErrorCode.BusinessProcessError.getValue(), aaiVolumeGroupId, e); VolumeGroupExceptionResponse excResp = new VolumeGroupExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.FALSE, null); logger.debug("Query queryVNFVolumes exit"); diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/HeatBridgeApi.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/HeatBridgeApi.java index aebd04f32c..7eff09b692 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/HeatBridgeApi.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/HeatBridgeApi.java @@ -138,9 +138,23 @@ public interface HeatBridgeApi { void buildAddVserverLInterfacesToAaiAction(List<Resource> stackResources, List<String> oobMgtNetIds); /** + * Query and build AAI actions for Openstack Compute resources to AAI's pserver and pinterface objects + * + * @param stackResources Openstack StackResources list + */ + void createPserversAndPinterfacesIfNotPresentInAai(final List<Resource> stackResources) throws HeatBridgeException; + + /** * Execute AAI restful API to update the Openstack resources * * @throws HeatBridgeException when failing to add openstack resource PoJos to AAI */ void submitToAai() throws HeatBridgeException; + + /** + * Delete heatbridge data for a given vf-module + * + * @throws HeatBridgeException when failing to remove heatbridge data from AAI for a given vf-module + */ + void deleteVfModuleData(String vnfId, String vfModuleId) throws HeatBridgeException; } diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/HeatBridgeImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/HeatBridgeImpl.java index ae15b70b00..e2022c9a6e 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/HeatBridgeImpl.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/HeatBridgeImpl.java @@ -32,6 +32,7 @@ */ package org.onap.so.heatbridge; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -49,6 +50,7 @@ import org.onap.aai.domain.yang.Image; import org.onap.aai.domain.yang.L3InterfaceIpv4AddressList; import org.onap.aai.domain.yang.LInterface; import org.onap.aai.domain.yang.PInterface; +import org.onap.aai.domain.yang.Pserver; import org.onap.aai.domain.yang.SriovPf; import org.onap.aai.domain.yang.SriovPfs; import org.onap.aai.domain.yang.SriovVf; @@ -56,13 +58,17 @@ import org.onap.aai.domain.yang.SriovVfs; import org.onap.aai.domain.yang.Vlan; import org.onap.aai.domain.yang.Vlans; import org.onap.aai.domain.yang.Vserver; +import org.onap.aai.domain.yang.VfModule; import org.onap.so.client.aai.AAIObjectType; import org.onap.so.client.aai.AAIResourcesClient; import org.onap.so.client.aai.AAISingleTransactionClient; +import org.onap.so.client.aai.entities.AAIResultWrapper; +import org.onap.so.client.aai.entities.Relationships; import org.onap.so.client.aai.entities.uri.AAIResourceUri; import org.onap.so.client.aai.entities.uri.AAIUriFactory; import org.onap.so.client.graphinventory.entities.uri.Depth; import org.onap.so.client.graphinventory.exceptions.BulkProcessFailed; +import org.onap.so.client.PreconditionFailedException; import org.onap.so.db.catalog.beans.CloudIdentity; import org.onap.so.heatbridge.constants.HeatBridgeConstants; import org.onap.so.heatbridge.factory.MsoCloudClientFactoryImpl; @@ -99,33 +105,39 @@ public class HeatBridgeImpl implements HeatBridgeApi { private AAISingleTransactionClient transaction; private String cloudOwner; private String cloudRegionId; + private String regionId; private String tenantId; private AaiHelper aaiHelper = new AaiHelper(); private CloudIdentity cloudIdentity; - public HeatBridgeImpl(AAIResourcesClient resourcesClient, final CloudIdentity cloudIdentity, - @Nonnull final String cloudOwner, @Nonnull final String cloudRegionId, @Nonnull final String tenantId) { + @Nonnull final String cloudOwner, @Nonnull final String cloudRegionId, @Nonnull final String regionId, + @Nonnull final String tenantId) { Objects.requireNonNull(cloudOwner, "Null cloud-owner value!"); Objects.requireNonNull(cloudRegionId, "Null cloud-region identifier!"); Objects.requireNonNull(tenantId, "Null tenant identifier!"); - Objects.requireNonNull(tenantId, "Null AAI actions list!"); + Objects.requireNonNull(regionId, "Null regionId identifier!"); this.cloudIdentity = cloudIdentity; this.cloudOwner = cloudOwner; this.cloudRegionId = cloudRegionId; + this.regionId = regionId; this.tenantId = tenantId; this.resourcesClient = resourcesClient; this.transaction = resourcesClient.beginSingleTransaction(); } + public HeatBridgeImpl() { + this.resourcesClient = new AAIResourcesClient(); + this.transaction = resourcesClient.beginSingleTransaction(); + } + @Override public OpenstackClient authenticate() throws HeatBridgeException { this.osClient = new MsoCloudClientFactoryImpl(new OpenstackClientFactoryImpl()).getOpenstackClient( - cloudIdentity.getIdentityUrl(), cloudIdentity.getMsoId(), cloudIdentity.getMsoPass(), cloudRegionId, + cloudIdentity.getIdentityUrl(), cloudIdentity.getMsoId(), cloudIdentity.getMsoPass(), regionId, tenantId); - logger.debug("Successfully authenticated with keystone for tenant: " + tenantId + " and cloud " + "region: " - + cloudRegionId); + logger.debug("Successfully authenticated with keystone for tenant: " + tenantId + " and region: " + regionId); return osClient; } @@ -263,6 +275,44 @@ public class HeatBridgeImpl implements HeatBridgeApi { } } + @Override + public void createPserversAndPinterfacesIfNotPresentInAai(final List<Resource> stackResources) + throws HeatBridgeException { + Map<String, Pserver> serverHostnames = getPserverMapping(stackResources); + createPServerIfNotExists(serverHostnames); + List<String> portIds = + extractStackResourceIdsByResourceType(stackResources, HeatBridgeConstants.OS_PORT_RESOURCE_TYPE); + for (String portId : portIds) { + Port port = osClient.getPortById(portId); + if (port.getvNicType().equalsIgnoreCase(HeatBridgeConstants.OS_SRIOV_PORT_TYPE)) { + createPServerPInterfaceIfNotExists(serverHostnames.get(port.getHostId()).getHostname(), + aaiHelper.buildPInterface(port)); + } + } + } + + private Map<String, Pserver> getPserverMapping(final List<Resource> stackResources) { + List<Server> osServers = getAllOpenstackServers(stackResources); + Map<String, Pserver> pserverMap = new HashMap<>(); + for (Server server : osServers) { + pserverMap.put(server.getHost(), aaiHelper.buildPserver(server)); + } + return pserverMap; + } + + private void createPServerIfNotExists(Map<String, Pserver> serverHostnames) { + for (Pserver pserver : serverHostnames.values()) { + AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectType.PSERVER, pserver.getHostname()); + resourcesClient.createIfNotExists(uri, Optional.of(pserver)); + } + } + + private void createPServerPInterfaceIfNotExists(String pserverHostname, PInterface pInterface) { + AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectType.P_INTERFACE, pserverHostname, + pInterface.getInterfaceName()); + resourcesClient.createIfNotExists(uri, Optional.of(pInterface)); + } + private void updateLInterfaceVlan(final Port port, final LInterface lIf) { Vlan vlan = new Vlan(); Network network = osClient.getNetworkById(port.getNetworkId()); @@ -377,6 +427,78 @@ public class HeatBridgeImpl implements HeatBridgeApi { } } + @Override + public void deleteVfModuleData(@Nonnull final String vnfId, @Nonnull final String vfModuleId) + throws HeatBridgeException { + Objects.requireNonNull(vnfId, "Null vnf-id!"); + Objects.requireNonNull(vfModuleId, "Null vf-module-id!"); + try { + Optional<VfModule> vfModule = resourcesClient.get(VfModule.class, + AAIUriFactory.createResourceUri(AAIObjectType.VF_MODULE, vnfId, vfModuleId).depth(Depth.ONE)); + if (vfModule.isPresent()) { + + AAIResultWrapper resultWrapper = new AAIResultWrapper(vfModule); + Optional<Relationships> relationships = resultWrapper.getRelationships(); + if (relationships.isPresent()) { + List<AAIResourceUri> vserverUris = relationships.get().getRelatedUris(AAIObjectType.VSERVER); + createTransactionToDeleteSriovPfFromPserver(vserverUris); + if (!vserverUris.isEmpty()) { + for (AAIResourceUri vserverUri : vserverUris) { + resourcesClient.delete(vserverUri); + } + } + } + } + } catch (Exception e) { + String msg = "Failed to commit delete heatbridge data transaction"; + logger.debug(msg + " with error: " + e); + throw new HeatBridgeException(msg, e); + } + } + + private void createTransactionToDeleteSriovPfFromPserver(List<AAIResourceUri> vserverUris) { + Map<String, List<String>> pserverToPciIdMap = getPserverToPciIdMap(vserverUris); + for (Map.Entry<String, List<String>> entry : pserverToPciIdMap.entrySet()) { + String pserverName = entry.getKey(); + List<String> pciIds = entry.getValue(); + Optional<Pserver> pserver = resourcesClient.get(Pserver.class, + AAIUriFactory.createResourceUri(AAIObjectType.PSERVER, pserverName).depth(Depth.TWO)); + if (pserver.isPresent()) { + // For each pserver/p-interface match sriov-vfs by pic-id and delete them. + pserver.get().getPInterfaces().getPInterface().stream().filter( + pIf -> pIf.getSriovPfs() != null && CollectionUtils.isNotEmpty(pIf.getSriovPfs().getSriovPf())) + .forEach(pIf -> pIf.getSriovPfs().getSriovPf().forEach(sriovPf -> { + if (pciIds.contains(sriovPf.getPfPciId())) { + logger.debug("creating transaction to delete SR-IOV PF: " + pIf.getInterfaceName() + + " from PServer: " + pserverName); + resourcesClient.delete(AAIUriFactory.createResourceUri(AAIObjectType.SRIOV_PF, + pserverName, pIf.getInterfaceName(), sriovPf.getPfPciId())); + } + })); + } + } + } + + private Map<String, List<String>> getPserverToPciIdMap(List<AAIResourceUri> vserverUris) { + Map<String, List<String>> pserverToPciIdMap = new HashMap<>(); + for (AAIResourceUri vserverUri : vserverUris) { + AAIResultWrapper vserverWrapper = resourcesClient.get(vserverUri.depth(Depth.TWO)); + Optional<Relationships> vserverRelationships = vserverWrapper.getRelationships(); + if (vserverRelationships.isPresent() + && CollectionUtils.isNotEmpty(vserverRelationships.get().getRelatedLinks(AAIObjectType.PSERVER))) { + Vserver vserver = vserverWrapper.asBean(Vserver.class).get(); + List<String> pciIds = HeatBridgeUtils.extractPciIdsFromVServer(vserver); + if (CollectionUtils.isNotEmpty(pciIds)) { + List<String> matchingPservers = vserverRelationships.get().getRelatedLinks(AAIObjectType.PSERVER); + if (matchingPservers != null && matchingPservers.size() == 1) { + pserverToPciIdMap.put(matchingPservers.get(0), pciIds); + } + } + } + } + return pserverToPciIdMap; + } + private <T> Predicate<T> distinctByProperty(Function<? super T, Object> keyExtractor) { Map<Object, Boolean> map = new ConcurrentHashMap<>(); return t -> map.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null; diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/constants/HeatBridgeConstants.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/constants/HeatBridgeConstants.java index f2d61d2587..0e87e1fb31 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/constants/HeatBridgeConstants.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/constants/HeatBridgeConstants.java @@ -43,6 +43,7 @@ public class HeatBridgeConstants { public static final String OS_SRIOV_PORT_TYPE = "direct"; public static final String OS_PCI_SLOT_KEY = "pci_slot"; public static final String OS_PHYSICAL_NETWORK_KEY = "physical_network"; + public static final String OS_PHYSICAL_INTERFACE_KEY = "physical-interface"; public static final String OS_VLAN_NETWORK_KEY = "vlan"; public static final String OS_UNKNOWN_KEY = "unknown"; public static final String OS_RESOURCES_SELF_LINK_KEY = "self"; diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/factory/MsoCloudClientFactory.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/factory/MsoCloudClientFactory.java index 018a4eac8d..e1f363ca05 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/factory/MsoCloudClientFactory.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/factory/MsoCloudClientFactory.java @@ -47,13 +47,13 @@ public interface MsoCloudClientFactory { * @param url openstack url * @param msoId openstack user for mso * @param msoPass openstack password for mso user - * @param cloudRegionId cloud-region identifier + * @param regionId region identifier * @param tenantId tenant identifier * @return Openstack Client for the keystone version requested * @throws HeatBridgeException if any errors when reading cloud configuration or getting openstack client */ - OpenstackClient getOpenstackClient(String url, String msoId, String msoPass, String cloudRegionId, String tenantId) + OpenstackClient getOpenstackClient(String url, String msoId, String msoPass, String regionId, String tenantId) throws HeatBridgeException; } diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/factory/MsoCloudClientFactoryImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/factory/MsoCloudClientFactoryImpl.java index f0c5a0b434..04245899aa 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/factory/MsoCloudClientFactoryImpl.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/factory/MsoCloudClientFactoryImpl.java @@ -61,17 +61,17 @@ public class MsoCloudClientFactoryImpl implements MsoCloudClientFactory { @Override public OpenstackClient getOpenstackClient(@Nonnull String url, @Nonnull String msoId, @Nonnull String msoPass, - @Nonnull String cloudRegionId, @Nonnull String tenantId) throws HeatBridgeException { + @Nonnull String regionId, @Nonnull String tenantId) throws HeatBridgeException { Objects.requireNonNull(url, "Null openstack url!"); Objects.requireNonNull(msoId, "Null openstack user id!"); Objects.requireNonNull(msoPass, "Null openstack password!"); - Objects.requireNonNull(cloudRegionId, "Null cloud-region ID!"); + Objects.requireNonNull(regionId, "Null regionId ID!"); Objects.requireNonNull(tenantId, "Null tenant ID!"); try { final OpenstackAccess osAccess = new OpenstackAccessBuilder().setBaseUrl(url) // keystone URL .setUser(msoId) // keystone username .setPassword(CryptoUtils.decryptCloudConfigPassword(msoPass)) // keystone decrypted password - .setRegion(cloudRegionId) // openstack region + .setRegion(regionId) // openstack region .setDomainName(HeatBridgeConstants.OS_DEFAULT_DOMAIN_NAME) // hardcode to "default" .setTenantId(tenantId) // tenantId .build(); diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/helpers/AaiHelper.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/helpers/AaiHelper.java index 137aaa9f41..c578b29664 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/helpers/AaiHelper.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/helpers/AaiHelper.java @@ -43,6 +43,8 @@ import java.util.stream.Collectors; import org.apache.commons.collections.CollectionUtils; import org.onap.aai.domain.yang.Flavor; import org.onap.aai.domain.yang.Image; +import org.onap.aai.domain.yang.PInterface; +import org.onap.aai.domain.yang.Pserver; import org.onap.aai.domain.yang.Relationship; import org.onap.aai.domain.yang.RelationshipData; import org.onap.aai.domain.yang.RelationshipList; @@ -50,6 +52,7 @@ import org.onap.aai.domain.yang.SriovVf; import org.onap.aai.domain.yang.Vserver; import org.onap.so.heatbridge.constants.HeatBridgeConstants; import org.openstack4j.model.compute.Server; +import org.openstack4j.model.network.Port; /** * This class provides wrapper methods to manage creation of AAI objects and extracting objects from AAI and @@ -84,11 +87,13 @@ public class AaiHelper { relationships.add(vfModuleRelationship); // vserver to image relationship - Relationship imageRel = buildRelationship(HeatBridgeConstants.AAI_IMAGE, - ImmutableMap.<String, String>builder().put(HeatBridgeConstants.AAI_CLOUD_OWNER, cloudOwner) - .put(HeatBridgeConstants.AAI_CLOUD_REGION_ID, cloudRegionId) - .put(HeatBridgeConstants.AAI_IMAGE_ID, server.getImage().getId()).build()); - relationships.add(imageRel); + if (server.getImage() != null) { + Relationship imageRel = buildRelationship(HeatBridgeConstants.AAI_IMAGE, + ImmutableMap.<String, String>builder().put(HeatBridgeConstants.AAI_CLOUD_OWNER, cloudOwner) + .put(HeatBridgeConstants.AAI_CLOUD_REGION_ID, cloudRegionId) + .put(HeatBridgeConstants.AAI_IMAGE_ID, server.getImage().getId()).build()); + relationships.add(imageRel); + } // vserver to flavor relationship Relationship flavorRel = buildRelationship(HeatBridgeConstants.AAI_FLAVOR, @@ -135,6 +140,37 @@ public class AaiHelper { } /** + * Transform Openstack Server object to AAI Pserver object + * + * @param server Openstack server object + * @return AAI Pserver object + */ + public Pserver buildPserver(final Server server) { + Pserver pserver = new Pserver(); + pserver.setInMaint(false); + pserver.setPserverId(server.getId()); + pserver.setHostname(server.getHypervisorHostname()); + pserver.setPserverName2(server.getHost()); + pserver.setProvStatus(server.getStatus().value()); + return pserver; + } + + /** + * Transform Openstack Server object to AAI PInterface object + * + * @param port Openstack port object + * @return AAI PInterface object + */ + public PInterface buildPInterface(Port port) { + Map<String, Object> portProfile = port.getProfile(); + PInterface pInterface = new PInterface(); + pInterface.setInterfaceName(portProfile.get(HeatBridgeConstants.OS_PHYSICAL_NETWORK_KEY).toString()); + pInterface.setInMaint(false); + pInterface.setInterfaceRole(HeatBridgeConstants.OS_PHYSICAL_INTERFACE_KEY); + return pInterface; + } + + /** * Transform Openstack Image object to AAI Image object * * @param image Openstack Image object diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/utils/HeatBridgeUtils.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/utils/HeatBridgeUtils.java index be086677db..1667f980e1 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/utils/HeatBridgeUtils.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/utils/HeatBridgeUtils.java @@ -35,10 +35,15 @@ package org.onap.so.heatbridge.utils; import com.google.common.base.Preconditions; import com.google.common.base.Strings; +import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; import javax.annotation.Nonnull; +import org.apache.commons.collections.CollectionUtils; +import org.onap.aai.domain.yang.SriovVf; +import org.onap.aai.domain.yang.Vserver; -public class HeatBridgeUtils { +public final class HeatBridgeUtils { /** * IaaS naming convention for compute/p-interface to openstack/physical-network name mapping @@ -64,4 +69,13 @@ public class HeatBridgeUtils { } return Optional.empty(); } + + public static List<String> extractPciIdsFromVServer(Vserver vserver) { + return vserver.getLInterfaces().getLInterface().stream() + .filter(lInterface -> lInterface.getSriovVfs() != null + && CollectionUtils.isNotEmpty(lInterface.getSriovVfs().getSriovVf())) + .flatMap(lInterface -> lInterface.getSriovVfs().getSriovVf().stream()).map(SriovVf::getPciId) + .collect(Collectors.toList()); + } + } diff --git a/adapters/mso-openstack-adapters/src/main/resources/application-aaf.yaml b/adapters/mso-openstack-adapters/src/main/resources/application-aaf.yaml new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/resources/application-aaf.yaml diff --git a/adapters/mso-openstack-adapters/src/main/resources/application-basic.yaml b/adapters/mso-openstack-adapters/src/main/resources/application-basic.yaml new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/resources/application-basic.yaml diff --git a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/audit/AuditStackServiceDataTest.java b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/audit/AuditStackServiceDataTest.java index 3432e4a8b6..cff4d5f994 100644 --- a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/audit/AuditStackServiceDataTest.java +++ b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/audit/AuditStackServiceDataTest.java @@ -37,6 +37,7 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.onap.so.audit.beans.AuditInventory; +import org.onap.so.externaltasks.logging.AuditMDCSetup; import org.onap.so.objects.audit.AAIObjectAuditList; import org.springframework.core.env.Environment; import com.fasterxml.jackson.core.JsonParseException; @@ -67,6 +68,9 @@ public class AuditStackServiceDataTest extends AuditCreateStackService { @Mock private AuditDataService auditDataService; + @Mock + private AuditMDCSetup mdcSetup; + private ObjectMapper objectMapper = new ObjectMapper(); private AuditInventory auditInventory = new AuditInventory(); @@ -170,47 +174,6 @@ public class AuditStackServiceDataTest extends AuditCreateStackService { } @Test - public void retry_sequence_calculation_Test() { - long firstRetry = auditStackService.calculateRetryDelay(8); - assertEquals(6000L, firstRetry); - long secondRetry = auditStackService.calculateRetryDelay(7); - assertEquals(6000L, secondRetry); - long thirdRetry = auditStackService.calculateRetryDelay(6); - assertEquals(12000L, thirdRetry); - long fourthRetry = auditStackService.calculateRetryDelay(5); - assertEquals(18000L, fourthRetry); - long fifthRetry = auditStackService.calculateRetryDelay(4); - assertEquals(30000L, fifthRetry); - long sixRetry = auditStackService.calculateRetryDelay(3); - assertEquals(48000L, sixRetry); - long seventhRetry = auditStackService.calculateRetryDelay(2); - assertEquals(78000L, seventhRetry); - long eigthRetry = auditStackService.calculateRetryDelay(1); - assertEquals(120000L, eigthRetry); - } - - @Test - public void retry_sequence_Test() { - long firstRetry = auditStackService.calculateRetryDelay(8); - assertEquals(6000L, firstRetry); - long secondRetry = auditStackService.calculateRetryDelay(7); - assertEquals(6000L, secondRetry); - long thirdRetry = auditStackService.calculateRetryDelay(6); - assertEquals(12000L, thirdRetry); - long fourthRetry = auditStackService.calculateRetryDelay(5); - assertEquals(18000L, fourthRetry); - long fifthRetry = auditStackService.calculateRetryDelay(4); - assertEquals(30000L, fifthRetry); - long sixRetry = auditStackService.calculateRetryDelay(3); - assertEquals(48000L, sixRetry); - long seventhRetry = auditStackService.calculateRetryDelay(2); - assertEquals(78000L, seventhRetry); - long eigthRetry = auditStackService.calculateRetryDelay(1); - assertEquals(120000L, eigthRetry); - } - - - @Test public void determineAuditResult_Test() throws Exception { boolean actual = auditStackService.didCreateAuditFail(auditListOptSuccess); assertEquals(false, actual); diff --git a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/audit/AuditStackServiceTest.java b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/audit/AuditStackServiceTest.java deleted file mode 100644 index c9aef950f7..0000000000 --- a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/audit/AuditStackServiceTest.java +++ /dev/null @@ -1,91 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * ONAP - SO - * ================================================================================ - * Copyright (C) 2017 - 2019 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * 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 org.onap.so.adapters.audit; - -import static com.shazam.shazamcrest.MatcherAssert.assertThat; -import static com.shazam.shazamcrest.matcher.Matchers.sameBeanAs; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import org.camunda.bpm.client.ExternalTaskClient; -import org.camunda.bpm.client.interceptor.ClientRequestInterceptor; -import org.camunda.bpm.client.interceptor.auth.BasicAuthProvider; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.Spy; -import org.mockito.junit.MockitoJUnitRunner; -import org.onap.so.utils.CryptoUtils; -import org.springframework.core.env.Environment; - -@RunWith(MockitoJUnitRunner.class) -public class AuditStackServiceTest { - - @Spy - @InjectMocks - AuditStackService auditStackService; - - @Mock - Environment mockEnvironment; - - - @Before - public void before() { - Mockito.doReturn("5").when(mockEnvironment).getProperty("workflow.topics.maxClients", "10"); - Mockito.doReturn("6B466C603A260F3655DBF91E53CE54667041C01406D10E8CAF9CC24D8FA5388D06F90BFE4C852052B436") - .when(mockEnvironment).getRequiredProperty("mso.auth"); - Mockito.doReturn("07a7159d3bf51a0e53be7a8f89699be7").when(mockEnvironment).getRequiredProperty("mso.msoKey"); - Mockito.doReturn("something").when(mockEnvironment).getRequiredProperty("mso.config.cadi.aafId"); - Mockito.doReturn("host.com").when(mockEnvironment).getRequiredProperty("mso.workflow.endpoint"); - } - - @Test - public void testGetMaxClients() throws Exception { - int actual = auditStackService.getMaxClients(); - assertEquals(5, actual); - } - - @Test - public void testCreateClientRequestInterceptor() throws Exception { - String auth = CryptoUtils.decrypt( - "6B466C603A260F3655DBF91E53CE54667041C01406D10E8CAF9CC24D8FA5388D06F90BFE4C852052B436", - "07a7159d3bf51a0e53be7a8f89699be7"); - ClientRequestInterceptor expected = new BasicAuthProvider("something", auth); - ClientRequestInterceptor actual = auditStackService.createClientRequestInterceptor(); - assertThat(actual, sameBeanAs(expected)); - - } - - @Test - public void testCreateExternalTaskClient() throws Exception { - String auth = CryptoUtils.decrypt( - "6B466C603A260F3655DBF91E53CE54667041C01406D10E8CAF9CC24D8FA5388D06F90BFE4C852052B436", - "07a7159d3bf51a0e53be7a8f89699be7"); - ClientRequestInterceptor inter = new BasicAuthProvider("something", auth); - Mockito.doReturn(inter).when(auditStackService).createClientRequestInterceptor(); - ExternalTaskClient actual = auditStackService.createExternalTaskClient(); - assertNotNull(actual); - Mockito.verify(auditStackService, Mockito.times(1)).createClientRequestInterceptor(); - - } -} diff --git a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/inventory/create/CreateInventoryTaskTest.java b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/inventory/create/CreateInventoryTaskTest.java index 8dc9d7fe5c..c4fa9ee2c5 100644 --- a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/inventory/create/CreateInventoryTaskTest.java +++ b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/inventory/create/CreateInventoryTaskTest.java @@ -31,6 +31,7 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.onap.so.client.graphinventory.GraphInventoryCommonObjectMapperProvider; +import org.onap.so.externaltasks.logging.AuditMDCSetup; import org.onap.so.objects.audit.AAIObjectAudit; import org.onap.so.objects.audit.AAIObjectAuditList; import com.fasterxml.jackson.core.JsonProcessingException; @@ -46,6 +47,9 @@ public class CreateInventoryTaskTest { @Mock ExternalTaskService externalTaskService; + @Mock + private AuditMDCSetup mdcSetup; + @InjectMocks CreateInventoryTask inventoryTask; diff --git a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/network/NetworkAdapterRestTest.java b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/network/NetworkAdapterRestTest.java index 1f4c205e7a..412abeab3b 100644 --- a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/network/NetworkAdapterRestTest.java +++ b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/network/NetworkAdapterRestTest.java @@ -194,9 +194,7 @@ public class NetworkAdapterRestTest extends BaseRestTestUtils { public void testRollbackNetwork() throws IOException { RollbackNetworkRequest request = new RollbackNetworkRequest(); - MsoRequest msoReq = new MsoRequest(); - msoReq.setRequestId(MSO_REQUEST_ID); msoReq.setServiceInstanceId(MSO_SERVICE_INSTANCE_ID); diff --git a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/vnf/MsoVnfAdapterImplTest.java b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/vnf/MsoVnfAdapterImplTest.java index 651e2c9a73..a058378425 100644 --- a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/vnf/MsoVnfAdapterImplTest.java +++ b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/vnf/MsoVnfAdapterImplTest.java @@ -7,9 +7,9 @@ * 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. @@ -40,7 +40,6 @@ import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.onap.so.adapters.vnf.exceptions.VnfAlreadyExists; import org.onap.so.adapters.vnf.exceptions.VnfException; import org.onap.so.adapters.vnf.exceptions.VnfNotFound; import org.onap.so.db.catalog.beans.HeatEnvironment; @@ -50,15 +49,15 @@ import org.onap.so.db.catalog.beans.VfModule; import org.onap.so.db.catalog.beans.VfModuleCustomization; import org.onap.so.db.catalog.beans.VnfResource; import org.onap.so.entity.MsoRequest; -import org.onap.so.openstack.beans.HeatStatus; -import org.onap.so.openstack.beans.StackInfo; import org.onap.so.openstack.beans.VnfRollback; import org.onap.so.openstack.exceptions.MsoException; import org.onap.so.openstack.utils.MsoHeatUtils; import org.springframework.beans.factory.annotation.Autowired; +import com.github.tomakehurst.wiremock.stubbing.Scenario; public class MsoVnfAdapterImplTest extends BaseRestTestUtils { + @Rule public ExpectedException expectedException = ExpectedException.none(); @@ -71,17 +70,7 @@ public class MsoVnfAdapterImplTest extends BaseRestTestUtils { String vnfName = "DEV-VF-1802-it3-pwt3-v6-vSAMP10a-addon2-Replace-1001/stackId"; @Test - @Ignore - public void healthCheckVNFTest() { - MsoVnfAdapterImpl instance = new MsoVnfAdapterImpl(); - instance.healthCheck(); - } - - @Test public void createVnfTest() throws Exception { - StackInfo info = new StackInfo(); - info.setStatus(HeatStatus.CREATED); - mockOpenStackResponseAccess(wireMockServer, wireMockPort); mockOpenStackGetStackVfModule_200(wireMockServer); @@ -90,105 +79,71 @@ public class MsoVnfAdapterImplTest extends BaseRestTestUtils { Map<String, Object> map = new HashMap<>(); map.put("key1", "value1"); instance.createVfModule("mtn13", "CloudOwner", "88a6ca3ee0394ade9403f075db23167e", "vnf", "1", "", vnfName, "", - "VFMOD", "volumeGroupHeatStackId|1", "baseVfHeatStackId", "88a6ca3ee0394ade9403f075db23167e", map, - Boolean.FALSE, Boolean.TRUE, Boolean.FALSE, msoRequest, new Holder<>(), - new Holder<Map<String, String>>(), new Holder<VnfRollback>()); + "VFMOD", null, null, "b4ea86b4-253f-11e7-93ae-92361f002671", map, Boolean.TRUE, Boolean.TRUE, + Boolean.FALSE, msoRequest, new Holder<>(), new Holder<Map<String, String>>(), + new Holder<VnfRollback>()); } @Test - public void createVnfTest_HeatStatusUpdating() throws Exception { - expectedException.expect(VnfAlreadyExists.class); + public void createVnfTest_NullFailIfExists() throws Exception { mockOpenStackResponseAccess(wireMockServer, wireMockPort); - - wireMockServer.stubFor(get( - urlPathEqualTo("/mockPublicUrl/stacks/DEV-VF-1802-it3-pwt3-v6-vSAMP10a-addon2-Replace-1001/stackId")) - .willReturn(aResponse().withHeader("Content-Type", "application/json") - .withBodyFile("OpenstackResponse_Stack_Updating_VfModule.json") - .withStatus(HttpStatus.SC_OK))); + mockOpenStackGetStackVfModule_200(wireMockServer); MsoRequest msoRequest = getMsoRequest(); Map<String, Object> map = new HashMap<>(); map.put("key1", "value1"); instance.createVfModule("mtn13", "CloudOwner", "88a6ca3ee0394ade9403f075db23167e", "vnf", "1", "", vnfName, "", - "VFMOD", "volumeGroupHeatStackId|1", "baseVfHeatStackId", "88a6ca3ee0394ade9403f075db23167e", map, - Boolean.FALSE, Boolean.TRUE, Boolean.FALSE, msoRequest, new Holder<>(), - new Holder<Map<String, String>>(), new Holder<VnfRollback>()); + "VFMOD", null, null, "b4ea86b4-253f-11e7-93ae-92361f002671", map, null, Boolean.TRUE, Boolean.FALSE, + msoRequest, new Holder<>(), new Holder<Map<String, String>>(), new Holder<VnfRollback>()); } @Test - public void createVnfTest_HeatStatusUpdated() throws Exception { - expectedException.expect(VnfAlreadyExists.class); + public void createVnfTest_HeatStatusFailed() throws Exception { mockOpenStackResponseAccess(wireMockServer, wireMockPort); - wireMockServer.stubFor(get( urlPathEqualTo("/mockPublicUrl/stacks/DEV-VF-1802-it3-pwt3-v6-vSAMP10a-addon2-Replace-1001/stackId")) .willReturn(aResponse().withHeader("Content-Type", "application/json") - .withBodyFile("OpenstackResponse_StackId.json").withStatus(HttpStatus.SC_OK))); - - MsoRequest msoRequest = getMsoRequest(); - - Map<String, Object> map = new HashMap<>(); - map.put("key1", "value1"); - instance.createVfModule("mtn13", "CloudOwner", "88a6ca3ee0394ade9403f075db23167e", "vnf", "1", "", vnfName, "", - "VFMOD", "volumeGroupHeatStackId|1", "baseVfHeatStackId", "88a6ca3ee0394ade9403f075db23167e", map, - Boolean.FALSE, Boolean.TRUE, Boolean.FALSE, msoRequest, new Holder<>(), - new Holder<Map<String, String>>(), new Holder<VnfRollback>()); - } - - @Test - public void createVnfTest_HeatStatusFailed() throws Exception { - expectedException.expect(VnfAlreadyExists.class); - mockOpenStackResponseAccess(wireMockServer, wireMockPort); + .withBodyFile("OpenstackResponse_Stack_Failed_VfModule.json") + .withStatus(HttpStatus.SC_OK)) + .inScenario("HeatStatusFailure").whenScenarioStateIs(Scenario.STARTED) + .willSetStateTo("HeatStackFailed")); wireMockServer.stubFor(get( urlPathEqualTo("/mockPublicUrl/stacks/DEV-VF-1802-it3-pwt3-v6-vSAMP10a-addon2-Replace-1001/stackId")) .willReturn(aResponse().withHeader("Content-Type", "application/json") - .withBodyFile("OpenstackResponse_Stack_Failed_VfModule.json") - .withStatus(HttpStatus.SC_OK))); + .withBodyFile("OpenstackResponse_Stack_Created_VfModule.json") + .withStatus(HttpStatus.SC_OK)) + .inScenario("HeatStatusFailure").whenScenarioStateIs("HeatStackFailed") + .willSetStateTo("HeatStackSuccess")); MsoRequest msoRequest = getMsoRequest(); Map<String, Object> map = new HashMap<>(); map.put("key1", "value1"); instance.createVfModule("mtn13", "CloudOwner", "88a6ca3ee0394ade9403f075db23167e", "vnf", "1", "", vnfName, "", - "VFMOD", "volumeGroupHeatStackId|1", "baseVfHeatStackId", "88a6ca3ee0394ade9403f075db23167e", map, - Boolean.FALSE, Boolean.TRUE, Boolean.FALSE, msoRequest, new Holder<>(), - new Holder<Map<String, String>>(), new Holder<VnfRollback>()); + "VFMOD", null, null, "b4ea86b4-253f-11e7-93ae-92361f002671", map, Boolean.FALSE, Boolean.TRUE, + Boolean.FALSE, msoRequest, new Holder<>(), new Holder<Map<String, String>>(), + new Holder<VnfRollback>()); } + + @Test public void createVnfTest_HeatStatusCreated() throws Exception { - expectedException.expect(VnfAlreadyExists.class); mockOpenStackResponseAccess(wireMockServer, wireMockPort); - mockOpenStackGetStackVfModule_200(wireMockServer); - MsoRequest msoRequest = getMsoRequest(); - Map<String, Object> map = new HashMap<>(); map.put("key1", "value1"); instance.createVfModule("mtn13", "CloudOwner", "88a6ca3ee0394ade9403f075db23167e", "vnf", "1", "", vnfName, "", - "VFMOD", "volumeGroupHeatStackId|1", "baseVfHeatStackId", "88a6ca3ee0394ade9403f075db23167e", map, - Boolean.TRUE, Boolean.TRUE, Boolean.FALSE, msoRequest, new Holder<>(), - new Holder<Map<String, String>>(), new Holder<VnfRollback>()); + "VFMOD", null, null, "b4ea86b4-253f-11e7-93ae-92361f002671", map, Boolean.TRUE, Boolean.TRUE, + Boolean.FALSE, msoRequest, new Holder<>(), new Holder<Map<String, String>>(), + new Holder<VnfRollback>()); } @Test - public void createVnfTest_ExceptionInGettingHeat() throws Exception { - expectedException.expect(VnfException.class); - MsoRequest msoRequest = getMsoRequest(); - - Map<String, Object> map = new HashMap<>(); - map.put("key1", "value1"); - instance.createVfModule("mtn13", "CloudOwner", "88a6ca3ee0394ade9403f075db23167e", "vnf", "1", "", vnfName, "", - "VFMOD", "volumeGroupHeatStackId|1", "baseVfHeatStackId", "88a6ca3ee0394ade9403f075db23167e", map, - Boolean.FALSE, Boolean.TRUE, Boolean.FALSE, msoRequest, new Holder<>(), - new Holder<Map<String, String>>(), new Holder<VnfRollback>()); - } - - @Test public void createVnfTest_NestedHeatStatusNotFound() throws Exception { expectedException.expect(VnfException.class); mockOpenStackResponseAccess(wireMockServer, wireMockPort); @@ -529,7 +484,8 @@ public class MsoVnfAdapterImplTest extends BaseRestTestUtils { MsoVnfAdapterImpl instance = new MsoVnfAdapterImpl(); MsoRequest msoRequest = getMsoRequest(); try { - instance.deleteVfModule("mdt1", "CloudOwner", "88a6ca3ee0394ade9403f075db23167e", "vSAMP12", msoRequest, + instance.deleteVfModule("mdt1", "CloudOwner", "88a6ca3ee0394ade9403f075db23167e", "vSAMP12", + "5aae1e49-805c-4f9f-bd78-055bf7451157", "11420693-3f69-4c61-b3ee-9787c744e760", null, msoRequest, new Holder<Map<String, String>>()); } catch (Exception e) { diff --git a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/vnf/MsoVnfCloudifyAdapterImplTest.java b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/vnf/MsoVnfCloudifyAdapterImplTest.java index 16cc2c34de..45504fcab5 100644 --- a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/vnf/MsoVnfCloudifyAdapterImplTest.java +++ b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/vnf/MsoVnfCloudifyAdapterImplTest.java @@ -8,9 +8,9 @@ * 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. @@ -67,30 +67,30 @@ public class MsoVnfCloudifyAdapterImplTest extends BaseRestTestUtils { * msoRequest.setRequestId("12345"); msoRequest.setServiceInstanceId("12345"); Holder<Map<String, String>> outputs = * new Holder<>(); instance.queryVnf("siteid", "CloudOwner", "1234", "vfname", msoRequest, new Holder<>(), new * Holder<>(), new Holder<>(), outputs); - * + * * assertTrue(outputs.value.isEmpty()); } */ /* * @Test public void queryVnfTest() throws Exception { - * - * + * + * * MsoRequest msoRequest = new MsoRequest(); msoRequest.setRequestId("12345"); * msoRequest.setServiceInstanceId("12345"); * wireMockServer.stubFor(get(urlPathEqualTo("/v2.0/api/v3/deployments/vfname")) * .willReturn(aResponse().withBody("{ \"id\": \"123\" }").withStatus(HttpStatus.SC_OK))); - * + * * wireMockServer.stubFor(get(urlPathEqualTo("/v2.0/api/v3/deployments/vfname/outputs")) * .willReturn(aResponse().withBody("{ \"deployment_id\": \"123\",\"outputs\":{\"abc\":\"abc\"} }") * .withStatus(HttpStatus.SC_OK))); - * + * * wireMockServer.stubFor(get(urlMatching("/v2.0/api/v3/executions?.*")).willReturn(aResponse() * .withBody("{ \"items\": {\"id\": \"123\",\"workflow_id\":\"install\",\"status\":\"terminated\" } } ") * .withStatus(HttpStatus.SC_OK))); - * + * * instance.queryVnf("mtn13", "CloudOwner", "1234", "vfname", msoRequest, new Holder<>(), new Holder<>(), new * Holder<>(), new Holder<>()); - * + * * } */ @@ -101,7 +101,8 @@ public class MsoVnfCloudifyAdapterImplTest extends BaseRestTestUtils { msoRequest.setRequestId("12345"); msoRequest.setServiceInstanceId("12345"); - instance.deleteVfModule("mtn13", "CloudOwner", "1234", "vfname", msoRequest, new Holder<>()); + instance.deleteVfModule("mtn13", "CloudOwner", "1234", "vfname", "5aae1e49-805c-4f9f-bd78-055bf7451157", + "11420693-3f69-4c61-b3ee-9787c744e760", "customizationId", msoRequest, new Holder<>()); } @Test @@ -124,7 +125,8 @@ public class MsoVnfCloudifyAdapterImplTest extends BaseRestTestUtils { wireMockServer.stubFor(get(urlPathEqualTo("/v2.0/api/v3/tokens")) .willReturn(aResponse().withBodyFile("OpenstackResponse_Access.json").withStatus(HttpStatus.SC_OK))); - instance.deleteVfModule("mtn13", "CloudOwner", "1234", "vfname", msoRequest, new Holder<>()); + instance.deleteVfModule("mtn13", "CloudOwner", "1234", "vfname", "5aae1e49-805c-4f9f-bd78-055bf7451157", + "11420693-3f69-4c61-b3ee-9787c744e760", "customizationId", msoRequest, new Holder<>()); } @Test diff --git a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/vnf/MsoVnfMulticloudAdapterImplTest.java b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/vnf/MsoVnfMulticloudAdapterImplTest.java index 48ca0fd79c..3bf784c50b 100644 --- a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/vnf/MsoVnfMulticloudAdapterImplTest.java +++ b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/vnf/MsoVnfMulticloudAdapterImplTest.java @@ -210,7 +210,8 @@ public class MsoVnfMulticloudAdapterImplTest extends BaseRestTestUtils { wireMockServer.stubFor(delete(urlPathEqualTo("/api/multicloud/v1/CloudOwner/MTN13/infra_workload/workload-id")) .willReturn(aResponse().withStatus(HttpStatus.SC_NO_CONTENT))); - instance.deleteVfModule("MTN13", "CloudOwner", "123", "workload-id", msoRequest, new Holder<>()); + instance.deleteVfModule("MTN13", "CloudOwner", "123", "workload-id", "5aae1e49-805c-4f9f-bd78-055bf7451157", + "11420693-3f69-4c61-b3ee-9787c744e760", "customizationId", msoRequest, new Holder<>()); } @Test diff --git a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/vnf/MsoVnfPluginAdapterImplTest.java b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/vnf/MsoVnfPluginAdapterImplTest.java index 7ec8e51892..a68efbe130 100644 --- a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/vnf/MsoVnfPluginAdapterImplTest.java +++ b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/vnf/MsoVnfPluginAdapterImplTest.java @@ -134,6 +134,7 @@ public class MsoVnfPluginAdapterImplTest extends BaseRestTestUtils { expectedException.expect(VnfException.class); MsoRequest msoRequest = getMsoRequest(); msoVnfPluginAdapter.deleteVfModule("mtn13", "CloudOwner", "88a6ca3ee0394ade9403f075db23167e", "vSAMP12", + "5aae1e49-805c-4f9f-bd78-055bf7451157", "11420693-3f69-4c61-b3ee-9787c744e760", "customizationId", msoRequest, new Holder<Map<String, String>>()); } @@ -151,6 +152,7 @@ public class MsoVnfPluginAdapterImplTest extends BaseRestTestUtils { .withStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR))); MsoRequest msoRequest = getMsoRequest(); msoVnfPluginAdapter.deleteVfModule("mtn13", "CloudOwner", "88a6ca3ee0394ade9403f075db23167e", "vSAMP12", + "5aae1e49-805c-4f9f-bd78-055bf7451157", "11420693-3f69-4c61-b3ee-9787c744e760", "customizationId", msoRequest, new Holder<Map<String, String>>()); } diff --git a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/vnf/VnfAdapterRestTest.java b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/vnf/VnfAdapterRestTest.java index 89adafd280..5a8524fd73 100644 --- a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/vnf/VnfAdapterRestTest.java +++ b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/vnf/VnfAdapterRestTest.java @@ -98,7 +98,6 @@ public class VnfAdapterRestTest extends BaseRestTestUtils { private static final String EXN_HSL_NET_FQDN = "hsl"; private static final String AVAILABILITY_ZONE_0 = "nova"; private static final String VF_MODULE_INDEX = "0"; - private static final String REQUEST_TYPE = ""; @Test public void testCreateVfModule() throws JSONException, JsonParseException, JsonMappingException, IOException { @@ -188,7 +187,6 @@ public class VnfAdapterRestTest extends BaseRestTestUtils { msoReq.setRequestId(MSO_REQUEST_ID); msoReq.setServiceInstanceId(MSO_SERVICE_INSTANCE_ID); request.setMsoRequest(msoReq); - request.setRequestType(REQUEST_TYPE); request.setCloudSiteId(CLOUDSITE_ID); request.setTenantId(TENANT_ID); request.setModelCustomizationUuid(MODEL_CUSTOMIZATION_UUID); @@ -254,7 +252,6 @@ public class VnfAdapterRestTest extends BaseRestTestUtils { msoReq.setRequestId(MSO_REQUEST_ID); msoReq.setServiceInstanceId(MSO_SERVICE_INSTANCE_ID); request.setMsoRequest(msoReq); - request.setRequestType(REQUEST_TYPE); request.setCloudSiteId(CLOUDSITE_ID); request.setTenantId(TENANT_ID); request.setModelCustomizationUuid(MODEL_CUSTOMIZATION_UUID); @@ -394,7 +391,6 @@ public class VnfAdapterRestTest extends BaseRestTestUtils { request.setFailIfExists(failIfExists); request.setModelCustomizationUuid(MODEL_CUSTOMIZATION_UUID); request.setMsoRequest(msoRequest); - request.setRequestType(REQUEST_TYPE); request.setTenantId(TENANT_ID); request.setVfModuleId(VF_MODULE_ID); request.setVfModuleName(VF_MODULE_NAME); @@ -526,7 +522,6 @@ public class VnfAdapterRestTest extends BaseRestTestUtils { msoReq.setRequestId(MSO_REQUEST_ID); msoReq.setServiceInstanceId(MSO_SERVICE_INSTANCE_ID); request.setMsoRequest(msoReq); - request.setRequestType(REQUEST_TYPE); request.setCloudSiteId(CLOUDSITE_ID); request.setTenantId(TENANT_ID); request.setModelCustomizationUuid(MODEL_CUSTOMIZATION_UUID); diff --git a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/heatbridge/HeatBridgeImplTest.java b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/heatbridge/HeatBridgeImplTest.java index d611322c02..e2f5531280 100644 --- a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/heatbridge/HeatBridgeImplTest.java +++ b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/heatbridge/HeatBridgeImplTest.java @@ -112,7 +112,7 @@ public class HeatBridgeImplTest { public void setUp() throws HeatBridgeException, OpenstackClientException, BulkProcessFailed { when(resourcesClient.beginSingleTransaction()).thenReturn(transaction); - heatbridge = new HeatBridgeImpl(resourcesClient, cloudIdentity, CLOUD_OWNER, REGION_ID, TENANT_ID); + heatbridge = new HeatBridgeImpl(resourcesClient, cloudIdentity, CLOUD_OWNER, REGION_ID, REGION_ID, TENANT_ID); } @Ignore diff --git a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/heatbridge/factory/MsoCloudClientFactoryImplTest.java b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/heatbridge/factory/MsoCloudClientFactoryImplTest.java index 701ed65d19..4eeb1c03a3 100644 --- a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/heatbridge/factory/MsoCloudClientFactoryImplTest.java +++ b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/heatbridge/factory/MsoCloudClientFactoryImplTest.java @@ -38,7 +38,7 @@ public class MsoCloudClientFactoryImplTest { private static final String MSO_ID = "testMsoId"; private static final String ENCRYPTED_PASSWORD = CryptoUtils.encryptCloudConfigPassword("testPassword"); - private static final String CLOUD_REGION_ID = "testCloudRegionId"; + private static final String REGION_ID = "testCloudRegionId"; private static final String TENANT_ID = "testTenantId"; private MsoCloudClientFactoryImpl testedObject; @@ -52,20 +52,19 @@ public class MsoCloudClientFactoryImplTest { @Test public void getOpenstackClientWithVersion2() throws Exception { - testedObject.getOpenstackClient(URL_V2, MSO_ID, ENCRYPTED_PASSWORD, CLOUD_REGION_ID, TENANT_ID); + testedObject.getOpenstackClient(URL_V2, MSO_ID, ENCRYPTED_PASSWORD, REGION_ID, TENANT_ID); verify(openstackClientFactoryMock).createOpenstackV2Client(any(OpenstackAccess.class)); } @Test public void getOpenstackClientWithVersion3() throws Exception { - testedObject.getOpenstackClient(URL_V3, MSO_ID, ENCRYPTED_PASSWORD, CLOUD_REGION_ID, TENANT_ID); + testedObject.getOpenstackClient(URL_V3, MSO_ID, ENCRYPTED_PASSWORD, REGION_ID, TENANT_ID); verify(openstackClientFactoryMock).createOpenstackV3Client(any(OpenstackAccess.class)); } @Test(expected = HeatBridgeException.class) public void getOpenstackClient_unsupportedVersion() throws Exception { - testedObject.getOpenstackClient(URL_WITH_UNSUPPORTED_VERSION, MSO_ID, ENCRYPTED_PASSWORD, CLOUD_REGION_ID, - TENANT_ID); + testedObject.getOpenstackClient(URL_WITH_UNSUPPORTED_VERSION, MSO_ID, ENCRYPTED_PASSWORD, REGION_ID, TENANT_ID); } } diff --git a/adapters/mso-openstack-adapters/src/test/resources/application-test.yaml b/adapters/mso-openstack-adapters/src/test/resources/application-test.yaml index 7cc7697129..20fd812ab9 100644 --- a/adapters/mso-openstack-adapters/src/test/resources/application-test.yaml +++ b/adapters/mso-openstack-adapters/src/test/resources/application-test.yaml @@ -1,5 +1,3 @@ -# will be used as entry in DB to say SITE OFF/ON for healthcheck -# MSO Properties go here org: onap: so: @@ -41,7 +39,7 @@ org: default_keystone_reg_ex: "/[vV][0-9]" default_tenant_description: ECOMP Tenant default_region_type: single - default_user_role: admin + default_user_role: adminev default_success_status_string: Success default_no_regions_status_string: no regions default_orm_request_path: /v1/orm/customers/ diff --git a/adapters/mso-openstack-adapters/src/test/resources/schema.sql b/adapters/mso-openstack-adapters/src/test/resources/schema.sql index 7b3ffd7d30..6b791e789c 100644 --- a/adapters/mso-openstack-adapters/src/test/resources/schema.sql +++ b/adapters/mso-openstack-adapters/src/test/resources/schema.sql @@ -735,6 +735,8 @@ CREATE TABLE `orchestration_flow_reference` ( `SEQ_NO` int(11) NOT NULL, `FLOW_NAME` varchar(200) NOT NULL, `FLOW_VERSION` double NOT NULL, + `SCOPE` varchar(200) DEFAULT NULL, + `ACTION` varchar(200) DEFAULT NULL, `NB_REQ_REF_LOOKUP_ID` int(11) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `UK_orchestration_flow_reference` (`COMPOSITE_ACTION`,`FLOW_NAME`,`SEQ_NO`,`NB_REQ_REF_LOOKUP_ID`), @@ -806,6 +808,10 @@ CREATE TABLE `service` ( `OVERALL_DISTRIBUTION_STATUS` varchar(45), `ONAP_GENERATED_NAMING` TINYINT(1) DEFAULT NULL, `NAMING_POLICY` varchar(200) DEFAULT NULL, + `CDS_BLUEPRINT_NAME` varchar(200) DEFAULT NULL, + `CDS_BLUEPRINT_VERSION` varchar(20) DEFAULT NULL, + `CONTROLLER_ACTOR` varchar(200) DEFAULT NULL, + `SKIP_POST_INSTANTIATION_CONFIGURATION` boolean default true, PRIMARY KEY (`MODEL_UUID`), KEY `fk_service__tosca_csar1_idx` (`TOSCA_CSAR_ARTIFACT_UUID`), CONSTRAINT `fk_service__tosca_csar1` FOREIGN KEY (`TOSCA_CSAR_ARTIFACT_UUID`) REFERENCES `tosca_csar` (`ARTIFACT_UUID`) ON DELETE CASCADE ON UPDATE CASCADE @@ -960,6 +966,7 @@ CREATE TABLE `vf_module_customization` ( `CREATION_TIMESTAMP` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `VF_MODULE_MODEL_UUID` varchar(200) NOT NULL, `VNF_RESOURCE_CUSTOMIZATION_ID` int(13) DEFAULT NULL, + `SKIP_POST_INSTANTIATION_CONFIGURATION` boolean default true, PRIMARY KEY (`ID`), KEY `fk_vf_module_customization__vf_module1_idx` (`VF_MODULE_MODEL_UUID`), KEY `fk_vf_module_customization__heat_env__heat_environment1_idx` (`HEAT_ENVIRONMENT_ARTIFACT_UUID`), @@ -1109,7 +1116,9 @@ CREATE TABLE `vnf_resource_customization` ( `CREATION_TIMESTAMP` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `VNF_RESOURCE_MODEL_UUID` varchar(200) NOT NULL, `SERVICE_MODEL_UUID` varchar(200) NOT NULL, + `NF_DATA_VALID` tinyint(1) DEFAULT '0', `VNFCINSTANCEGROUP_ORDER` varchar(200) default NULL, + `CONTROLLER_ACTOR` varchar(200) DEFAULT NULL, PRIMARY KEY (`ID`), UNIQUE KEY `UK_vnf_resource_customization` (`MODEL_CUSTOMIZATION_UUID`,`SERVICE_MODEL_UUID`), KEY `fk_vnf_resource_customization__vnf_resource1_idx` (`VNF_RESOURCE_MODEL_UUID`), @@ -1191,6 +1200,7 @@ CREATE TABLE IF NOT EXISTS `pnf_resource_customization` ( `CDS_BLUEPRINT_NAME` varchar(200) DEFAULT NULL, `CDS_BLUEPRINT_VERSION` varchar(20) DEFAULT NULL, `SKIP_POST_INSTANTIATION_CONFIGURATION` boolean default true, + `CONTROLLER_ACTOR` varchar(200) DEFAULT NULL, PRIMARY KEY (`MODEL_CUSTOMIZATION_UUID`), KEY `fk_pnf_resource_customization__pnf_resource1_idx` (`PNF_RESOURCE_MODEL_UUID`), CONSTRAINT `fk_pnf_resource_customization__pnf_resource1` FOREIGN KEY (`PNF_RESOURCE_MODEL_UUID`) REFERENCES `pnf_resource` (`MODEL_UUID`) ON DELETE CASCADE ON UPDATE CASCADE diff --git a/adapters/mso-requests-db-adapter/pom.xml b/adapters/mso-requests-db-adapter/pom.xml index a02ebbe75d..366a207d60 100644 --- a/adapters/mso-requests-db-adapter/pom.xml +++ b/adapters/mso-requests-db-adapter/pom.xml @@ -169,6 +169,9 @@ <executions> <execution> <id>original</id> + <configuration> + <skip>false</skip> + </configuration> </execution> </executions> </plugin> diff --git a/adapters/mso-requests-db-adapter/src/main/java/org/onap/so/adapters/requestsdb/ArchiveInfraRequestsScheduler.java b/adapters/mso-requests-db-adapter/src/main/java/org/onap/so/adapters/requestsdb/ArchiveInfraRequestsScheduler.java index 8c4150cd50..3deabb3ce1 100644 --- a/adapters/mso-requests-db-adapter/src/main/java/org/onap/so/adapters/requestsdb/ArchiveInfraRequestsScheduler.java +++ b/adapters/mso-requests-db-adapter/src/main/java/org/onap/so/adapters/requestsdb/ArchiveInfraRequestsScheduler.java @@ -27,15 +27,19 @@ import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; -import org.onap.so.logger.LoggingAnchor; +import org.onap.logging.filter.base.ONAPComponents; +import org.onap.logging.ref.slf4j.ONAPLogConstants; import org.onap.so.db.request.beans.ArchivedInfraRequests; import org.onap.so.db.request.beans.InfraActiveRequests; import org.onap.so.db.request.data.repository.ArchivedInfraRequestsRepository; import org.onap.so.db.request.data.repository.InfraActiveRequestsRepository; import org.onap.so.logger.ErrorCode; +import org.onap.so.logger.LoggingAnchor; import org.onap.so.logger.MessageEnum; +import org.onap.so.logger.ScheduledTasksMDCSetup; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.slf4j.MDC; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.PageRequest; @@ -52,6 +56,9 @@ public class ArchiveInfraRequestsScheduler { private InfraActiveRequestsRepository infraActiveRepo; @Autowired private ArchivedInfraRequestsRepository archivedInfraRepo; + @Autowired + private ScheduledTasksMDCSetup scheduledMDCSetup; + @Value("${mso.infra-requests.archived.period}") private int archivedPeriod; @@ -62,6 +69,7 @@ public class ArchiveInfraRequestsScheduler { @Scheduled(cron = "0 0 1 * * ?") @SchedulerLock(name = "archiveInfraRequestsScheduler") public void infraRequestsScheduledTask() { + scheduledMDCSetup.mdcSetup(ONAPComponents.REQUEST_DB, "infraRequestsScheduledTask"); logger.debug("Start of archiveInfraRequestsScheduler"); Date currentDate = new Date(); @@ -89,6 +97,7 @@ public class ArchiveInfraRequestsScheduler { } while (!requestsByStartTime.isEmpty()); logger.debug("End of archiveInfraRequestsScheduler"); + scheduledMDCSetup.exitAndClearMDC(); } protected void archiveInfraRequests(List<InfraActiveRequests> requests) { @@ -98,12 +107,8 @@ public class ArchiveInfraRequestsScheduler { for (InfraActiveRequests iar : requests) { ArchivedInfraRequests archivedInfra = new ArchivedInfraRequests(); try { - archivedInfra.setAaiServiceId(iar.getAaiServiceId()); - archivedInfra.setAction(iar.getAction()); - archivedInfra.setAicCloudRegion(iar.getAicCloudRegion()); - archivedInfra.setAicNodeClli(iar.getAicNodeClli()); + archivedInfra.setCloudRegion(iar.getCloudRegion()); archivedInfra.setCallBackUrl(iar.getCallBackUrl()); - archivedInfra.setClientRequestId(iar.getClientRequestId()); archivedInfra.setConfigurationId(iar.getConfigurationId()); archivedInfra.setConfigurationName(iar.getConfigurationName()); archivedInfra.setCorrelator(iar.getCorrelator()); @@ -116,14 +121,12 @@ public class ArchiveInfraRequestsScheduler { archivedInfra.setOperationalEnvName(iar.getOperationalEnvName()); archivedInfra.setRequestUrl(iar.getRequestUrl()); archivedInfra.setProgress(iar.getProgress()); - archivedInfra.setProvStatus(iar.getProvStatus()); archivedInfra.setRequestAction(iar.getRequestAction()); archivedInfra.setRequestBody(iar.getRequestBody()); archivedInfra.setRequestId(iar.getRequestId()); archivedInfra.setRequestorId(iar.getRequestorId()); archivedInfra.setRequestScope(iar.getRequestScope()); archivedInfra.setRequestStatus(iar.getRequestStatus()); - archivedInfra.setRequestType(iar.getRequestType()); archivedInfra.setResponseBody(iar.getResponseBody()); archivedInfra.setServiceInstanceId(iar.getServiceInstanceId()); archivedInfra.setServiceInstanceName(iar.getServiceInstanceName()); @@ -146,6 +149,8 @@ public class ArchiveInfraRequestsScheduler { newArchivedReqs.add(archivedInfra); oldInfraReqs.add(iar); } catch (Exception e) { + scheduledMDCSetup.errorMDCSetup(ErrorCode.UnknownError, e.getMessage()); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE, ONAPLogConstants.ResponseStatus.ERROR.toString()); logger.error(LoggingAnchor.TWO, MessageEnum.RA_GENERAL_EXCEPTION.toString(), ErrorCode.UnknownError.getValue(), e); } diff --git a/adapters/mso-requests-db-adapter/src/main/java/org/onap/so/adapters/requestsdb/InfraActiveRequestsRepositoryCustomController.java b/adapters/mso-requests-db-adapter/src/main/java/org/onap/so/adapters/requestsdb/InfraActiveRequestsRepositoryCustomController.java index f6a0aec86f..28e931a3e1 100644 --- a/adapters/mso-requests-db-adapter/src/main/java/org/onap/so/adapters/requestsdb/InfraActiveRequestsRepositoryCustomController.java +++ b/adapters/mso-requests-db-adapter/src/main/java/org/onap/so/adapters/requestsdb/InfraActiveRequestsRepositoryCustomController.java @@ -74,4 +74,9 @@ public class InfraActiveRequestsRepositoryCustomController { @RequestParam(value = "maxResult", required = false) Integer maxResult) { return infraActiveRequestsRepository.getInfraActiveRequests(filters, startTime, endTime, maxResult); } + + @RequestMapping(method = RequestMethod.GET, value = "/infraActiveRequests/getInProgressVolumeGroupsAndVfModules") + public List<InfraActiveRequests> getInProgressVolumeGroupsAndVfModules() { + return infraActiveRequestsRepository.getInProgressVolumeGroupsAndVfModules(); + } } diff --git a/adapters/mso-requests-db-adapter/src/main/java/org/onap/so/adapters/requestsdb/MsoRequestsDbAdapter.java b/adapters/mso-requests-db-adapter/src/main/java/org/onap/so/adapters/requestsdb/MsoRequestsDbAdapter.java index f4a9f711fd..110fc6c03e 100644 --- a/adapters/mso-requests-db-adapter/src/main/java/org/onap/so/adapters/requestsdb/MsoRequestsDbAdapter.java +++ b/adapters/mso-requests-db-adapter/src/main/java/org/onap/so/adapters/requestsdb/MsoRequestsDbAdapter.java @@ -7,9 +7,9 @@ * 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. @@ -31,6 +31,7 @@ import org.onap.so.db.request.beans.ResourceOperationStatus; /** * MSO Request DB Adapter Web Service */ +@Deprecated @WebService(name = "RequestsDbAdapter", targetNamespace = "http://org.onap.so/requestsdb") public interface MsoRequestsDbAdapter { diff --git a/adapters/mso-requests-db-adapter/src/main/java/org/onap/so/adapters/requestsdb/MsoRequestsDbAdapterImpl.java b/adapters/mso-requests-db-adapter/src/main/java/org/onap/so/adapters/requestsdb/MsoRequestsDbAdapterImpl.java index 9d6a8b0529..085a255948 100644 --- a/adapters/mso-requests-db-adapter/src/main/java/org/onap/so/adapters/requestsdb/MsoRequestsDbAdapterImpl.java +++ b/adapters/mso-requests-db-adapter/src/main/java/org/onap/so/adapters/requestsdb/MsoRequestsDbAdapterImpl.java @@ -10,9 +10,9 @@ * 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. @@ -45,6 +45,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; +@Deprecated @WebService(serviceName = "RequestsDbAdapter", endpointInterface = "org.onap.so.adapters.requestsdb.MsoRequestsDbAdapter", targetNamespace = "http://org.onap.so/requestsdb") @@ -73,7 +74,7 @@ public class MsoRequestsDbAdapterImpl implements MsoRequestsDbAdapter { String networkId, String vnfId, String vfModuleId, String volumeGroupId, String serviceInstanceName, String configurationId, String configurationName, String vfModuleName) throws MsoRequestsDbException { try { - InfraActiveRequests request = infraActive.findOneByRequestIdOrClientRequestId(requestId, requestId); + InfraActiveRequests request = infraActive.findOneByRequestId(requestId); if (request == null) { String error = "Entity not found. Unable to retrieve MSO Infra Requests DB for Request ID " + requestId; throw new MsoRequestsDbException(error); @@ -129,7 +130,7 @@ public class MsoRequestsDbAdapterImpl implements MsoRequestsDbAdapter { } catch (Exception e) { String error = "Error retrieving MSO Infra Requests DB for Request ID " + requestId; logger.error(error, e); - throw new MsoRequestsDbException(error, ErrorCode.BusinessProcesssError, e); + throw new MsoRequestsDbException(error, ErrorCode.BusinessProcessError, e); } } @@ -147,7 +148,7 @@ public class MsoRequestsDbAdapterImpl implements MsoRequestsDbAdapter { logger.debug("Call to MSO Infra RequestsDb adapter get method with request Id: {}", requestId); InfraActiveRequests request = null; try { - request = infraActive.findOneByRequestIdOrClientRequestId(requestId, requestId); + request = infraActive.findOneByRequestId(requestId); if (request == null) { String error = "Entity not found. Unable to retrieve MSO Infra Requests DB for Request ID " + requestId; throw new MsoRequestsDbException(error); @@ -155,7 +156,7 @@ public class MsoRequestsDbAdapterImpl implements MsoRequestsDbAdapter { } catch (Exception e) { String error = "Error retrieving MSO Infra Requests DB for Request ID " + requestId; logger.error(error, e); - throw new MsoRequestsDbException(error, ErrorCode.BusinessProcesssError, e); + throw new MsoRequestsDbException(error, ErrorCode.BusinessProcessError, e); } return request; } @@ -183,7 +184,7 @@ public class MsoRequestsDbAdapterImpl implements MsoRequestsDbAdapter { /** * update operation status <br> - * + * * @param serviceId * @param operationId * @param operationType @@ -253,7 +254,7 @@ public class MsoRequestsDbAdapterImpl implements MsoRequestsDbAdapter { /** * init the operation status of all the resources <br> - * + * * @param serviceId the service Id * @param operationId the operation Id * @param operationType the operationType @@ -284,7 +285,7 @@ public class MsoRequestsDbAdapterImpl implements MsoRequestsDbAdapter { /** * get resource operation status <br> - * + * * @param serviceId * @param operationId * @param resourceTemplateUUID @@ -304,7 +305,7 @@ public class MsoRequestsDbAdapterImpl implements MsoRequestsDbAdapter { /** * update resource operation status <br> - * + * * @param serviceId * @param operationId * @param resourceTemplateUUID @@ -340,7 +341,7 @@ public class MsoRequestsDbAdapterImpl implements MsoRequestsDbAdapter { /** * update service operation status when a operation resource status updated <br> - * + * * @param operStatus the resource operation status * @since ONAP Amsterdam Release */ diff --git a/adapters/mso-requests-db-adapter/src/main/java/org/onap/so/adapters/requestsdb/application/MSORequestDBApplication.java b/adapters/mso-requests-db-adapter/src/main/java/org/onap/so/adapters/requestsdb/application/MSORequestDBApplication.java index 85c05decb1..0272bab1a1 100644 --- a/adapters/mso-requests-db-adapter/src/main/java/org/onap/so/adapters/requestsdb/application/MSORequestDBApplication.java +++ b/adapters/mso-requests-db-adapter/src/main/java/org/onap/so/adapters/requestsdb/application/MSORequestDBApplication.java @@ -22,8 +22,9 @@ package org.onap.so.adapters.requestsdb.application; -import java.time.Duration; import javax.sql.DataSource; +import org.onap.logging.filter.base.Constants; +import org.onap.logging.filter.base.ONAPComponents; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; @@ -32,16 +33,15 @@ import org.springframework.jmx.support.RegistrationPolicy; import org.springframework.scheduling.annotation.EnableScheduling; import net.javacrumbs.shedlock.core.LockProvider; import net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider; -import net.javacrumbs.shedlock.spring.ScheduledLockConfiguration; -import net.javacrumbs.shedlock.spring.ScheduledLockConfigurationBuilder; +import net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock; /** * @since Version 1.0 * */ - -@SpringBootApplication(scanBasePackages = {"org.onap.so"}) +@SpringBootApplication(scanBasePackages = {"org.onap.so", "org.onap.logging.filter"}) @EnableScheduling +@EnableSchedulerLock(defaultLockAtMostFor = "120s") @EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING) public class MSORequestDBApplication { @@ -54,6 +54,7 @@ public class MSORequestDBApplication { } public static void main(String... args) { + System.setProperty(Constants.Property.PARTNER_NAME, ONAPComponents.REQUEST_DB.toString()); SpringApplication.run(MSORequestDBApplication.class, args); java.security.Security.setProperty("networkaddress.cache.ttl", "10"); setLogsDir(); @@ -64,10 +65,5 @@ public class MSORequestDBApplication { return new JdbcTemplateLockProvider(dataSource); } - @Bean - public ScheduledLockConfiguration taskScheduler(LockProvider lockProvider) { - return ScheduledLockConfigurationBuilder.withLockProvider(lockProvider).withPoolSize(10) - .withDefaultLockAtMostFor(Duration.ofMinutes(10)).build(); - } } diff --git a/adapters/mso-requests-db-adapter/src/main/java/org/onap/so/adapters/requestsdb/application/WebMvcConfig.java b/adapters/mso-requests-db-adapter/src/main/java/org/onap/so/adapters/requestsdb/application/WebMvcConfig.java index 579afe9243..9135d31ac3 100644 --- a/adapters/mso-requests-db-adapter/src/main/java/org/onap/so/adapters/requestsdb/application/WebMvcConfig.java +++ b/adapters/mso-requests-db-adapter/src/main/java/org/onap/so/adapters/requestsdb/application/WebMvcConfig.java @@ -21,22 +21,32 @@ package org.onap.so.adapters.requestsdb.application; -import org.onap.so.logging.spring.interceptor.LoggingInterceptor; +import org.onap.logging.filter.spring.LoggingInterceptor; +import org.onap.logging.filter.spring.StatusLoggingInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.handler.MappedInterceptor; @Configuration +@ComponentScan(basePackages = {"org.onap.logging.filter"}) public class WebMvcConfig extends WebMvcConfigurerAdapter { @Autowired - LoggingInterceptor loggingInterceptor; + private LoggingInterceptor loggingInterceptor; + + @Autowired + private StatusLoggingInterceptor statusLoggingInterceptor; @Bean public MappedInterceptor mappedLoggingInterceptor() { return new MappedInterceptor(new String[] {"/**"}, loggingInterceptor); } + @Bean + public MappedInterceptor mappedStatusLoggingInterceptor() { + return new MappedInterceptor(new String[] {"/**"}, statusLoggingInterceptor); + } } diff --git a/adapters/mso-requests-db-adapter/src/main/resources/application-aaf.yaml b/adapters/mso-requests-db-adapter/src/main/resources/application-aaf.yaml new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/adapters/mso-requests-db-adapter/src/main/resources/application-aaf.yaml diff --git a/adapters/mso-requests-db-adapter/src/main/resources/application-basic.yaml b/adapters/mso-requests-db-adapter/src/main/resources/application-basic.yaml new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/adapters/mso-requests-db-adapter/src/main/resources/application-basic.yaml diff --git a/adapters/mso-requests-db-adapter/src/main/resources/db/migration/V6.4.1__Rename_Infra_active_requests_AIC_CLOUD_REGION_Column.sql b/adapters/mso-requests-db-adapter/src/main/resources/db/migration/V6.4.1__Rename_Infra_active_requests_AIC_CLOUD_REGION_Column.sql new file mode 100644 index 0000000000..eac9a65f65 --- /dev/null +++ b/adapters/mso-requests-db-adapter/src/main/resources/db/migration/V6.4.1__Rename_Infra_active_requests_AIC_CLOUD_REGION_Column.sql @@ -0,0 +1,12 @@ +use requestdb; + +DROP INDEX `infra_active_requests__aic_cloud_region_idx` on `infra_active_requests`; + +ALTER TABLE + `infra_active_requests` CHANGE AIC_CLOUD_REGION CLOUD_REGION varchar(50) DEFAULT NULL; + +ALTER TABLE + `archived_infra_requests` CHANGE AIC_CLOUD_REGION CLOUD_REGION VARCHAR(50) NULL DEFAULT NULL; + +ALTER TABLE `infra_active_requests` + ADD INDEX IF NOT EXISTS `infra_active_requests__cloud_region_idx` (`CLOUD_REGION` ASC); diff --git a/adapters/mso-requests-db-adapter/src/main/resources/db/migration/V6.4__Add_Indexes_to_Infra_Active_Requests_Table.sql b/adapters/mso-requests-db-adapter/src/main/resources/db/migration/V6.4__Add_Indexes_to_Infra_Active_Requests_Table.sql new file mode 100644 index 0000000000..2f7438c1d3 --- /dev/null +++ b/adapters/mso-requests-db-adapter/src/main/resources/db/migration/V6.4__Add_Indexes_to_Infra_Active_Requests_Table.sql @@ -0,0 +1,21 @@ +ALTER TABLE `requestdb`.`infra_active_requests` +ADD INDEX IF NOT EXISTS `infra_active_requests__service_instance_id_idx` (`SERVICE_INSTANCE_ID` ASC), +ADD INDEX IF NOT EXISTS `infra_active_requests__service_instance_name_idx` (`SERVICE_INSTANCE_NAME` ASC), +ADD INDEX IF NOT EXISTS `infra_active_requests__vnf_id_idx` (`VNF_ID` ASC), +ADD INDEX IF NOT EXISTS `infra_active_requests__vnf_name_name_idx` (`VNF_NAME` ASC), +ADD INDEX IF NOT EXISTS `infra_active_requests__vf_module_id_idx` (`VF_MODULE_ID` ASC), +ADD INDEX IF NOT EXISTS `infra_active_requests__vf_module_name_idx` (`VF_MODULE_NAME` ASC), +ADD INDEX IF NOT EXISTS `infra_active_requests__volume_group_id_idx` (`VOLUME_GROUP_ID` ASC), +ADD INDEX IF NOT EXISTS `infra_active_requests__volume_group_name_idx` (`VOLUME_GROUP_NAME` ASC), +ADD INDEX IF NOT EXISTS `infra_active_requests__network_id_idx` (`NETWORK_ID` ASC), +ADD INDEX IF NOT EXISTS `infra_active_requests__network_name_idx` (`NETWORK_NAME` ASC), +ADD INDEX IF NOT EXISTS `infra_active_requests__configuration_id_idx` (`CONFIGURATION_ID` ASC), +ADD INDEX IF NOT EXISTS `infra_active_requests__configuration_name_idx` (`CONFIGURATION_NAME` ASC), +ADD INDEX IF NOT EXISTS `infra_active_requests__instance_group_id_idx` (`INSTANCE_GROUP_ID` ASC), +ADD INDEX IF NOT EXISTS `infra_active_requests__instance_group_name_idx` (`INSTANCE_GROUP_NAME` ASC), +ADD INDEX IF NOT EXISTS `infra_active_requests__aic_cloud_region_idx` (`AIC_CLOUD_REGION` ASC), +ADD INDEX IF NOT EXISTS `infra_active_requests__tenant_id_idx` (`TENANT_ID` ASC), +ADD INDEX IF NOT EXISTS `infra_active_requests__request_scope_idx` (`REQUEST_SCOPE` ASC), +ADD INDEX IF NOT EXISTS `infra_active_requests__requestor_id_idx` (`REQUESTOR_ID` ASC), +ADD INDEX IF NOT EXISTS `infra_active_requests__start_time_idx` (`START_TIME` ASC), +ADD INDEX IF NOT EXISTS `infra_active_requests__end_time_idx` (`END_TIME` ASC);
\ No newline at end of file diff --git a/adapters/mso-requests-db-adapter/src/main/resources/db/migration/V6.5__Drop_Table_Active_Requests.sql b/adapters/mso-requests-db-adapter/src/main/resources/db/migration/V6.5__Drop_Table_Active_Requests.sql new file mode 100644 index 0000000000..c3d385ccc2 --- /dev/null +++ b/adapters/mso-requests-db-adapter/src/main/resources/db/migration/V6.5__Drop_Table_Active_Requests.sql @@ -0,0 +1,4 @@ + +use requestdb; + +DROP TABLE IF EXISTS active_requests;
\ No newline at end of file diff --git a/adapters/mso-requests-db-adapter/src/main/resources/db/migration/V6.6__UpdateRequestProcessingData.sql b/adapters/mso-requests-db-adapter/src/main/resources/db/migration/V6.6__UpdateRequestProcessingData.sql new file mode 100644 index 0000000000..70d1d3fd46 --- /dev/null +++ b/adapters/mso-requests-db-adapter/src/main/resources/db/migration/V6.6__UpdateRequestProcessingData.sql @@ -0,0 +1,9 @@ +use requestdb; + +UPDATE request_processing_data +SET IS_DATA_INTERNAL = 1 +WHERE TAG = 'BPMNExecutionData'; + +UPDATE request_processing_data +SET IS_DATA_INTERNAL = 0 +WHERE TAG = 'StackInformation' OR TAG = 'pincFabricConfigRequest';
\ No newline at end of file diff --git a/adapters/mso-requests-db-adapter/src/main/resources/db/migration/V7.1__Drop_Columns_from_Infra_requests_archive_tables.sql b/adapters/mso-requests-db-adapter/src/main/resources/db/migration/V7.1__Drop_Columns_from_Infra_requests_archive_tables.sql new file mode 100644 index 0000000000..352fbfda21 --- /dev/null +++ b/adapters/mso-requests-db-adapter/src/main/resources/db/migration/V7.1__Drop_Columns_from_Infra_requests_archive_tables.sql @@ -0,0 +1,17 @@ +use requestdb; + +ALTER TABLE `infra_active_requests` DROP IF EXISTS `PROV_STATUS`; + +ALTER TABLE `archived_infra_requests` DROP IF EXISTS `PROV_STATUS`; + +ALTER TABLE `infra_active_requests` DROP IF EXISTS `ACTION`; + +ALTER TABLE `archived_infra_requests` DROP IF EXISTS `ACTION`; + +ALTER TABLE `infra_active_requests` DROP IF EXISTS `AAI_SERVICE_ID`; + +ALTER TABLE `archived_infra_requests` DROP IF EXISTS `AAI_SERVICE_ID`; + +ALTER TABLE `infra_active_requests` DROP IF EXISTS `REQUEST_TYPE`; + +ALTER TABLE `archived_infra_requests` DROP IF EXISTS `REQUEST_TYPE`; diff --git a/adapters/mso-requests-db-adapter/src/main/resources/db/migration/V7.2__Add_PNF_Column_Infra_Requests_archive_tables.sql b/adapters/mso-requests-db-adapter/src/main/resources/db/migration/V7.2__Add_PNF_Column_Infra_Requests_archive_tables.sql new file mode 100644 index 0000000000..dbdc925dae --- /dev/null +++ b/adapters/mso-requests-db-adapter/src/main/resources/db/migration/V7.2__Add_PNF_Column_Infra_Requests_archive_tables.sql @@ -0,0 +1,4 @@ +use requestdb; + +ALTER TABLE infra_active_requests ADD COLUMN IF NOT EXISTS PNF_ID varchar(45); +ALTER TABLE archived_infra_requests ADD COLUMN IF NOT EXISTS PNF_ID varchar(45);
\ No newline at end of file diff --git a/adapters/mso-requests-db-adapter/src/test/java/org/onap/so/adapters/requestdb/rest/RequestProcessingDataRequestDbQueryTest.java b/adapters/mso-requests-db-adapter/src/test/java/org/onap/so/adapters/requestdb/rest/RequestProcessingDataRequestDbQueryTest.java index abc70ed6bf..9641cb8004 100644 --- a/adapters/mso-requests-db-adapter/src/test/java/org/onap/so/adapters/requestdb/rest/RequestProcessingDataRequestDbQueryTest.java +++ b/adapters/mso-requests-db-adapter/src/test/java/org/onap/so/adapters/requestdb/rest/RequestProcessingDataRequestDbQueryTest.java @@ -7,9 +7,9 @@ * 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. @@ -86,4 +86,28 @@ public class RequestProcessingDataRequestDbQueryTest { assertEquals(dataFound.get(1).getValue(), secondEntry.getValue()); assertEquals(dataFound.get(1).getTag(), secondEntry.getTag()); } + + @Test + @Transactional + public void testGetRequestProcessingDataBySoRequestIdAndIsInternalData() { + String soRequestId = "00032ab7-na18-42e5-965d-8ea592502018"; + String tag = "pincFabricConfigRequest"; + RequestProcessingData firstEntry = new RequestProcessingData(); + List<RequestProcessingData> expectedList = new ArrayList<>(); + firstEntry.setSoRequestId(soRequestId); + firstEntry.setGroupingId("7d2e8c07-4d10-456d-bddc-37abf38ca715"); + firstEntry.setName("configurationId"); + firstEntry.setValue("52234bc0-d6a6-41d4-a901-79015e4877e2"); + firstEntry.setTag(tag); + expectedList.add(firstEntry); + + List<RequestProcessingData> dataFound = client.getExternalRequestProcessingDataBySoRequestId(soRequestId); + + assertEquals(1, dataFound.size()); + assertEquals(dataFound.get(0).getSoRequestId(), firstEntry.getSoRequestId()); + assertEquals(dataFound.get(0).getGroupingId(), firstEntry.getGroupingId()); + assertEquals(dataFound.get(0).getName(), firstEntry.getName()); + assertEquals(dataFound.get(0).getValue(), firstEntry.getValue()); + assertEquals(dataFound.get(0).getTag(), firstEntry.getTag()); + } } diff --git a/adapters/mso-requests-db-adapter/src/test/java/org/onap/so/adapters/requestsdb/ArchiveInfraRequestsSchedulerTest.java b/adapters/mso-requests-db-adapter/src/test/java/org/onap/so/adapters/requestsdb/ArchiveInfraRequestsSchedulerTest.java index 663be24318..3ac5c28c34 100644 --- a/adapters/mso-requests-db-adapter/src/test/java/org/onap/so/adapters/requestsdb/ArchiveInfraRequestsSchedulerTest.java +++ b/adapters/mso-requests-db-adapter/src/test/java/org/onap/so/adapters/requestsdb/ArchiveInfraRequestsSchedulerTest.java @@ -53,11 +53,9 @@ public class ArchiveInfraRequestsSchedulerTest extends RequestsAdapterBase { InfraActiveRequests iar1 = new InfraActiveRequests(); iar1.setRequestId(requestId1); - iar1.setAction("action1"); InfraActiveRequests iar2 = new InfraActiveRequests(); iar2.setRequestId(requestId2); - iar2.setAction("action2"); List<InfraActiveRequests> requests = new ArrayList<>(); requests.add(iar1); diff --git a/adapters/mso-requests-db-adapter/src/test/java/org/onap/so/adapters/requestsdb/InfraActiveRequestsRepositoryCustomControllerTest.java b/adapters/mso-requests-db-adapter/src/test/java/org/onap/so/adapters/requestsdb/InfraActiveRequestsRepositoryCustomControllerTest.java index 4ed3285a70..a7f21334ed 100644 --- a/adapters/mso-requests-db-adapter/src/test/java/org/onap/so/adapters/requestsdb/InfraActiveRequestsRepositoryCustomControllerTest.java +++ b/adapters/mso-requests-db-adapter/src/test/java/org/onap/so/adapters/requestsdb/InfraActiveRequestsRepositoryCustomControllerTest.java @@ -21,8 +21,13 @@ package org.onap.so.adapters.requestsdb; +import static com.shazam.shazamcrest.matcher.Matchers.sameBeanAs; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import java.sql.Timestamp; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -33,6 +38,7 @@ import org.junit.Before; import org.junit.Test; import org.onap.so.db.request.beans.InfraActiveRequests; import org.onap.so.db.request.data.controller.InstanceNameDuplicateCheckRequest; +import org.onap.so.serviceinstancebeans.ModelType; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.web.server.LocalServerPort; @@ -77,7 +83,6 @@ public class InfraActiveRequestsRepositoryCustomControllerTest extends RequestsA assertEquals(infraActiveRequests.getNetworkName(), infraActiveRequestsResponse.getNetworkName()); assertEquals(infraActiveRequests.getConfigurationId(), infraActiveRequestsResponse.getConfigurationId()); assertEquals(infraActiveRequests.getConfigurationName(), infraActiveRequestsResponse.getConfigurationName()); - assertEquals(infraActiveRequests.getAaiServiceId(), infraActiveRequestsResponse.getAaiServiceId()); assertEquals(infraActiveRequests.getTenantId(), infraActiveRequestsResponse.getTenantId()); assertEquals(infraActiveRequests.getRequestScope(), infraActiveRequestsResponse.getRequestScope()); assertEquals(infraActiveRequests.getRequestorId(), infraActiveRequestsResponse.getRequestorId()); @@ -85,20 +90,11 @@ public class InfraActiveRequestsRepositoryCustomControllerTest extends RequestsA assertEquals(infraActiveRequests.getOperationalEnvId(), infraActiveRequestsResponse.getOperationalEnvId()); assertEquals(infraActiveRequests.getOperationalEnvName(), infraActiveRequestsResponse.getOperationalEnvName()); assertEquals(infraActiveRequests.getRequestStatus(), infraActiveRequestsResponse.getRequestStatus()); - assertEquals(infraActiveRequests.getAction(), infraActiveRequestsResponse.getAction()); assertEquals(infraActiveRequests.getRequestUrl(), infraActiveRequestsResponse.getRequestUrl()); } @Before public void setup() { - - headers = new HttpHeaders(); - restTemplate = new TestRestTemplate("test", "test"); - - headers.set("Accept", MediaType.APPLICATION_JSON); - headers.set("Content-Type", MediaType.APPLICATION_JSON); - headers.set("Authorization", msoAdaptersAuth); - infraActiveRequests = new InfraActiveRequests(); infraActiveRequests.setRequestId(UUID.randomUUID().toString()); @@ -115,23 +111,32 @@ public class InfraActiveRequestsRepositoryCustomControllerTest extends RequestsA infraActiveRequests.setNetworkName("networkInstanceNameTest"); infraActiveRequests.setConfigurationId(UUID.randomUUID().toString()); infraActiveRequests.setConfigurationName("configurationInstanceNameTest"); - infraActiveRequests.setAicCloudRegion("1"); + infraActiveRequests.setCloudRegion("1"); infraActiveRequests.setTenantId(UUID.randomUUID().toString()); infraActiveRequests.setRequestScope("operationalEnvironment"); infraActiveRequests.setRequestorId(UUID.randomUUID().toString()); infraActiveRequests.setSource("sourceTest"); infraActiveRequests.setOperationalEnvName(UUID.randomUUID().toString()); infraActiveRequests.setRequestStatus("IN_PROGRESS"); - infraActiveRequests.setAction("create"); infraActiveRequests .setRequestUrl("http://localhost:8080/onap/so/infra/serviceInstantiation/v7/serviceInstances"); - HttpEntity<String> entity = new HttpEntity(infraActiveRequests, headers); + saveInfraActiveRequest(infraActiveRequests); + } + + public void saveInfraActiveRequest(InfraActiveRequests request) { + headers = new HttpHeaders(); + restTemplate = new TestRestTemplate("test", "test"); + + headers.set("Accept", MediaType.APPLICATION_JSON); + headers.set("Content-Type", MediaType.APPLICATION_JSON); + headers.set("Authorization", msoAdaptersAuth); + + HttpEntity<String> entity = new HttpEntity(request, headers); UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(createURLWithPort("/infraActiveRequests")); ResponseEntity<String> response = restTemplate.exchange(builder.toUriString(), HttpMethod.POST, entity, String.class); - assertEquals(201, response.getStatusCodeValue()); } @@ -297,4 +302,38 @@ public class InfraActiveRequestsRepositoryCustomControllerTest extends RequestsA assertEquals(200, response.getStatusCodeValue()); assertEquals(null, response.getBody()); } + + @Test + public void getInProgressVolumeGroupsAndVfModulesTest() { + boolean expectedReturned = false; + InfraActiveRequests request = new InfraActiveRequests(); + request.setRequestId(UUID.randomUUID().toString()); + request.setVfModuleId(UUID.randomUUID().toString()); + request.setRequestStatus("IN_PROGRESS"); + request.setRequestScope(ModelType.vfModule.toString()); + Instant startInstant = Instant.now().minus(3, ChronoUnit.MINUTES); + request.setStartTime(Timestamp.from(startInstant)); + request.setRequestAction("create"); + saveInfraActiveRequest(request); + + UriComponentsBuilder builder = UriComponentsBuilder + .fromHttpUrl(createURLWithPort("/infraActiveRequests/getInProgressVolumeGroupsAndVfModules")); + + HttpEntity<String> entity = new HttpEntity<String>(headers); + + ResponseEntity<List<InfraActiveRequests>> response = restTemplate.exchange(builder.toUriString(), + HttpMethod.GET, entity, new ParameterizedTypeReference<List<InfraActiveRequests>>() {}); + + List<InfraActiveRequests> responseList = response.getBody(); + + assertEquals(200, response.getStatusCodeValue()); + + for (InfraActiveRequests result : responseList) { + if (result.getRequestId().equals(request.getRequestId())) { + assertThat(request, sameBeanAs(result).ignoring("modifyTime")); + expectedReturned = true; + } + } + assertTrue(expectedReturned); + } } diff --git a/adapters/mso-requests-db-adapter/src/test/java/org/onap/so/adapters/requestsdb/adapters/MSORequestDBImplTest.java b/adapters/mso-requests-db-adapter/src/test/java/org/onap/so/adapters/requestsdb/adapters/MSORequestDBImplTest.java index e53b957210..fef9dbc22c 100644 --- a/adapters/mso-requests-db-adapter/src/test/java/org/onap/so/adapters/requestsdb/adapters/MSORequestDBImplTest.java +++ b/adapters/mso-requests-db-adapter/src/test/java/org/onap/so/adapters/requestsdb/adapters/MSORequestDBImplTest.java @@ -23,17 +23,14 @@ package org.onap.so.adapters.requestsdb.adapters; import static com.shazam.shazamcrest.MatcherAssert.assertThat; import static com.shazam.shazamcrest.matcher.Matchers.sameBeanAs; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; import java.util.ArrayList; import java.util.List; -import java.util.Map; import org.apache.cxf.jaxws.JaxWsProxyFactoryBean; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.onap.logging.ref.slf4j.ONAPLogConstants; import org.onap.so.adapters.requestsdb.MsoRequestsDbAdapter; import org.onap.so.adapters.requestsdb.RequestStatusType; import org.onap.so.adapters.requestsdb.RequestsAdapterBase; @@ -47,7 +44,6 @@ import org.onap.so.db.request.data.repository.ResourceOperationStatusRepository; import org.onap.so.requestsdb.RequestsDbConstant; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.web.server.LocalServerPort; -import ch.qos.logback.classic.spi.ILoggingEvent; public class MSORequestDBImplTest extends RequestsAdapterBase { @@ -94,7 +90,6 @@ public class MSORequestDBImplTest extends RequestsAdapterBase { private InfraActiveRequests buildTestRequest() { InfraActiveRequests testRequest = new InfraActiveRequests(); testRequest.setRequestId("00032ab7-3fb3-42e5-965d-8ea592502017"); - testRequest.setClientRequestId("00032ab7-3fb3-42e5-965d-8ea592502016"); testRequest.setRequestStatus("COMPLETE"); testRequest.setStatusMessage("Vf Module has been deleted successfully."); testRequest.setProgress((long) 100); @@ -103,8 +98,7 @@ public class MSORequestDBImplTest extends RequestsAdapterBase { testRequest.setServiceInstanceId("e3b5744d-2ad1-4cdd-8390-c999a38829bc"); testRequest.setRequestAction("deleteInstance"); testRequest.setRequestScope("vfModule"); - testRequest.setAction("deleteInstance"); - testRequest.setAicCloudRegion("mtn6"); + testRequest.setCloudRegion("mtn6"); testRequest.setLastModifiedBy("BPMN"); testRequest.setVfModuleId("c7d527b1-7a91-49fd-b97d-1c8c0f4a7992"); testRequest.setVfModuleModelName("vSAMP10aDEV::base::module-0"); @@ -153,26 +147,10 @@ public class MSORequestDBImplTest extends RequestsAdapterBase { } @Test - public void getByClientRequestId() throws MsoRequestsDbException { - InfraActiveRequests testRequest = setupTestEntities(); - // Given - String clientRequestId = "00032ab7-3fb3-42e5-965d-8ea592502016"; - - // When - InfraActiveRequests infraRequest = dbAdapter.getInfraRequest(clientRequestId); - if (infraRequest == null) - fail("Null infraRequest"); - - // Then - assertEquals(clientRequestId, infraRequest.getClientRequestId()); - } - - - @Test public void updateInfraRequest() throws MsoRequestsDbException { InfraActiveRequests testRequest = setupTestEntities(); // Given - String clientRequestId = "00032ab7-3fb3-42e5-965d-8ea592502016"; + String requestId = "00032ab7-3fb3-42e5-965d-8ea592502017"; // When @@ -214,7 +192,7 @@ public class MSORequestDBImplTest extends RequestsAdapterBase { dbAdapter.updateInfraRequest(testRequest.getRequestId(), lastModifiedBy, statusMessage, responseBody, requestStatus, progress, vnfOutputs, serviceInstanceId, networkId, vnfId, vfModuleId, volumeGroupId, serviceInstanceName, configurationId, configurationName, vfModuleName); - InfraActiveRequests infraRequest = dbAdapter.getInfraRequest(clientRequestId); + InfraActiveRequests infraRequest = dbAdapter.getInfraRequest(requestId); // Then assertThat(infraRequest, sameBeanAs(testRequest).ignoring("requestBody").ignoring("endTime") .ignoring("startTime").ignoring("modifyTime")); @@ -241,12 +219,12 @@ public class MSORequestDBImplTest extends RequestsAdapterBase { public void updateInfraRequestNulls() throws MsoRequestsDbException { InfraActiveRequests testRequest = setupTestEntities(); // Given - String clientRequestId = "00032ab7-3fb3-42e5-965d-8ea592502016"; + String requestId = "00032ab7-3fb3-42e5-965d-8ea592502017"; // When dbAdapter.updateInfraRequest(testRequest.getRequestId(), testRequest.getLastModifiedBy(), null, null, null, null, null, null, null, null, null, null, null, null, null, null); - InfraActiveRequests infraRequest = dbAdapter.getInfraRequest(clientRequestId); + InfraActiveRequests infraRequest = dbAdapter.getInfraRequest(requestId); // Then assertThat(infraRequest, sameBeanAs(testRequest).ignoring("requestBody").ignoring("endTime") .ignoring("startTime").ignoring("modifyTime")); @@ -441,28 +419,5 @@ public class MSORequestDBImplTest extends RequestsAdapterBase { ResourceOperationStatus actualResource = dbAdapter.getResourceOperationStatus(serviceId, operationId, "template1"); assertThat(actualResource, sameBeanAs(expectedResource)); - - for (ILoggingEvent logEvent : TestAppender.events) - if (logEvent.getLoggerName().equals("org.onap.so.logging.cxf.interceptor.SOAPLoggingInInterceptor") - && logEvent.getMarker().getName().equals("ENTRY")) { - Map<String, String> mdc = logEvent.getMDCPropertyMap(); - assertNotNull(mdc.get(ONAPLogConstants.MDCs.INSTANCE_UUID)); - assertNotNull(mdc.get(ONAPLogConstants.MDCs.REQUEST_ID)); - assertNotNull(mdc.get(ONAPLogConstants.MDCs.INVOCATION_ID)); - assertEquals("", mdc.get(ONAPLogConstants.MDCs.PARTNER_NAME)); - assertEquals("/services/RequestsDbAdapter", mdc.get(ONAPLogConstants.MDCs.SERVICE_NAME)); - assertEquals("INPROGRESS", mdc.get(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE)); - } else if (logEvent.getLoggerName().equals("org.onap.so.logging.cxf.interceptor.SOAPLoggingOutInterceptor") - && logEvent.getMarker().getName().equals("EXIT")) { - Map<String, String> mdc = logEvent.getMDCPropertyMap(); - assertNotNull(mdc.get(ONAPLogConstants.MDCs.REQUEST_ID)); - assertNotNull(mdc.get(ONAPLogConstants.MDCs.INVOCATION_ID)); - assertEquals(null, mdc.get(ONAPLogConstants.MDCs.RESPONSE_CODE)); - assertEquals("", mdc.get(ONAPLogConstants.MDCs.PARTNER_NAME)); - assertEquals("/services/RequestsDbAdapter", mdc.get(ONAPLogConstants.MDCs.SERVICE_NAME)); - assertEquals("COMPLETED", mdc.get(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE)); - } } - - } diff --git a/adapters/mso-requests-db-adapter/src/test/java/org/onap/so/adapters/requestsdb/client/RequestsDbClientTest.java b/adapters/mso-requests-db-adapter/src/test/java/org/onap/so/adapters/requestsdb/client/RequestsDbClientTest.java index 49291b6863..09fea0644e 100644 --- a/adapters/mso-requests-db-adapter/src/test/java/org/onap/so/adapters/requestsdb/client/RequestsDbClientTest.java +++ b/adapters/mso-requests-db-adapter/src/test/java/org/onap/so/adapters/requestsdb/client/RequestsDbClientTest.java @@ -27,6 +27,8 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import java.sql.Timestamp; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -41,6 +43,7 @@ import org.onap.so.db.request.beans.OperationStatus; import org.onap.so.db.request.beans.OperationalEnvDistributionStatus; import org.onap.so.db.request.beans.OperationalEnvServiceModelStatus; import org.onap.so.db.request.beans.RequestProcessingData; +import org.onap.so.serviceinstancebeans.ModelType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.web.server.LocalServerPort; @@ -73,14 +76,13 @@ public class RequestsDbClientTest extends RequestsAdapterBase { infraActiveRequests.setNetworkName("networkInstanceNameTest"); infraActiveRequests.setConfigurationId(UUID.randomUUID().toString()); infraActiveRequests.setConfigurationName("configurationInstanceNameTest"); - infraActiveRequests.setAicCloudRegion("1"); + infraActiveRequests.setCloudRegion("1"); infraActiveRequests.setTenantId(UUID.randomUUID().toString()); infraActiveRequests.setRequestScope("operationalEnvironment"); infraActiveRequests.setRequestorId(UUID.randomUUID().toString()); infraActiveRequests.setSource("sourceTest"); infraActiveRequests.setOperationalEnvName(UUID.randomUUID().toString()); infraActiveRequests.setRequestStatus("IN_PROGRESS"); - infraActiveRequests.setAction("create"); infraActiveRequests.setRequestAction("someaction"); infraActiveRequests.setStartTime(new Timestamp(System.currentTimeMillis())); infraActiveRequests @@ -110,14 +112,13 @@ public class RequestsDbClientTest extends RequestsAdapterBase { infraActiveRequests2.setNetworkName("networkInstanceNameTest"); infraActiveRequests2.setConfigurationId(UUID.randomUUID().toString()); infraActiveRequests2.setConfigurationName("configurationInstanceNameTest"); - infraActiveRequests2.setAicCloudRegion("1"); + infraActiveRequests2.setCloudRegion("1"); infraActiveRequests2.setTenantId(UUID.randomUUID().toString()); infraActiveRequests2.setRequestScope("operationalEnvironment"); infraActiveRequests2.setRequestorId(UUID.randomUUID().toString()); infraActiveRequests2.setSource("sourceTest"); infraActiveRequests2.setOperationalEnvName(UUID.randomUUID().toString()); infraActiveRequests2.setRequestStatus("IN_PROGRESS"); - infraActiveRequests2.setAction("create"); infraActiveRequests2.setRequestAction("someaction"); infraActiveRequests2.setStartTime(new Timestamp(System.currentTimeMillis())); infraActiveRequests @@ -314,4 +315,20 @@ public class RequestsDbClientTest extends RequestsAdapterBase { verifyInfraActiveRequests(infraActiveRequestsResponse.get(0)); } + + @Test + public void getInProgressVolumeGroupsAndVfModulesTest() { + InfraActiveRequests request = new InfraActiveRequests(); + request.setRequestId(UUID.randomUUID().toString()); + request.setVfModuleId(UUID.randomUUID().toString()); + request.setRequestStatus("IN_PROGRESS"); + request.setRequestScope(ModelType.vfModule.toString()); + Instant startInstant = Instant.now().minus(3, ChronoUnit.MINUTES); + request.setStartTime(Timestamp.from(startInstant)); + request.setRequestAction("create"); + requestsDbClient.save(request); + + List<InfraActiveRequests> infraActiveRequests = requestsDbClient.getInProgressVolumeGroupsAndVfModules(); + assertThat(request, sameBeanAs(infraActiveRequests.get(0)).ignoring("modifyTime")); + } } diff --git a/adapters/mso-requests-db-adapter/src/test/resources/db/migration/afterMigrate.sql b/adapters/mso-requests-db-adapter/src/test/resources/db/migration/afterMigrate.sql index 9c2ea6d3bf..b34b272b51 100644 --- a/adapters/mso-requests-db-adapter/src/test/resources/db/migration/afterMigrate.sql +++ b/adapters/mso-requests-db-adapter/src/test/resources/db/migration/afterMigrate.sql @@ -4,13 +4,13 @@ insert into operation_status(service_id, operation_id, service_name, user_id, re ('serviceid', 'operationid', 'servicename', 'userid', 'result', 'operationcontent', 'progress', 'reason', '2016-11-24 13:19:10', '2016-11-24 13:19:10'); -insert into infra_active_requests(request_id, client_request_id, action, request_status, status_message, progress, start_time, end_time, source, vnf_id, vnf_name, vnf_type, service_type, aic_node_clli, tenant_id, prov_status, vnf_params, vnf_outputs, request_body, response_body, last_modified_by, modify_time, request_type, volume_group_id, volume_group_name, vf_module_id, vf_module_name, vf_module_model_name, aai_service_id, aic_cloud_region, callback_url, correlator, network_id, network_name, network_type, request_scope, request_action, service_instance_id, service_instance_name, requestor_id, configuration_id, configuration_name, operational_env_id, operational_env_name, request_url) values -('00032ab7-3fb3-42e5-965d-8ea592502017', '00032ab7-3fb3-42e5-965d-8ea592502016', 'deleteInstance', 'COMPLETE', 'Vf Module has been deleted successfully.', '100', '2016-12-22 18:59:54', '2016-12-22 19:00:28', 'VID', 'b92f60c8-8de3-46c1-8dc1-e4390ac2b005', null, null, null, null, '6accefef3cb442ff9e644d589fb04107', null, null, null, '{"requestDetails":{"modelInfo":{"modelType":"vfModule","modelName":"vSAMP10aDEV::base::module-0"},"requestInfo":{"source":"VID"},"cloudConfiguration":{"tenantId":"6accefef3cb442ff9e644d589fb04107","lcpCloudRegionId":"mtn6"}}}', null, 'BPMN', '2016-12-22 19:00:28', null, null, null, 'c7d527b1-7a91-49fd-b97d-1c8c0f4a7992', null, 'vSAMP10aDEV::base::module-0', null, 'mtn6', null, null, null, null, null, 'vfModule', 'deleteInstance', 'e3b5744d-2ad1-4cdd-8390-c999a38829bc', null, null, null, null, null, null, 'http://localhost:8080/onap/so/infra/serviceInstantiation/v7/serviceInstances'), -('00093944-bf16-4373-ab9a-3adfe730ff2d', null, 'createInstance', 'FAILED', 'Error: Locked instance - This service (MSODEV_1707_SI_vSAMP10a_011-4) already has a request being worked with a status of IN_PROGRESS (RequestId - 278e83b1-4f9f-450e-9e7d-3700a6ed22f4). The existing request must finish or be cleaned up before proceeding.', '100', '2017-07-11 18:33:26', '2017-07-11 18:33:26', 'VID', null, null, null, null, null, '19123c2924c648eb8e42a3c1f14b7682', null, null, null, '{"requestDetails":{"modelInfo":{"modelInvariantId":"9647dfc4-2083-11e7-93ae-92361f002671","modelType":"service","modelName":"MSOTADevInfra_vSAMP10a_Service","modelVersion":"1.0","modelVersionId":"5df8b6de-2083-11e7-93ae-92361f002671"},"requestInfo":{"source":"VID","instanceName":"MSODEV_1707_SI_vSAMP10a_011-4","suppressRollback":false,"requestorId":"xxxxxx"},"subscriberInfo":{"globalSubscriberId":"MSO_1610_dev","subscriberName":"MSO_1610_dev"},"cloudConfiguration":{"tenantId":"19123c2924c648eb8e42a3c1f14b7682","lcpCloudRegionId":"mtn6"},"requestParameters":{"subscriptionServiceType":"MSO-dev-service-type","userParams":[{"name":"someUserParam","value":"someValue"}],"aLaCarte":true,"autoBuildVfModules":false,"cascadeDelete":false,"usePreload":true,"alaCarteSet":true,"alaCarte":true}}}', null, 'APIH', '2016-12-22 19:00:28', null, null, null, null, null, null, null, 'mtn6', null, null, null, null, null, 'service', 'createInstance', null, 'MSODEV_1707_SI_vSAMP10a_011-4', 'xxxxxx', null, null, null, null, 'http://localhost:8080/onap/so/infra/serviceInstantiation/v7/serviceInstances'), -('001619d2-a297-4a4b-a9f5-e2823c88458f', '001619d2-a297-4a4b-a9f5-e2823c88458f', 'CREATE_VF_MODULE', 'COMPLETE', 'COMPLETED', '100', '2016-07-01 14:11:42', '2017-05-02 16:03:34', 'PORTAL', null, 'test-vscp', 'elena_test21', null, null, '381b9ff6c75e4625b7a4182f90fc68d3', null, null, null, '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<vnf-request xmlns=\"http://org.onap.so/mso/infra/vnf-request/v1\">\n <request-info>\n <request-id>001619d2-a297-4a4b-a9f5-e2823c88458f</request-id>\n <action>CREATE_VF_MODULE</action>\n <source>PORTAL</source>\n </request-info>\n <vnf-inputs>\n <vnf-name>test-vscp</vnf-name>\n <vf-module-name>moduleName</vf-module-name>\n <vnf-type>elena_test21</vnf-type>\n <vf-module-model-name>moduleModelName</vf-module-model-name>\n <asdc-service-model-version>1.0</asdc-service-model-version>\n <service-id>a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb</service-id>\n <aic-cloud-region>mtn9</aic-cloud-region>\n <tenant-id>381b9ff6c75e4625b7a4182f90fc68d3</tenant-id>\n <persona-model-id></persona-model-id>\n <persona-model-version></persona-model-version>\n <is-base-vf-module>false</is-base-vf-module>\n </vnf-inputs>\n <vnf-params xmlns:tns=\"http://org.onap.so/mso/infra/vnf-request/v1\"/>\n</vnf-request>\n', 'NONE', 'RDBTEST', '2016-07-01 14:11:42', 'VNF', null, null, null, 'MODULENAME1', 'moduleModelName', 'a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb', 'mtn9', null, null, null, null, null, 'vfModule', 'createInstance', null, null, null, null, null, null, null, 'http://localhost:8080/onap/so/infra/serviceInstantiation/v7/serviceInstances'), -('00164b9e-784d-48a8-8973-bbad6ef818ed', null, 'createInstance', 'COMPLETE', 'Service Instance was created successfully.', '100', '2017-09-28 12:45:51', '2017-09-28 12:45:53', 'VID', null, null, null, null, null, '19123c2924c648eb8e42a3c1f14b7682', null, null, null, '{"requestDetails":{"requestDetails":{"modelInfo":{"modelCustomizationName":null,"modelInvariantId":"52b49b5d-3086-4ffd-b5e6-1b1e5e7e062f","modelType":"service","modelNameVersionId":null,"modelName":"MSO Test Network","modelVersion":"1.0","modelCustomizationUuid":null,"modelVersionId":"aed5a5b7-20d3-44f7-90a3-ddbd16f14d1e","modelCustomizationId":null,"modelUuid":null,"modelInvariantUuid":null,"modelInstanceName":null},"requestInfo":{"billingAccountNumber":null,"callbackUrl":null,"correlator":null,"orderNumber":null,"productFamilyId":null,"orderVersion":null,"source":"VID","instanceName":"DEV-MTN6-3100-0927-1","suppressRollback":false,"requestorId":"xxxxxx"},"relatedInstanceList":null,"subscriberInfo":{"globalSubscriberId":"MSO_1610_dev","subscriberName":"MSO_1610_dev"},"cloudConfiguration":{"aicNodeClli":null,"tenantId":"19123c2924c648eb8e42a3c1f14b7682","lcpCloudRegionId":"mtn6"},"requestParameters":{"subscriptionServiceType":"MSO-dev-service-type","userParams":[{"name":"someUserParam","value":"someValue"}],"aLaCarte":true,"autoBuildVfModules":false,"cascadeDelete":false,"usePreload":true,"alaCarte":true},"project":null,"owningEntity":null,"platform":null,"lineOfBusiness":null}}}', null, 'CreateGenericALaCarteServiceInstance', '2017-09-28 12:45:52', null, null, null, null, null, null, null, 'mtn6', null, null, null, null, null, 'service', 'createInstance', 'b2f59173-b7e5-4e0f-8440-232fd601b865', 'DEV-MTN6-3100-0927-1', 'xxxxxx', null, null, null, null, 'http://localhost:8080/onap/so/infra/serviceInstantiation/v7/serviceInstances'), -('00173cc9-5ce2-4673-a810-f87fefb2829e', null, 'createInstance', 'FAILED', 'Error parsing request. No valid instanceName is specified', '100', '2017-04-14 21:08:46', '2017-04-14 21:08:46', 'VID', null, null, null, null, null, 'a259ae7b7c3f493cb3d91f95a7c18149', null, null, null, '{"requestDetails":{"modelInfo":{"modelInvariantId":"ff6163d4-7214-459e-9f76-507b4eb00f51","modelType":"service","modelName":"ConstraintsSrvcVID","modelVersion":"2.0","modelVersionId":"722d256c-a374-4fba-a14f-a59b76bb7656"},"requestInfo":{"productFamilyId":"LRSI-OSPF","source":"VID","requestorId":"xxxxxx"},"subscriberInfo":{"globalSubscriberId":"a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb"},"cloudConfiguration":{"tenantId":"a259ae7b7c3f493cb3d91f95a7c18149","lcpCloudRegionId":"mtn16"},"requestParameters":{"subscriptionServiceType":"Mobility","userParams":[{"name":"neutronport6_name","value":"8"},{"name":"neutronnet5_network_name","value":"8"},{"name":"contrailv2vlansubinterface3_name","value":"false"}]}}}', null, 'APIH', '2016-12-22 19:00:28', null, null, null, null, null, null, null, 'mtn16', null, null, null, null, null, 'service', 'createInstance', null, null, null, null, null, null, null, 'http://localhost:8080/onap/so/infra/serviceInstantiation/v7/serviceInstances'), -('0017f68c-eb2d-45bb-b7c7-ec31b37dc349', null, 'activateInstance', 'UNLOCKED', null, '20', '2017-09-26 16:09:29', '2017-09-28 12:45:53', 'VID', null, null, null, null, null, null, null, null, null, '{"requestDetails":{"modelInfo":{"modelCustomizationName":null,"modelInvariantId":"1587cf0e-f12f-478d-8530-5c55ac578c39","modelType":"configuration","modelNameVersionId":null,"modelName":null,"modelVersion":null,"modelCustomizationUuid":null,"modelVersionId":"36a3a8ea-49a6-4ac8-b06c-89a545444455","modelCustomizationId":"68dc9a92-214c-11e7-93ae-92361f002671","modelUuid":null,"modelInvariantUuid":null,"modelInstanceName":null},"requestInfo":{"billingAccountNumber":null,"callbackUrl":null,"correlator":null,"orderNumber":null,"productFamilyId":null,"orderVersion":null,"source":"VID","instanceName":null,"suppressRollback":false,"requestorId":"xxxxxx"},"relatedInstanceList":[{"relatedInstance":{"instanceName":null,"instanceId":"9e15a443-af65-4f05-9000-47ae495e937d","modelInfo":{"modelCustomizationName":null,"modelInvariantId":"de19ae10-9a25-11e7-abc4-cec278b6b50a","modelType":"service","modelNameVersionId":null,"modelName":"MSOTADevInfra_Configuration_Service","modelVersion":"1.0","modelCustomizationUuid":null,"modelVersionId":"ee938612-9a25-11e7-abc4-cec278b6b50a","modelCustomizationId":null,"modelUuid":null,"modelInvariantUuid":null,"modelInstanceName":null},"instanceDirection":null}}],"subscriberInfo":null,"cloudConfiguration":{"aicNodeClli":null,"tenantId":null,"lcpCloudRegionId":"mtn6"},"requestParameters":{"subscriptionServiceType":null,"userParams":[],"aLaCarte":false,"autoBuildVfModules":false,"cascadeDelete":false,"usePreload":true,"alaCarte":false},"project":null,"owningEntity":null,"platform":null,"lineOfBusiness":null}}', null, 'APIH', '2017-09-26 16:09:29', null, null, null, null, null, null, null, 'mtn6', null, null, null, null, null, 'configuration', 'activateInstance', '9e15a443-af65-4f05-9000-47ae495e937d', null, 'xxxxxx', '26ef7f15-57bb-48df-8170-e59edc26234c', null, null, null, 'http://localhost:8080/onap/so/infra/serviceInstantiation/v7/serviceInstances'); +insert into infra_active_requests(request_id, request_status, status_message, progress, start_time, end_time, source, vnf_id, vnf_name, vnf_type, service_type, tenant_id, vnf_params, vnf_outputs, request_body, response_body, last_modified_by, modify_time, volume_group_id, volume_group_name, vf_module_id, vf_module_name, vf_module_model_name, cloud_region, callback_url, correlator, network_id, network_name, network_type, request_scope, request_action, service_instance_id, service_instance_name, requestor_id, configuration_id, configuration_name, operational_env_id, operational_env_name, request_url) values +('00032ab7-3fb3-42e5-965d-8ea592502017', 'COMPLETE', 'Vf Module has been deleted successfully.', '100', '2016-12-22 18:59:54', '2016-12-22 19:00:28', 'VID', 'b92f60c8-8de3-46c1-8dc1-e4390ac2b005', null, null, null, '6accefef3cb442ff9e644d589fb04107', null, null, '{"requestDetails":{"modelInfo":{"modelType":"vfModule","modelName":"vSAMP10aDEV::base::module-0"},"requestInfo":{"source":"VID"},"cloudConfiguration":{"tenantId":"6accefef3cb442ff9e644d589fb04107","lcpCloudRegionId":"mtn6"}}}', null, 'BPMN', '2016-12-22 19:00:28', null, null, 'c7d527b1-7a91-49fd-b97d-1c8c0f4a7992', null, 'vSAMP10aDEV::base::module-0', 'mtn6', null, null, null, null, null, 'vfModule', 'deleteInstance', 'e3b5744d-2ad1-4cdd-8390-c999a38829bc', null, null, null, null, null, null, 'http://localhost:8080/onap/so/infra/serviceInstantiation/v7/serviceInstances'), +('00093944-bf16-4373-ab9a-3adfe730ff2d', 'FAILED', 'Error: Locked instance - This service (MSODEV_1707_SI_vSAMP10a_011-4) already has a request being worked with a status of IN_PROGRESS (RequestId - 278e83b1-4f9f-450e-9e7d-3700a6ed22f4). The existing request must finish or be cleaned up before proceeding.', '100', '2017-07-11 18:33:26', '2017-07-11 18:33:26', 'VID', null, null, null, null, '19123c2924c648eb8e42a3c1f14b7682', null, null, '{"requestDetails":{"modelInfo":{"modelInvariantId":"9647dfc4-2083-11e7-93ae-92361f002671","modelType":"service","modelName":"MSOTADevInfra_vSAMP10a_Service","modelVersion":"1.0","modelVersionId":"5df8b6de-2083-11e7-93ae-92361f002671"},"requestInfo":{"source":"VID","instanceName":"MSODEV_1707_SI_vSAMP10a_011-4","suppressRollback":false,"requestorId":"xxxxxx"},"subscriberInfo":{"globalSubscriberId":"MSO_1610_dev","subscriberName":"MSO_1610_dev"},"cloudConfiguration":{"tenantId":"19123c2924c648eb8e42a3c1f14b7682","lcpCloudRegionId":"mtn6"},"requestParameters":{"subscriptionServiceType":"MSO-dev-service-type","userParams":[{"name":"someUserParam","value":"someValue"}],"aLaCarte":true,"autoBuildVfModules":false,"cascadeDelete":false,"usePreload":true,"alaCarteSet":true,"alaCarte":true}}}', null, 'APIH', '2016-12-22 19:00:28', null, null, null, null, null, 'mtn6', null, null, null, null, null, 'service', 'createInstance', null, 'MSODEV_1707_SI_vSAMP10a_011-4', 'xxxxxx', null, null, null, null, 'http://localhost:8080/onap/so/infra/serviceInstantiation/v7/serviceInstances'), +('001619d2-a297-4a4b-a9f5-e2823c88458f', 'COMPLETE', 'COMPLETED', '100', '2016-07-01 14:11:42', '2017-05-02 16:03:34', 'PORTAL', null, 'test-vscp', 'elena_test21', null, '381b9ff6c75e4625b7a4182f90fc68d3', null, null, '<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<vnf-request xmlns=\"http://org.onap.so/mso/infra/vnf-request/v1\">\n <request-info>\n <request-id>001619d2-a297-4a4b-a9f5-e2823c88458f</request-id>\n <action>CREATE_VF_MODULE</action>\n <source>PORTAL</source>\n </request-info>\n <vnf-inputs>\n <vnf-name>test-vscp</vnf-name>\n <vf-module-name>moduleName</vf-module-name>\n <vnf-type>elena_test21</vnf-type>\n <vf-module-model-name>moduleModelName</vf-module-model-name>\n <asdc-service-model-version>1.0</asdc-service-model-version>\n <service-id>a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb</service-id>\n <aic-cloud-region>mtn9</aic-cloud-region>\n <tenant-id>381b9ff6c75e4625b7a4182f90fc68d3</tenant-id>\n <persona-model-id></persona-model-id>\n <persona-model-version></persona-model-version>\n <is-base-vf-module>false</is-base-vf-module>\n </vnf-inputs>\n <vnf-params xmlns:tns=\"http://org.onap.so/mso/infra/vnf-request/v1\"/>\n</vnf-request>\n', 'NONE', 'RDBTEST', '2016-07-01 14:11:42', null, null, null, 'MODULENAME1', 'moduleModelName', 'mtn9', null, null, null, null, null, 'vfModule', 'createInstance', null, null, null, null, null, null, null, 'http://localhost:8080/onap/so/infra/serviceInstantiation/v7/serviceInstances'), +('00164b9e-784d-48a8-8973-bbad6ef818ed', 'COMPLETE', 'Service Instance was created successfully.', '100', '2017-09-28 12:45:51', '2017-09-28 12:45:53', 'VID', null, null, null, null, '19123c2924c648eb8e42a3c1f14b7682', null, null, '{"requestDetails":{"requestDetails":{"modelInfo":{"modelCustomizationName":null,"modelInvariantId":"52b49b5d-3086-4ffd-b5e6-1b1e5e7e062f","modelType":"service","modelNameVersionId":null,"modelName":"MSO Test Network","modelVersion":"1.0","modelCustomizationUuid":null,"modelVersionId":"aed5a5b7-20d3-44f7-90a3-ddbd16f14d1e","modelCustomizationId":null,"modelUuid":null,"modelInvariantUuid":null,"modelInstanceName":null},"requestInfo":{"billingAccountNumber":null,"callbackUrl":null,"correlator":null,"orderNumber":null,"productFamilyId":null,"orderVersion":null,"source":"VID","instanceName":"DEV-MTN6-3100-0927-1","suppressRollback":false,"requestorId":"xxxxxx"},"relatedInstanceList":null,"subscriberInfo":{"globalSubscriberId":"MSO_1610_dev","subscriberName":"MSO_1610_dev"},"cloudConfiguration":{"aicNodeClli":null,"tenantId":"19123c2924c648eb8e42a3c1f14b7682","lcpCloudRegionId":"mtn6"},"requestParameters":{"subscriptionServiceType":"MSO-dev-service-type","userParams":[{"name":"someUserParam","value":"someValue"}],"aLaCarte":true,"autoBuildVfModules":false,"cascadeDelete":false,"usePreload":true,"alaCarte":true},"project":null,"owningEntity":null,"platform":null,"lineOfBusiness":null}}}', null, 'CreateGenericALaCarteServiceInstance', '2017-09-28 12:45:52', null, null, null, null, null, 'mtn6', null, null, null, null, null, 'service', 'createInstance', 'b2f59173-b7e5-4e0f-8440-232fd601b865', 'DEV-MTN6-3100-0927-1', 'xxxxxx', null, null, null, null, 'http://localhost:8080/onap/so/infra/serviceInstantiation/v7/serviceInstances'), +('00173cc9-5ce2-4673-a810-f87fefb2829e', 'FAILED', 'Error parsing request. No valid instanceName is specified', '100', '2017-04-14 21:08:46', '2017-04-14 21:08:46', 'VID', null, null, null, null, 'a259ae7b7c3f493cb3d91f95a7c18149', null, null, '{"requestDetails":{"modelInfo":{"modelInvariantId":"ff6163d4-7214-459e-9f76-507b4eb00f51","modelType":"service","modelName":"ConstraintsSrvcVID","modelVersion":"2.0","modelVersionId":"722d256c-a374-4fba-a14f-a59b76bb7656"},"requestInfo":{"productFamilyId":"LRSI-OSPF","source":"VID","requestorId":"xxxxxx"},"subscriberInfo":{"globalSubscriberId":"a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb"},"cloudConfiguration":{"tenantId":"a259ae7b7c3f493cb3d91f95a7c18149","lcpCloudRegionId":"mtn16"},"requestParameters":{"subscriptionServiceType":"Mobility","userParams":[{"name":"neutronport6_name","value":"8"},{"name":"neutronnet5_network_name","value":"8"},{"name":"contrailv2vlansubinterface3_name","value":"false"}]}}}', null, 'APIH', '2016-12-22 19:00:28', null, null, null, null, null, 'mtn16', null, null, null, null, null, 'service', 'createInstance', null, null, null, null, null, null, null, 'http://localhost:8080/onap/so/infra/serviceInstantiation/v7/serviceInstances'), +('0017f68c-eb2d-45bb-b7c7-ec31b37dc349', 'UNLOCKED', null, '20', '2017-09-26 16:09:29', '2017-09-28 12:45:53', 'VID', null, null, null, null, null, null, null, '{"requestDetails":{"modelInfo":{"modelCustomizationName":null,"modelInvariantId":"1587cf0e-f12f-478d-8530-5c55ac578c39","modelType":"configuration","modelNameVersionId":null,"modelName":null,"modelVersion":null,"modelCustomizationUuid":null,"modelVersionId":"36a3a8ea-49a6-4ac8-b06c-89a545444455","modelCustomizationId":"68dc9a92-214c-11e7-93ae-92361f002671","modelUuid":null,"modelInvariantUuid":null,"modelInstanceName":null},"requestInfo":{"billingAccountNumber":null,"callbackUrl":null,"correlator":null,"orderNumber":null,"productFamilyId":null,"orderVersion":null,"source":"VID","instanceName":null,"suppressRollback":false,"requestorId":"xxxxxx"},"relatedInstanceList":[{"relatedInstance":{"instanceName":null,"instanceId":"9e15a443-af65-4f05-9000-47ae495e937d","modelInfo":{"modelCustomizationName":null,"modelInvariantId":"de19ae10-9a25-11e7-abc4-cec278b6b50a","modelType":"service","modelNameVersionId":null,"modelName":"MSOTADevInfra_Configuration_Service","modelVersion":"1.0","modelCustomizationUuid":null,"modelVersionId":"ee938612-9a25-11e7-abc4-cec278b6b50a","modelCustomizationId":null,"modelUuid":null,"modelInvariantUuid":null,"modelInstanceName":null},"instanceDirection":null}}],"subscriberInfo":null,"cloudConfiguration":{"aicNodeClli":null,"tenantId":null,"lcpCloudRegionId":"mtn6"},"requestParameters":{"subscriptionServiceType":null,"userParams":[],"aLaCarte":false,"autoBuildVfModules":false,"cascadeDelete":false,"usePreload":true,"alaCarte":false},"project":null,"owningEntity":null,"platform":null,"lineOfBusiness":null}}', null, 'APIH', '2017-09-26 16:09:29', null, null, null, null, null, 'mtn6', null, null, null, null, null, 'configuration', 'activateInstance', '9e15a443-af65-4f05-9000-47ae495e937d', null, 'xxxxxx', '26ef7f15-57bb-48df-8170-e59edc26234c', null, null, null, 'http://localhost:8080/onap/so/infra/serviceInstantiation/v7/serviceInstances'); insert into watchdog_distributionid_status(distribution_id, distribution_id_status, lock_version, create_time, modify_time) values ('1533c4bd-a3e3-493f-a16d-28c20614415e', '', 0, '2017-11-30 15:48:09', '2017-11-30 15:48:09'), @@ -31,11 +31,11 @@ insert into watchdog_service_mod_ver_id_lookup(distribution_id, service_model_ve insert into site_status(site_name, status, creation_timestamp) values ('testsite', 0, '2017-11-30 15:48:09'); -INSERT INTO requestdb.request_processing_data (ID, SO_REQUEST_ID, GROUPING_ID, NAME, VALUE, TAG) +INSERT INTO requestdb.request_processing_data (ID, SO_REQUEST_ID, GROUPING_ID, NAME, VALUE, TAG, IS_DATA_INTERNAL) VALUES -(1, '00032ab7-na18-42e5-965d-8ea592502018', '7d2e8c07-4d10-456d-bddc-37abf38ca714', 'requestAction', 'assign', 'pincFabricConfigRequest'), -(2, '00032ab7-na18-42e5-965d-8ea592502018', '7d2e8c07-4d10-456d-bddc-37abf38ca715', 'configurationId', '52234bc0-d6a6-41d4-a901-79015e4877e2', 'pincFabricConfigRequest'), -(3, '5ffbabd6-b793-4377-a1ab-082670fbc7ac', '5ffbabd6-b793-4377-a1ab-082670fbc7ac', 'configId', '52234bc0-d6a6-41d4-a901-79015e4877e2', 'pincFabricConfig'); +(1, '00032ab7-na18-42e5-965d-8ea592502018', '7d2e8c07-4d10-456d-bddc-37abf38ca714', 'requestAction', 'assign', 'pincFabricConfigRequest', 1), +(2, '00032ab7-na18-42e5-965d-8ea592502018', '7d2e8c07-4d10-456d-bddc-37abf38ca715', 'configurationId', '52234bc0-d6a6-41d4-a901-79015e4877e2', 'pincFabricConfigRequest', 0), +(3, '5ffbabd6-b793-4377-a1ab-082670fbc7ac', '5ffbabd6-b793-4377-a1ab-082670fbc7ac', 'configId', '52234bc0-d6a6-41d4-a901-79015e4877e2', 'pincFabricConfig', 1); INSERT INTO activate_operational_env_service_model_distribution_status (OPERATIONAL_ENV_ID, SERVICE_MODEL_VERSION_ID, REQUEST_ID,SERVICE_MOD_VER_FINAL_DISTR_STATUS,RECOVERY_ACTION,RETRY_COUNT_LEFT,WORKLOAD_CONTEXT, CREATE_TIME, MODIFY_TIME, VNF_OPERATIONAL_ENV_ID) VALUES diff --git a/adapters/mso-sdnc-adapter/pom.xml b/adapters/mso-sdnc-adapter/pom.xml index fc577a52e3..07c8ed5eab 100644 --- a/adapters/mso-sdnc-adapter/pom.xml +++ b/adapters/mso-sdnc-adapter/pom.xml @@ -42,6 +42,9 @@ <executions> <execution> <id>original</id> + <configuration> + <skip>false</skip> + </configuration> </execution> </executions> </plugin> diff --git a/adapters/mso-sdnc-adapter/src/main/java/org/onap/so/adapters/sdnc/CXFConfiguration.java b/adapters/mso-sdnc-adapter/src/main/java/org/onap/so/adapters/sdnc/CXFConfiguration.java index 6149f7ed25..dd1da98dd8 100644 --- a/adapters/mso-sdnc-adapter/src/main/java/org/onap/so/adapters/sdnc/CXFConfiguration.java +++ b/adapters/mso-sdnc-adapter/src/main/java/org/onap/so/adapters/sdnc/CXFConfiguration.java @@ -32,7 +32,7 @@ import org.apache.cxf.transport.servlet.CXFServlet; import org.onap.so.adapters.sdnc.sdncrest.SNIROResponse; import org.onap.so.logging.cxf.interceptor.SOAPLoggingInInterceptor; import org.onap.so.logging.cxf.interceptor.SOAPLoggingOutInterceptor; -import org.onap.so.logging.jaxrs.filter.JaxRsFilterLogging; +import org.onap.so.logging.jaxrs.filter.SOAuditLogContainerFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.annotation.Bean; @@ -51,7 +51,7 @@ public class CXFConfiguration { private Bus bus; @Autowired - private JaxRsFilterLogging jaxRsFilterLogging; + private SOAuditLogContainerFilter soAuditLogContainerFilter; @Autowired private SDNCAdapterPortType sdncAdapterPortImpl; @@ -70,7 +70,7 @@ public class CXFConfiguration { endpoint.setServiceBeans(Arrays.<Object>asList(sniroResponse)); endpoint.setAddress("/rest"); endpoint.setFeatures(Arrays.asList(createSwaggerFeature(), new LoggingFeature())); - endpoint.setProviders(Arrays.asList(new JacksonJsonProvider(mapper), jaxRsFilterLogging)); + endpoint.setProviders(Arrays.asList(new JacksonJsonProvider(mapper), soAuditLogContainerFilter)); return endpoint.create(); } diff --git a/adapters/mso-sdnc-adapter/src/main/java/org/onap/so/adapters/sdnc/SDNCAdapterApplication.java b/adapters/mso-sdnc-adapter/src/main/java/org/onap/so/adapters/sdnc/SDNCAdapterApplication.java index 55023088bc..55a05436f0 100644 --- a/adapters/mso-sdnc-adapter/src/main/java/org/onap/so/adapters/sdnc/SDNCAdapterApplication.java +++ b/adapters/mso-sdnc-adapter/src/main/java/org/onap/so/adapters/sdnc/SDNCAdapterApplication.java @@ -23,7 +23,9 @@ package org.onap.so.adapters.sdnc; import java.util.concurrent.Executor; -import org.onap.so.logging.jaxrs.filter.MDCTaskDecorator; +import org.onap.logging.filter.base.Constants; +import org.onap.logging.filter.spring.MDCTaskDecorator; +import org.onap.so.utils.Components; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -52,6 +54,7 @@ public class SDNCAdapterApplication { } public static void main(String[] args) { + System.setProperty(Constants.Property.PARTNER_NAME, Components.SDNC_ADAPTER.toString()); SpringApplication.run(SDNCAdapterApplication.class, args); System.getProperties().setProperty("server.name", "Springboot"); setLogsDir(); diff --git a/adapters/mso-sdnc-adapter/src/main/java/org/onap/so/adapters/sdnc/WebSecurityConfigImpl.java b/adapters/mso-sdnc-adapter/src/main/java/org/onap/so/adapters/sdnc/WebSecurityConfigImpl.java deleted file mode 100644 index 232381385f..0000000000 --- a/adapters/mso-sdnc-adapter/src/main/java/org/onap/so/adapters/sdnc/WebSecurityConfigImpl.java +++ /dev/null @@ -1,50 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * ONAP - SO - * ================================================================================ - * Copyright (C) 2017 - 2018 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Modifications Copyright (c) 2019 Samsung - * ================================================================================ - * 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 org.onap.so.adapters.sdnc; - -import org.onap.so.security.MSOSpringFirewall; -import org.onap.so.security.WebSecurityConfig; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.builders.WebSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.web.firewall.StrictHttpFirewall; -import org.springframework.util.StringUtils; - -@EnableWebSecurity -public class WebSecurityConfigImpl extends WebSecurityConfig { - - @Override - protected void configure(HttpSecurity http) throws Exception { - http.csrf().disable().authorizeRequests().antMatchers("/manage/health", "/manage/info", "/services").permitAll() - .antMatchers("/**").hasAnyRole(StringUtils.collectionToDelimitedString(getRoles(), ",")).and() - .httpBasic(); - } - - @Override - public void configure(WebSecurity web) throws Exception { - super.configure(web); - StrictHttpFirewall firewall = new MSOSpringFirewall(); - web.httpFirewall(firewall); - } - -} diff --git a/adapters/mso-sdnc-adapter/src/main/java/org/onap/so/adapters/sdnc/impl/SDNCRestClient.java b/adapters/mso-sdnc-adapter/src/main/java/org/onap/so/adapters/sdnc/impl/SDNCRestClient.java index 012a19f1a9..a8418ea901 100644 --- a/adapters/mso-sdnc-adapter/src/main/java/org/onap/so/adapters/sdnc/impl/SDNCRestClient.java +++ b/adapters/mso-sdnc-adapter/src/main/java/org/onap/so/adapters/sdnc/impl/SDNCRestClient.java @@ -178,7 +178,7 @@ public class SDNCRestClient { return (sdncResp); } catch (Exception e) { logger.error(LoggingAnchor.FOUR, MessageEnum.RA_EXCEPTION_COMMUNICATE_SDNC.toString(), "SDNC", - ErrorCode.BusinessProcesssError.getValue(), "Exception processing request to SDNC", e); + ErrorCode.BusinessProcessError.getValue(), "Exception processing request to SDNC", e); // default sdncResp.setRespCode(HttpURLConnection.HTTP_INTERNAL_ERROR); String respMsg = "Error processing request to SDNC. "; @@ -246,7 +246,7 @@ public class SDNCRestClient { } // is != null } catch (Exception e1) { logger.error(LoggingAnchor.FOUR, MessageEnum.RA_ERROR_GET_RESPONSE_SDNC.toString(), "SDNC", - ErrorCode.BusinessProcesssError.getValue(), "Exception while get SDNC response", e1); + ErrorCode.BusinessProcessError.getValue(), "Exception while get SDNC response", e1); } } // con != null @@ -312,7 +312,7 @@ public class SDNCRestClient { headers.put("Authorization", Collections.singletonList(basicAuth)); } catch (Exception e2) { logger.error(LoggingAnchor.FOUR, MessageEnum.RA_SET_CALLBACK_AUTH_EXC.toString(), CAMUNDA, - ErrorCode.BusinessProcesssError.getValue(), + ErrorCode.BusinessProcessError.getValue(), "Exception - Unable to set authorization in callback request", e2); } @@ -322,7 +322,7 @@ public class SDNCRestClient { } catch (Exception e) { error = "Error sending BpelCallback request" + e.getMessage(); - logger.error("Error {} - {} - {}", ErrorCode.BusinessProcesssError.getValue(), + logger.error("Error {} - {} - {}", ErrorCode.BusinessProcessError.getValue(), MessageEnum.RA_CALLBACK_BPEL_EXC.toString(), error, e); } logger.info(MessageEnum.RA_CALLBACK_BPEL_COMPLETE.name(), CAMUNDA); diff --git a/adapters/mso-sdnc-adapter/src/main/java/org/onap/so/adapters/sdnc/impl/Utils.java b/adapters/mso-sdnc-adapter/src/main/java/org/onap/so/adapters/sdnc/impl/Utils.java index 1c47a2d6b0..f710988886 100644 --- a/adapters/mso-sdnc-adapter/src/main/java/org/onap/so/adapters/sdnc/impl/Utils.java +++ b/adapters/mso-sdnc-adapter/src/main/java/org/onap/so/adapters/sdnc/impl/Utils.java @@ -99,7 +99,7 @@ public class Utils { } catch (Exception e) { logger.error(LoggingAnchor.FOUR, MessageEnum.RA_ERROR_CREATE_SDNC_REQUEST.toString(), "SDNC", - ErrorCode.BusinessProcesssError.getValue(), "Exception in genSdncReq", e); + ErrorCode.BusinessProcessError.getValue(), "Exception in genSdncReq", e); } return null; } diff --git a/adapters/mso-sdnc-adapter/src/main/java/org/onap/so/adapters/sdnc/sdncrest/BPRestCallback.java b/adapters/mso-sdnc-adapter/src/main/java/org/onap/so/adapters/sdnc/sdncrest/BPRestCallback.java index b50662a832..631be2f9ff 100644 --- a/adapters/mso-sdnc-adapter/src/main/java/org/onap/so/adapters/sdnc/sdncrest/BPRestCallback.java +++ b/adapters/mso-sdnc-adapter/src/main/java/org/onap/so/adapters/sdnc/sdncrest/BPRestCallback.java @@ -24,27 +24,30 @@ package org.onap.so.adapters.sdnc.sdncrest; +import java.net.URI; import javax.xml.bind.DatatypeConverter; -import org.onap.so.logger.LoggingAnchor; -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.util.EntityUtils; -import org.onap.logging.ref.slf4j.ONAPLogConstants; +import org.onap.logging.filter.spring.SpringClientPayloadFilter; import org.onap.so.adapters.sdnc.impl.Constants; import org.onap.so.logger.ErrorCode; +import org.onap.so.logger.LoggingAnchor; import org.onap.so.logger.MessageEnum; +import org.onap.so.logging.jaxrs.filter.SOSpringClientFilter; +import org.onap.so.utils.CryptoUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.onap.so.utils.CryptoUtils; -import org.slf4j.MDC; import org.springframework.core.env.Environment; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.BufferingClientHttpRequestFactory; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpStatusCodeException; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; /** * Sends asynchronous messages to the BPMN WorkflowMessage service. @@ -95,81 +98,72 @@ public class BPRestCallback { logger.info(LoggingAnchor.THREE, MessageEnum.RA_CALLBACK_BPEL.toString(), message == null ? "[no content]" : message, CAMUNDA); - - HttpPost method = null; - HttpResponse httpResponse = null; - try { int timeout = 60 * 1000; + RestTemplate restTemplate = setRestTemplate(timeout); - RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(timeout).setConnectTimeout(timeout) - .setConnectionRequestTimeout(timeout).build(); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); - HttpClient client = HttpClientBuilder.create().build(); - method = new HttpPost(url); - method.setConfig(requestConfig); - - if (message != null) { - method.setEntity(new StringEntity(message, ContentType.APPLICATION_JSON)); - } - - boolean error = false; - - try { - String userCredentials = CryptoUtils.decrypt(env.getProperty(Constants.BPEL_AUTH_PROP), - env.getProperty(Constants.ENCRYPTION_KEY_PROP)); - String authorization = "Basic " + DatatypeConverter.printBase64Binary(userCredentials.getBytes()); - method.setHeader("Authorization", authorization); - method.setHeader(ONAPLogConstants.Headers.REQUEST_ID, MDC.get(ONAPLogConstants.MDCs.REQUEST_ID)); - method.setHeader(ONAPLogConstants.Headers.INVOCATION_ID, MDC.get(ONAPLogConstants.MDCs.INVOCATION_ID)); - method.setHeader(ONAPLogConstants.Headers.PARTNER_NAME, "SO-SDNCAdapter"); - } catch (Exception e) { - logger.error(LoggingAnchor.FOUR, MessageEnum.RA_SET_CALLBACK_AUTH_EXC.toString(), CAMUNDA, - ErrorCode.BusinessProcesssError.getValue(), "Unable to set authorization in callback request", - e); - error = true; - } + boolean error = setAuthorizationHeader(headers); + HttpEntity<String> requestEntity = new HttpEntity<>(message, headers); if (!error) { - httpResponse = client.execute(method); - - @SuppressWarnings("unused") - String responseContent = null; - - if (httpResponse.getEntity() != null) { - responseContent = EntityUtils.toString(httpResponse.getEntity(), "UTF-8"); - } - - if (httpResponse.getStatusLine().getStatusCode() >= 300) { - String msg = "Received error response to callback request: " + httpResponse.getStatusLine(); - logger.error(LoggingAnchor.FOUR, MessageEnum.RA_CALLBACK_BPEL_EXC.toString(), CAMUNDA, - ErrorCode.BusinessProcesssError.getValue(), msg); - - } + postRequest(restTemplate, url, requestEntity); } + logger.info(LoggingAnchor.TWO, MessageEnum.RA_CALLBACK_BPEL_COMPLETE.toString(), CAMUNDA); return true; } catch (Exception e) { logger.error(LoggingAnchor.FOUR, MessageEnum.RA_CALLBACK_BPEL_EXC.toString(), CAMUNDA, - ErrorCode.BusinessProcesssError.getValue(), "Error sending callback request", e); + ErrorCode.BusinessProcessError.getValue(), "Error sending callback request", e); return false; - } finally { - if (httpResponse != null) { - try { - EntityUtils.consume(httpResponse.getEntity()); - httpResponse = null; - } catch (Exception e) { - logger.debug("Exception:", e); - } - } + } + } - if (method != null) { - try { - method.reset(); - } catch (Exception e) { - logger.debug("Exception:", e); - } - } - logger.info(LoggingAnchor.TWO, MessageEnum.RA_CALLBACK_BPEL_COMPLETE.toString(), CAMUNDA); + protected boolean setAuthorizationHeader(HttpHeaders headers) { + boolean error = false; + try { + String userCredentials = CryptoUtils.decrypt(env.getProperty(Constants.BPEL_AUTH_PROP), + env.getProperty(Constants.ENCRYPTION_KEY_PROP)); + String authorization = "Basic " + DatatypeConverter.printBase64Binary(userCredentials.getBytes()); + headers.set("Authorization", authorization); + } catch (Exception e) { + logger.error(LoggingAnchor.FOUR, MessageEnum.RA_SET_CALLBACK_AUTH_EXC.toString(), CAMUNDA, + ErrorCode.BusinessProcessError.getValue(), "Unable to set authorization in callback request", e); + error = true; + } + return error; + } + + private void postRequest(RestTemplate restTemplate, String url, HttpEntity<String> requestEntity) { + ResponseEntity<String> response = null; + try { + UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(url); + URI uri = builder.build(true).toUri(); + response = restTemplate.postForEntity(uri, requestEntity, String.class); + } catch (HttpStatusCodeException e) { + logResponseError(e.getStatusCode()); + } + if (response != null && response.getStatusCode().is3xxRedirection()) { + logResponseError(response.getStatusCode()); } } + + private void logResponseError(HttpStatus statusCode) { + String msg = "Received error response to callback request: " + statusCode; + logger.error(LoggingAnchor.FOUR, MessageEnum.RA_CALLBACK_BPEL_EXC.toString(), CAMUNDA, + ErrorCode.BusinessProcessError.getValue(), msg); + } + + protected RestTemplate setRestTemplate(int timeout) { + RestTemplate restTemplate = new RestTemplate(); + HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); + factory.setConnectionRequestTimeout(timeout); + factory.setReadTimeout(timeout); + factory.setConnectTimeout(timeout); + restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(factory)); + restTemplate.getInterceptors().add(new SOSpringClientFilter()); + restTemplate.getInterceptors().add((new SpringClientPayloadFilter())); + return restTemplate; + } } diff --git a/adapters/mso-sdnc-adapter/src/main/java/org/onap/so/adapters/sdnc/sdncrest/SDNCServiceRequestTask.java b/adapters/mso-sdnc-adapter/src/main/java/org/onap/so/adapters/sdnc/sdncrest/SDNCServiceRequestTask.java index 5697ed56a5..50c8a089df 100644 --- a/adapters/mso-sdnc-adapter/src/main/java/org/onap/so/adapters/sdnc/sdncrest/SDNCServiceRequestTask.java +++ b/adapters/mso-sdnc-adapter/src/main/java/org/onap/so/adapters/sdnc/sdncrest/SDNCServiceRequestTask.java @@ -185,7 +185,7 @@ public class SDNCServiceRequestTask { addTextChild(agnosticServiceInformation, "anydata", anydata); } catch (Exception e) { logger.error(LoggingAnchor.FOUR, MessageEnum.RA_ERROR_CREATE_SDNC_REQUEST.toString(), "SDNC", - ErrorCode.BusinessProcesssError.getValue(), "Exception in genSdncReq", e); + ErrorCode.BusinessProcessError.getValue(), "Exception in genSdncReq", e); return null; } diff --git a/adapters/mso-sdnc-adapter/src/main/resources/application-aaf.yaml b/adapters/mso-sdnc-adapter/src/main/resources/application-aaf.yaml new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/adapters/mso-sdnc-adapter/src/main/resources/application-aaf.yaml diff --git a/adapters/mso-sdnc-adapter/src/main/resources/application-basic.yaml b/adapters/mso-sdnc-adapter/src/main/resources/application-basic.yaml new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/adapters/mso-sdnc-adapter/src/main/resources/application-basic.yaml diff --git a/adapters/mso-sdnc-adapter/src/test/java/org/onap/so/adapters/sdnc/sdncrest/BPRestCallbackUnitTest.java b/adapters/mso-sdnc-adapter/src/test/java/org/onap/so/adapters/sdnc/sdncrest/BPRestCallbackUnitTest.java new file mode 100644 index 0000000000..09089890ab --- /dev/null +++ b/adapters/mso-sdnc-adapter/src/test/java/org/onap/so/adapters/sdnc/sdncrest/BPRestCallbackUnitTest.java @@ -0,0 +1,142 @@ +package org.onap.so.adapters.sdnc.sdncrest; + + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.when; +import java.io.IOException; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Paths; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnitRunner; +import org.onap.so.adapters.sdnc.impl.Constants; +import org.springframework.core.env.Environment; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.HttpServerErrorException; +import org.springframework.web.client.ResourceAccessException; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +@RunWith(MockitoJUnitRunner.class) +public class BPRestCallbackUnitTest { + @Mock + private Environment env; + + @Mock + private RestTemplate restTemplate; + + @Spy + @InjectMocks + private BPRestCallback bpRestCallback; + + private HttpEntity<String> requestEntity; + private String message; + private HttpHeaders headers; + private URI uri; + + @Before + public void setUp() throws IOException { + headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + message = input("BPRestCallbackRequest.json"); + requestEntity = new HttpEntity<>(message, headers); + UriComponentsBuilder builder = UriComponentsBuilder.fromUriString("http://localhost:8000/sdnc"); + uri = builder.build(true).toUri(); + } + + public String input(String JsonInput) throws IOException { + JsonInput = "src/test/resources/" + JsonInput; + return new String(Files.readAllBytes(Paths.get(JsonInput))); + } + + @Test + public void sendTest() throws IOException { + ResponseEntity<String> postResponse = new ResponseEntity<String>("response", HttpStatus.OK); + doReturn(restTemplate).when(bpRestCallback).setRestTemplate(60000); + doReturn(false).when(bpRestCallback).setAuthorizationHeader(headers); + when(restTemplate.postForEntity(uri, requestEntity, String.class)).thenReturn(postResponse); + boolean response = bpRestCallback.send("http://localhost:8000/sdnc", message); + assertTrue(response); + } + + @Test + public void sendNoAuthHeaderTest() throws IOException { + doReturn(true).when(bpRestCallback).setAuthorizationHeader(headers); + doReturn(restTemplate).when(bpRestCallback).setRestTemplate(60000); + boolean response = bpRestCallback.send("http://localhost:8000/sdnc", message); + assertTrue(response); + } + + @Test + public void sendErrorTest() throws IOException { + doReturn(false).when(bpRestCallback).setAuthorizationHeader(headers); + doReturn(restTemplate).when(bpRestCallback).setRestTemplate(60000); + when(restTemplate.postForEntity(uri, requestEntity, String.class)) + .thenThrow(new HttpServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR, null, null, null)); + boolean response = bpRestCallback.send("http://localhost:8000/sdnc", message); + assertTrue(response); + } + + @Test + public void sendResponse3xxTest() throws IOException { + ResponseEntity<String> postResponse = new ResponseEntity<String>("response", HttpStatus.MULTIPLE_CHOICES); + doReturn(false).when(bpRestCallback).setAuthorizationHeader(headers); + doReturn(restTemplate).when(bpRestCallback).setRestTemplate(60000); + when(restTemplate.postForEntity(uri, requestEntity, String.class)).thenReturn(postResponse); + boolean response = bpRestCallback.send("http://localhost:8000/sdnc", message); + assertTrue(response); + } + + @Test + public void sendResponseNullMessageTest() throws IOException { + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.setContentType(MediaType.APPLICATION_JSON); + HttpEntity<String> requestEntityNoMessage = new HttpEntity<>(null, httpHeaders); + ResponseEntity<String> postResponse = new ResponseEntity<String>("response", HttpStatus.OK); + doReturn(false).when(bpRestCallback).setAuthorizationHeader(httpHeaders); + doReturn(restTemplate).when(bpRestCallback).setRestTemplate(60000); + when(restTemplate.postForEntity(uri, requestEntityNoMessage, String.class)).thenReturn(postResponse); + boolean response = bpRestCallback.send("http://localhost:8000/sdnc", null); + assertTrue(response); + } + + @Test + public void postThrowsExceptionTest() throws IOException { + doReturn(false).when(bpRestCallback).setAuthorizationHeader(headers); + doReturn(restTemplate).when(bpRestCallback).setRestTemplate(60000); + when(restTemplate.postForEntity(uri, requestEntity, String.class)) + .thenThrow(new ResourceAccessException("ResourceAccessException")); + boolean response = bpRestCallback.send("http://localhost:8000/sdnc", message); + assertFalse(response); + } + + @Test + public void setAuthorizationHeaderTest() { + HttpHeaders authHeaders = new HttpHeaders(); + when(env.getProperty(Constants.BPEL_AUTH_PROP)) + .thenReturn("5E12ACACBD552A415E081E29F2C4772F9835792A51C766CCFDD7433DB5220B59969CB2798C"); + when(env.getProperty(Constants.ENCRYPTION_KEY_PROP)).thenReturn("07a7159d3bf51a0e53be7a8f89699be7"); + boolean result = bpRestCallback.setAuthorizationHeader(authHeaders); + assertFalse(result); + } + + @Test + public void setAuthorizationHeaderErrorTest() { + HttpHeaders authHeaders = new HttpHeaders(); + when(env.getProperty(Constants.BPEL_AUTH_PROP)).thenReturn("test"); + when(env.getProperty(Constants.ENCRYPTION_KEY_PROP)).thenReturn("test"); + boolean result = bpRestCallback.setAuthorizationHeader(authHeaders); + assertTrue(result); + } +} diff --git a/adapters/mso-sdnc-adapter/src/test/resources/BPRestCallbackRequest.json b/adapters/mso-sdnc-adapter/src/test/resources/BPRestCallbackRequest.json new file mode 100644 index 0000000000..21f3dab7e0 --- /dev/null +++ b/adapters/mso-sdnc-adapter/src/test/resources/BPRestCallbackRequest.json @@ -0,0 +1 @@ +{"SDNCServiceResponse":{"sdncRequestId":"b5b763aa-0d8a-4438-b900-83af45d21d10","responseCode":"200","ackFinalIndicator":"N"}}
\ No newline at end of file diff --git a/adapters/mso-ve-vnfm-adapter/pom.xml b/adapters/mso-ve-vnfm-adapter/pom.xml new file mode 100644 index 0000000000..d157466c67 --- /dev/null +++ b/adapters/mso-ve-vnfm-adapter/pom.xml @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-parent</artifactId> + <version>2.2.2.RELEASE</version> + </parent> + + <groupId>org.onap.so.adapters</groupId> + <artifactId>mso-ve-vnfm-adapter</artifactId> + <version>1.4.0-SNAPSHOT</version> + <packaging>jar</packaging> + + <name>mso-ve-vnfm-adapter</name> + <description>Ve-Vnfm (SOL002) Adapter</description> + + <properties> + <java.version>1.8</java.version> + <maven.compiler.source>${java.version}</maven.compiler.source> + <maven.compiler.target>${java.version}</maven.compiler.target> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + <dependencies> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-actuator</artifactId> + </dependency> + <dependency> + <groupId>org.onap.so.adapters</groupId> + <artifactId>mso-vnfm-adapter-ext-clients</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + </plugin> + </plugins> + </build> + +</project> diff --git a/adapters/mso-ve-vnfm-adapter/src/main/java/org/onap/so/adapters/vevnfm/Application.java b/adapters/mso-ve-vnfm-adapter/src/main/java/org/onap/so/adapters/vevnfm/Application.java new file mode 100644 index 0000000000..0e62a372b3 --- /dev/null +++ b/adapters/mso-ve-vnfm-adapter/src/main/java/org/onap/so/adapters/vevnfm/Application.java @@ -0,0 +1,31 @@ +/*- + * ============LICENSE_START======================================================= + * SO + * ================================================================================ + * Copyright (C) 2019 Samsung. All rights reserved. + * ================================================================================ + * 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 org.onap.so.adapters.vevnfm; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + public static void main(String... args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/adapters/mso-ve-vnfm-adapter/src/main/java/org/onap/so/adapters/vevnfm/controller/NotificationController.java b/adapters/mso-ve-vnfm-adapter/src/main/java/org/onap/so/adapters/vevnfm/controller/NotificationController.java new file mode 100644 index 0000000000..2e5a00ad02 --- /dev/null +++ b/adapters/mso-ve-vnfm-adapter/src/main/java/org/onap/so/adapters/vevnfm/controller/NotificationController.java @@ -0,0 +1,41 @@ +/*- + * ============LICENSE_START======================================================= + * SO + * ================================================================================ + * Copyright (C) 2019 Samsung. All rights reserved. + * ================================================================================ + * 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 org.onap.so.adapters.vevnfm.controller; + +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.VnfLcmOperationOccurrenceNotification; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class NotificationController { + + private static final Logger logger = LoggerFactory.getLogger(NotificationController.class); + + @PostMapping("${notification.url}") + public ResponseEntity receiveNotification(@RequestBody final VnfLcmOperationOccurrenceNotification notification) { + logger.info("Notification received {}", notification); + return ResponseEntity.ok().build(); + } +} diff --git a/adapters/mso-ve-vnfm-adapter/src/main/resources/application.yaml b/adapters/mso-ve-vnfm-adapter/src/main/resources/application.yaml new file mode 100644 index 0000000000..30b3955821 --- /dev/null +++ b/adapters/mso-ve-vnfm-adapter/src/main/resources/application.yaml @@ -0,0 +1,23 @@ +# +# Copyright © 2019 Samsung. +# All rights reserved. +# +# 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. + +notification: + url: /lcm/v1/vnf/instances/notifications + +spring: + http: + converters: + preferred-json-mapper: gson diff --git a/adapters/mso-ve-vnfm-adapter/src/test/java/org/onap/so/adapters/vevnfm/controller/NotificationControllerTest.java b/adapters/mso-ve-vnfm-adapter/src/test/java/org/onap/so/adapters/vevnfm/controller/NotificationControllerTest.java new file mode 100644 index 0000000000..d31c6f2ea5 --- /dev/null +++ b/adapters/mso-ve-vnfm-adapter/src/test/java/org/onap/so/adapters/vevnfm/controller/NotificationControllerTest.java @@ -0,0 +1,41 @@ +/*- + * ============LICENSE_START======================================================= + * SO + * ================================================================================ + * Copyright (C) 2019 Samsung. All rights reserved. + * ================================================================================ + * 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 org.onap.so.adapters.vevnfm.controller; + +import org.junit.Test; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.VnfLcmOperationOccurrenceNotification; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import static org.junit.Assert.assertEquals; + +public class NotificationControllerTest { + + private final NotificationController controller = new NotificationController(); + + @Test + public void testReceiveNotification() { + final VnfLcmOperationOccurrenceNotification notification + = new VnfLcmOperationOccurrenceNotification(); + final ResponseEntity response = controller.receiveNotification(notification); + assertEquals(HttpStatus.OK, response.getStatusCode()); + } +} diff --git a/adapters/mso-vfc-adapter/src/main/java/org/onap/so/adapters/vfc/CXFConfiguration.java b/adapters/mso-vfc-adapter/src/main/java/org/onap/so/adapters/vfc/CXFConfiguration.java index 5ea68f08a2..dd875c573e 100644 --- a/adapters/mso-vfc-adapter/src/main/java/org/onap/so/adapters/vfc/CXFConfiguration.java +++ b/adapters/mso-vfc-adapter/src/main/java/org/onap/so/adapters/vfc/CXFConfiguration.java @@ -28,7 +28,7 @@ import org.apache.cxf.jaxrs.JAXRSServerFactoryBean; import org.apache.cxf.jaxrs.swagger.Swagger2Feature; import org.apache.cxf.transport.servlet.CXFServlet; import org.onap.so.adapters.vfc.rest.VfcAdapterRest; -import org.onap.so.logging.jaxrs.filter.JaxRsFilterLogging; +import org.onap.so.logging.jaxrs.filter.SOAuditLogContainerFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.annotation.Bean; @@ -47,7 +47,7 @@ public class CXFConfiguration { private VfcAdapterRest vfcAdapterRest; @Autowired - private JaxRsFilterLogging jaxRsFilterLogging; + private SOAuditLogContainerFilter soAuditLogContainerFilter; @Autowired private ObjectMapper mapper; @@ -64,7 +64,7 @@ public class CXFConfiguration { endpoint.setServiceBeans(Arrays.<Object>asList(vfcAdapterRest)); endpoint.setAddress("/"); endpoint.setFeatures(Arrays.asList(createSwaggerFeature(), new LoggingFeature())); - endpoint.setProviders(Arrays.asList(new JacksonJsonProvider(mapper), jaxRsFilterLogging)); + endpoint.setProviders(Arrays.asList(new JacksonJsonProvider(mapper), soAuditLogContainerFilter)); return endpoint.create(); } diff --git a/adapters/mso-vfc-adapter/src/main/java/org/onap/so/adapters/vfc/WebSecurityConfigImpl.java b/adapters/mso-vfc-adapter/src/main/java/org/onap/so/adapters/vfc/WebSecurityConfigImpl.java deleted file mode 100644 index e94e34d87c..0000000000 --- a/adapters/mso-vfc-adapter/src/main/java/org/onap/so/adapters/vfc/WebSecurityConfigImpl.java +++ /dev/null @@ -1,50 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * ONAP - SO - * ================================================================================ - * Copyright (C) 2017 - 2018 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Modifications Copyright (c) 2019 Samsung - * ================================================================================ - * 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 org.onap.so.adapters.vfc; - -import org.onap.so.security.MSOSpringFirewall; -import org.onap.so.security.WebSecurityConfig; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.builders.WebSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.web.firewall.StrictHttpFirewall; -import org.springframework.util.StringUtils; - -@EnableWebSecurity -public class WebSecurityConfigImpl extends WebSecurityConfig { - - @Override - protected void configure(HttpSecurity http) throws Exception { - http.csrf().disable().authorizeRequests().antMatchers("/manage/health", "/manage/info", "/services").permitAll() - .antMatchers("/**").hasAnyRole(StringUtils.collectionToDelimitedString(getRoles(), ",")).and() - .httpBasic(); - } - - @Override - public void configure(WebSecurity web) throws Exception { - super.configure(web); - StrictHttpFirewall firewall = new MSOSpringFirewall(); - web.httpFirewall(firewall); - } - -} diff --git a/adapters/mso-vfc-adapter/src/main/java/org/onap/so/adapters/vfc/util/JsonUtil.java b/adapters/mso-vfc-adapter/src/main/java/org/onap/so/adapters/vfc/util/JsonUtil.java index e8b4cfd997..5b50f776cc 100644 --- a/adapters/mso-vfc-adapter/src/main/java/org/onap/so/adapters/vfc/util/JsonUtil.java +++ b/adapters/mso-vfc-adapter/src/main/java/org/onap/so/adapters/vfc/util/JsonUtil.java @@ -85,7 +85,7 @@ public class JsonUtil { return MAPPER.readValue(jsonstr, type); } catch (IOException e) { logger.error(LoggingAnchor.THREE, MessageEnum.RA_NS_EXC.toString(), - ErrorCode.BusinessProcesssError.getValue(), UNMARSHAL_FAIL_MSG, e); + ErrorCode.BusinessProcessError.getValue(), UNMARSHAL_FAIL_MSG, e); throw new ApplicationException(HttpCode.BAD_REQUEST, UNMARSHAL_FAIL_MSG); } } @@ -103,7 +103,7 @@ public class JsonUtil { return MAPPER.readValue(jsonstr, type); } catch (IOException e) { logger.error(LoggingAnchor.THREE, MessageEnum.RA_NS_EXC.toString(), - ErrorCode.BusinessProcesssError.getValue(), UNMARSHAL_FAIL_MSG, e); + ErrorCode.BusinessProcessError.getValue(), UNMARSHAL_FAIL_MSG, e); throw new ApplicationException(HttpCode.BAD_REQUEST, UNMARSHAL_FAIL_MSG); } } @@ -120,7 +120,7 @@ public class JsonUtil { return MAPPER.writeValueAsString(srcObj); } catch (IOException e) { logger.error(LoggingAnchor.THREE, MessageEnum.RA_NS_EXC.toString(), - ErrorCode.BusinessProcesssError.getValue(), "fail to marshal json", e); + ErrorCode.BusinessProcessError.getValue(), "fail to marshal json", e); throw new ApplicationException(HttpCode.BAD_REQUEST, "srcObj marshal failed!"); } } diff --git a/adapters/mso-vfc-adapter/src/main/resources/application-aaf.yaml b/adapters/mso-vfc-adapter/src/main/resources/application-aaf.yaml new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/adapters/mso-vfc-adapter/src/main/resources/application-aaf.yaml diff --git a/adapters/mso-vfc-adapter/src/main/resources/application-basic.yaml b/adapters/mso-vfc-adapter/src/main/resources/application-basic.yaml new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/adapters/mso-vfc-adapter/src/main/resources/application-basic.yaml diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-adapter-api/pom.xml b/adapters/mso-vnfm-adapter/mso-vnfm-adapter-api/pom.xml index 9d9e33a524..e874c4b8b3 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-adapter-api/pom.xml +++ b/adapters/mso-vnfm-adapter/mso-vnfm-adapter-api/pom.xml @@ -15,6 +15,8 @@ <threetenbp-version>1.3.5</threetenbp-version> <oltu-version>1.0.1</oltu-version> <swagger-core-version>1.5.15</swagger-core-version> + <okhttp3-version>3.14.0</okhttp3-version> + <okhttp-version>2.7.5</okhttp-version> </properties> <name>mso-vnfm-adapter-api</name> <description>MSO VNFM adapter API</description> @@ -47,6 +49,27 @@ </configOptions> </configuration> </execution> + + <execution> + <id>etsicatalog-notification-api</id> + <goals> + <goal>generate</goal> + </goals> + <configuration> + <inputSpec>${basedir}/src/main/resources/ETSI-Catalog-Notification-API.json</inputSpec> + <language>java</language> + <library>okhttp-gson</library> + <output>${project.build.directory}/generated-sources/etsicatalog/notification</output> + <apiPackage>org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.notification.api</apiPackage> + <modelPackage>org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.notification.model</modelPackage> + <configOptions> + <sourceFolder>src/gen/java/main</sourceFolder> + <withXml>true</withXml> + <useRxJava2>true</useRxJava2> + <serializableModel>true</serializableModel> + </configOptions> + </configuration> + </execution> </executions> </plugin> </plugins> @@ -105,5 +128,34 @@ <artifactId>okio</artifactId> <version>1.13.0</version> </dependency> + <dependency> + <groupId>com.squareup.okhttp3</groupId> + <artifactId>okhttp</artifactId> + <version>${okhttp3-version}</version> + </dependency> + <dependency> + <groupId>com.squareup.okhttp3</groupId> + <artifactId>logging-interceptor</artifactId> + <version>${okhttp3-version}</version> + </dependency> + <dependency> + <groupId>com.squareup.okhttp</groupId> + <artifactId>logging-interceptor</artifactId> + <version>${okhttp-version}</version> + </dependency> + <dependency> + <groupId>com.squareup.okhttp</groupId> + <artifactId>okhttp</artifactId> + <version>${okhttp-version}</version> + </dependency> + <dependency> + <groupId>com.squareup.okhttp</groupId> + <artifactId>logging-interceptor</artifactId> + <version>${okhttp-version}</version> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + </dependency> </dependencies> </project> diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-adapter-api/src/main/resources/ETSI-Catalog-Notification-API.json b/adapters/mso-vnfm-adapter/mso-vnfm-adapter-api/src/main/resources/ETSI-Catalog-Notification-API.json new file mode 100644 index 0000000000..6f9b2c3bbe --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-adapter-api/src/main/resources/ETSI-Catalog-Notification-API.json @@ -0,0 +1,230 @@ +{ + "swagger": "2.0", + "info": { + "title": "Modeling etsicatalog API", + "description": "\n\nThe `swagger-ui` view can be found [here](/api/catalog/v1/swagger).\nThe `ReDoc` view can be found [here](/api/catalog/v1/redoc).\nThe swagger YAML document can be found [here](/api/catalog/v1/swagger.yaml).\nThe swagger JSON document can be found [here](/api/catalog/v1/swagger.json).", + "version": "v1" + }, + "host": "127.0.0.1:8000", + "schemes": ["http"], + "basePath": "/", + "consumes": ["application/json"], + "produces": ["application/json"], + "securityDefinitions": { + "Basic": { + "type": "basic" + } + }, + "security": [{ + "Basic": [] + }], + "paths": { + "/URI-is-provided-by-the-client-when-creating-the-subscription-VnfPackageChangeNotification": { + "get": { + "operationId": "URI-is-provided-by-the-client-when-creating-the-subscription-VnfPackageChangeNotification_list", + "description": "", + "parameters": [], + "responses": { + "204": { + "description": "" + }, + "500": { + "description": "error message", + "schema": { + "type": "string" + } + } + }, + "tags": ["VNF Package Management interface"] + }, + "post": { + "operationId": "URI-is-provided-by-the-client-when-creating-the-subscription-VnfPackageChangeNotification_create", + "description": "", + "parameters": [{ + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/PkgChangeNotification" + } + }], + "responses": { + "204": { + "description": "" + } + }, + "tags": ["VNF Package Management interface"] + }, + "parameters": [] + }, + "/URI-is-provided-by-the-client-when-creating-the-subscription-VnfPackageOnboardingNotification": { + "get": { + "operationId": "URI-is-provided-by-the-client-when-creating-the-subscription-VnfPackageOnboardingNotification_list", + "description": "", + "parameters": [], + "responses": { + "204": { + "description": "" + }, + "500": { + "description": "error message", + "schema": { + "type": "string" + } + } + }, + "tags": ["VNF Package Management interface"] + }, + "post": { + "operationId": "URI-is-provided-by-the-client-when-creating-the-subscription-VnfPackageOnboardingNotification_create", + "description": "", + "parameters": [{ + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/PkgOnboardingNotification" + } + }], + "responses": { + "204": { + "description": "" + } + }, + "tags": ["VNF Package Management interface"] + }, + "parameters": [] + } + }, + "definitions": { + "NOTIFICATION_LINKSERIALIZER": { + "title": "Vnfpackage", + "description": "Link to the resource representing the VNF package to which the notified change applies.", + "required": ["href"], + "type": "object", + "properties": { + "href": { + "title": "Href", + "description": "URI of the referenced resource.", + "type": "string", + "minLength": 1 + } + } + }, + "PkgmLinks": { + "title": " links", + "description": "Links to resources related to this resource.", + "type": "object", + "properties": { + "vnfPackage": { + "$ref": "#/definitions/NOTIFICATION_LINKSERIALIZER" + }, + "subscription": { + "$ref": "#/definitions/NOTIFICATION_LINKSERIALIZER" + } + } + }, + "PkgChangeNotification": { + "required": ["id", "notificationType", "timeStamp", "subscriptionId", "vnfPkgId", "changeType", "vnfdId", "_links"], + "type": "object", + "properties": { + "id": { + "title": "Id", + "description": "Identifier of this notification.", + "type": "string", + "minLength": 1 + }, + "notificationType": { + "title": "Notificationtype", + "description": "Discriminator for the different notification types.", + "type": "string", + "enum": ["VnfPackageChangeNotification"] + }, + "timeStamp": { + "title": "Timestamp", + "description": "Date-time of the generation of the notification.", + "type": "string", + "format": "date-time" + }, + "subscriptionId": { + "title": "Subscriptionid", + "description": "Identifier of the subscription that this notification relates to.", + "type": "string", + "minLength": 1 + }, + "vnfPkgId": { + "title": "Vnfpkgid", + "description": "Identifier of the VNF package.", + "type": "string", + "format": "uuid" + }, + "changeType": { + "title": "Changetype", + "description": "The type of change of the VNF package.", + "type": "string", + "enum": ["OP_STATE_CHANGE", "PKG_DELETE"] + }, + "operationalState": { + "title": "Operationalstate", + "description": "New operational state of the VNF package.", + "type": "string", + "enum": ["ENABLED", "DISABLED"] + }, + "vnfdId": { + "title": "Vnfdid", + "description": "This identifier, which is managed by the VNF provider, identifies the VNF package and the VNFD in a globally unique way.", + "type": "string", + "minLength": 1 + }, + "_links": { + "$ref": "#/definitions/PkgmLinks" + } + } + }, + "PkgOnboardingNotification": { + "required": ["id", "notificationType", "subscriptionId", "timeStamp", "vnfPkgId", "vnfdId", "_links"], + "type": "object", + "properties": { + "id": { + "title": "Id", + "description": "Identifier of this notification.", + "type": "string", + "minLength": 1 + }, + "notificationType": { + "title": "Notificationtype", + "description": "Discriminator for the different notification types.", + "type": "string", + "enum": ["VnfPackageOnboardingNotification"] + }, + "subscriptionId": { + "title": "Subscriptionid", + "description": "Identifier of the subscription that this notification relates to.", + "type": "string", + "minLength": 1 + }, + "timeStamp": { + "title": "Timestamp", + "description": "Date-time of the generation of the notification.", + "type": "string", + "format": "date-time" + }, + "vnfPkgId": { + "title": "Vnfpkgid", + "description": "Identifier of the VNF package.", + "type": "string", + "format": "uuid" + }, + "vnfdId": { + "title": "Vnfdid", + "description": "This identifier, which is managed by the VNF provider, identifies the VNF package and the VNFD in a globally unique way.", + "type": "string", + "format": "uuid" + }, + "_links": { + "$ref": "#/definitions/PkgmLinks" + } + } + } + } +}
\ No newline at end of file diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-adapter-ext-clients/pom.xml b/adapters/mso-vnfm-adapter/mso-vnfm-adapter-ext-clients/pom.xml index 91478e1f8e..8e2cfd2be4 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-adapter-ext-clients/pom.xml +++ b/adapters/mso-vnfm-adapter/mso-vnfm-adapter-ext-clients/pom.xml @@ -75,8 +75,7 @@ <goal>generate</goal> </goals> <configuration> - <inputSpec>${basedir}/src/main/resources/SOL003-VNFLifecycleOperationGranting-API.json - </inputSpec> + <inputSpec>${basedir}/src/main/resources/SOL003-VNFLifecycleOperationGranting-API.json</inputSpec> <language>java</language> <library>okhttp-gson</library> <output>${project.build.directory}/generated-sources/sol003-vnf-grant</output> @@ -91,6 +90,46 @@ </configOptions> </configuration> </execution> + <execution> + <id>sol003-vnf-packagemanagement-api</id> + <goals> + <goal>generate</goal> + </goals> + <configuration> + <inputSpec>${basedir}/src/main/resources/SOL003-VNFPackageManagement-API.json</inputSpec> + <language>java</language> + <library>okhttp-gson</library> + <output>${project.build.directory}/generated-sources/sol003-vnf-packagemanagement</output> + <apiPackage>org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.api</apiPackage> + <modelPackage>org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model</modelPackage> + <configOptions> + <sourceFolder>src/gen/java/main</sourceFolder> + <withXml>true</withXml> + <useRxJava2>true</useRxJava2> + <serializableModel>true</serializableModel> + </configOptions> + </configuration> + </execution> + <execution> + <id>etsicatalog-api</id> + <goals> + <goal>generate</goal> + </goals> + <configuration> + <inputSpec>${basedir}/src/main/resources/ETSI-Catalog-API.json</inputSpec> + <language>java</language> + <library>okhttp-gson</library> + <output>${project.build.directory}/generated-sources/etsicatalog</output> + <apiPackage>org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.api</apiPackage> + <modelPackage>org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.model</modelPackage> + <configOptions> + <sourceFolder>src/gen/java/main</sourceFolder> + <withXml>true</withXml> + <useRxJava2>true</useRxJava2> + <serializableModel>true</serializableModel> + </configOptions> + </configuration> + </execution> </executions> </plugin> </plugins> diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-adapter-ext-clients/src/main/resources/ETSI-Catalog-API.json b/adapters/mso-vnfm-adapter/mso-vnfm-adapter-ext-clients/src/main/resources/ETSI-Catalog-API.json new file mode 100644 index 0000000000..efd427009d --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-adapter-ext-clients/src/main/resources/ETSI-Catalog-API.json @@ -0,0 +1,3117 @@ +{ + "swagger": "2.0", + "info": { + "title": "Modeling etsicatalog API", + "description": "\n\nThe `swagger-ui` view can be found [here](/api/catalog/v1/swagger).\nThe `ReDoc` view can be found [here](/api/catalog/v1/redoc).\nThe swagger YAML document can be found [here](/api/catalog/v1/swagger.yaml).\nThe swagger JSON document can be found [here](/api/catalog/v1/swagger.json).", + "version": "v1" + }, + "host": "127.0.0.1:8000", + "schemes": ["http"], + "basePath": "/", + "consumes": ["application/json"], + "produces": ["application/json"], + "securityDefinitions": { + "Basic": { + "type": "basic" + } + }, + "security": [{ + "Basic": [] + }], + "paths": { + "/api/catalog/v1/callback_sample": { + "get": { + "operationId": "api_catalog_v1_callback_sample_list", + "description": "Callback Sample.", + "parameters": [], + "responses": { + "200": { + "description": "" + } + }, + "tags": ["Sample interface"] + }, + "parameters": [] + }, + "/api/catalog/v1/health_check": { + "get": { + "operationId": "api_catalog_v1_health_check_list", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "Active" + } + }, + "tags": ["Health Check interface"] + }, + "parameters": [] + }, + "/api/catalog/v1/jobs/{job_id}": { + "get": { + "operationId": "api_catalog_v1_jobs_read", + "description": "Get job status", + "parameters": [{ + "name": "job_id", + "in": "query", + "description": "job id", + "type": "string" + }, { + "name": "responseId", + "in": "query", + "description": "response id", + "type": "string" + }], + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/GetJobResponse" + } + }, + "500": { + "description": "", + "schema": { + "$ref": "#/definitions/PostJobResponseResult" + } + } + }, + "tags": ["Catalog interface"] + }, + "post": { + "operationId": "api_catalog_v1_jobs_create", + "description": "Update job status", + "parameters": [{ + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/PostJobRequest" + } + }, { + "name": "job_id", + "in": "query", + "description": "job id", + "type": "string" + }], + "responses": { + "202": { + "description": "", + "schema": { + "$ref": "#/definitions/PostJobResponseResult" + } + }, + "500": { + "description": "", + "schema": { + "$ref": "#/definitions/PostJobResponseResult" + } + } + }, + "tags": ["Catalog interface"] + }, + "parameters": [{ + "name": "job_id", + "in": "path", + "required": true, + "type": "string" + }] + }, + "/api/catalog/v1/mandb/{modelName}": { + "get": { + "operationId": "api_catalog_v1_mandb_read", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "" + } + }, + "tags": ["Sample interface"] + }, + "delete": { + "operationId": "api_catalog_v1_mandb_delete", + "description": "", + "parameters": [], + "responses": { + "204": { + "description": "" + } + }, + "tags": ["Sample interface"] + }, + "parameters": [{ + "name": "modelName", + "in": "path", + "required": true, + "type": "string" + }] + }, + "/api/catalog/v1/nspackages": { + "get": { + "operationId": "api_catalog_v1_nspackages_list", + "description": "Query NS packages", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/NsPackage" + } + } + }, + "500": { + "description": "", + "schema": { + "$ref": "#/definitions/InternalErrorRequest" + } + } + }, + "tags": ["Catalog interface"] + }, + "post": { + "operationId": "api_catalog_v1_nspackages_create", + "description": "On distribute NS package", + "parameters": [{ + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/NsPackageDistributeRequest" + } + }], + "responses": { + "202": { + "description": "", + "schema": { + "$ref": "#/definitions/NsPackageDistributeResponse" + } + }, + "500": { + "description": "", + "schema": { + "$ref": "#/definitions/InternalErrorRequest" + } + } + }, + "tags": ["Catalog interface"] + }, + "parameters": [] + }, + "/api/catalog/v1/nspackages/{csarId}": { + "get": { + "operationId": "api_catalog_v1_nspackages_read", + "description": "Query one NS package", + "parameters": [{ + "name": "csarId", + "in": "query", + "description": "csarId", + "type": "string" + }], + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/NsPackage" + } + }, + "500": { + "description": "error message", + "schema": { + "type": "string" + } + } + }, + "tags": ["Catalog interface"] + }, + "delete": { + "operationId": "api_catalog_v1_nspackages_delete", + "description": "Delete one NS package", + "parameters": [{ + "name": "csarId", + "in": "query", + "description": "csarId", + "type": "string" + }], + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/NsPackageDistributeResponse" + } + }, + "500": { + "description": "error message", + "schema": { + "type": "string" + } + } + }, + "tags": ["Catalog interface"] + }, + "parameters": [{ + "name": "csarId", + "in": "path", + "required": true, + "type": "string" + }] + }, + "/api/catalog/v1/service_packages": { + "get": { + "operationId": "api_catalog_v1_service_packages_list", + "description": "Query Service packages", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/ServicePackage" + } + } + }, + "500": { + "description": "", + "schema": { + "$ref": "#/definitions/InternalErrorRequest" + } + } + }, + "tags": ["Catalog interface"] + }, + "post": { + "operationId": "api_catalog_v1_service_packages_create", + "description": "On distribute Service package", + "parameters": [{ + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/ServicePackageDistributeRequest" + } + }], + "responses": { + "202": { + "description": "" + }, + "400": { + "description": "", + "schema": { + "$ref": "#/definitions/InternalErrorRequest" + } + }, + "500": { + "description": "", + "schema": { + "$ref": "#/definitions/InternalErrorRequest" + } + } + }, + "tags": ["Catalog interface"] + }, + "parameters": [] + }, + "/api/catalog/v1/service_packages/{csarId}": { + "get": { + "operationId": "api_catalog_v1_service_packages_read", + "description": "Query one Service package", + "parameters": [{ + "name": "csarId", + "in": "query", + "description": "csarId", + "type": "string" + }], + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/ServicePackage" + } + }, + "404": { + "description": "", + "schema": { + "$ref": "#/definitions/InternalErrorRequest" + } + }, + "500": { + "description": "", + "schema": { + "$ref": "#/definitions/InternalErrorRequest" + } + } + }, + "tags": ["Catalog interface"] + }, + "delete": { + "operationId": "api_catalog_v1_service_packages_delete", + "description": "Delete one Service package", + "parameters": [{ + "name": "csarId", + "in": "query", + "description": "csarId", + "type": "string" + }], + "responses": { + "204": { + "description": "" + }, + "404": { + "description": "", + "schema": { + "$ref": "#/definitions/InternalErrorRequest" + } + }, + "500": { + "description": "", + "schema": { + "$ref": "#/definitions/InternalErrorRequest" + } + } + }, + "tags": ["Catalog interface"] + }, + "parameters": [{ + "name": "csarId", + "in": "path", + "required": true, + "type": "string" + }] + }, + "/api/catalog/v1/vnfpackages": { + "get": { + "operationId": "api_catalog_v1_vnfpackages_list", + "description": "Query Nf packages", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/NfPackage" + } + } + }, + "500": { + "description": "", + "schema": { + "$ref": "#/definitions/InternalErrorRequest" + } + } + }, + "tags": ["Catalog interface"] + }, + "post": { + "operationId": "api_catalog_v1_vnfpackages_create", + "description": "On distribute Nf package", + "parameters": [{ + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/NfPackageDistributeRequest" + } + }], + "responses": { + "202": { + "description": "", + "schema": { + "$ref": "#/definitions/PostJobResponse" + } + }, + "500": { + "description": "", + "schema": { + "$ref": "#/definitions/InternalErrorRequest" + } + } + }, + "tags": ["Catalog interface"] + }, + "parameters": [] + }, + "/api/catalog/v1/vnfpackages/{csarId}": { + "get": { + "operationId": "api_catalog_v1_vnfpackages_read", + "description": "Query one Nf package", + "parameters": [{ + "name": "csarId", + "in": "query", + "description": "csarId", + "type": "string" + }], + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/NfPackage" + } + }, + "500": { + "description": "error message", + "schema": { + "type": "string" + } + } + }, + "tags": ["Catalog interface"] + }, + "delete": { + "operationId": "api_catalog_v1_vnfpackages_delete", + "description": "Delete one Nf package", + "parameters": [{ + "name": "csarId", + "in": "query", + "description": "csarId", + "type": "string" + }], + "responses": { + "202": { + "description": "", + "schema": { + "$ref": "#/definitions/PostJobResponse" + } + }, + "500": { + "description": "error message", + "schema": { + "type": "string" + } + } + }, + "tags": ["Catalog interface"] + }, + "parameters": [{ + "name": "csarId", + "in": "path", + "required": true, + "type": "string" + }] + }, + "/api/nsd/v1/health_check": { + "get": { + "operationId": "api_nsd_v1_health_check_list", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "Active" + } + }, + "tags": ["Health Check interface"] + }, + "parameters": [] + }, + "/api/nsd/v1/ns_descriptors": { + "get": { + "operationId": "api_nsd_v1_ns_descriptors_list", + "description": "Query multiple NSDs", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/NsdInfo" + } + } + }, + "500": { + "description": "Internal error" + } + }, + "tags": ["NSD Management interface"] + }, + "post": { + "operationId": "api_nsd_v1_ns_descriptors_create", + "description": "Create a NSD", + "parameters": [{ + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/CreateNsdInfoRequest" + } + }], + "responses": { + "201": { + "description": "", + "schema": { + "$ref": "#/definitions/NsdInfo" + } + }, + "500": { + "description": "Internal error" + } + }, + "tags": ["NSD Management interface"] + }, + "parameters": [] + }, + "/api/nsd/v1/ns_descriptors/{nsdInfoId}": { + "get": { + "operationId": "api_nsd_v1_ns_descriptors_read", + "description": "Query a NSD", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/NsdInfo" + } + }, + "404": { + "description": "NSDs do not exist" + }, + "500": { + "description": "Internal error" + } + }, + "tags": ["NSD Management interface"] + }, + "delete": { + "operationId": "api_nsd_v1_ns_descriptors_delete", + "description": "Delete a NSD", + "parameters": [], + "responses": { + "204": { + "description": "No content" + }, + "500": { + "description": "Internal error" + } + }, + "tags": ["NSD Management interface"] + }, + "parameters": [{ + "name": "nsdInfoId", + "in": "path", + "required": true, + "type": "string" + }] + }, + "/api/nsd/v1/ns_descriptors/{nsdInfoId}/nsd_content": { + "get": { + "operationId": "api_nsd_v1_ns_descriptors_nsd_content_list", + "description": "Download NSD content", + "parameters": [], + "responses": { + "204": { + "description": "No content" + }, + "404": { + "description": "NSD does not exist." + }, + "500": { + "description": "Internal error" + } + }, + "tags": ["NSD Management interface"] + }, + "put": { + "operationId": "api_nsd_v1_ns_descriptors_nsd_content_update", + "description": "Upload NSD content", + "parameters": [], + "responses": { + "204": { + "description": "PNFD file" + }, + "500": { + "description": "Internal error" + } + }, + "tags": ["NSD Management interface"] + }, + "parameters": [{ + "name": "nsdInfoId", + "in": "path", + "required": true, + "type": "string" + }] + }, + "/api/nsd/v1/pnf_descriptors": { + "get": { + "operationId": "api_nsd_v1_pnf_descriptors_list", + "description": "Query multiple PNFDs", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/PnfdInfo" + } + } + }, + "500": { + "description": "", + "schema": { + "$ref": "#/definitions/SUBSCRIPTION_ProblemDetailsSerializer" + } + } + }, + "tags": ["NSD Management interface"] + }, + "post": { + "operationId": "api_nsd_v1_pnf_descriptors_create", + "description": "Create a PNFD", + "parameters": [{ + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/CreatePnfdInfoRequest" + } + }], + "responses": { + "201": { + "description": "", + "schema": { + "$ref": "#/definitions/PnfdInfo" + } + }, + "500": { + "description": "", + "schema": { + "$ref": "#/definitions/SUBSCRIPTION_ProblemDetailsSerializer" + } + } + }, + "tags": ["NSD Management interface"] + }, + "parameters": [] + }, + "/api/nsd/v1/pnf_descriptors/{pnfdInfoId}": { + "get": { + "operationId": "api_nsd_v1_pnf_descriptors_read", + "description": "Query a PNFD", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/PnfdInfo" + } + }, + "404": { + "description": "", + "schema": { + "$ref": "#/definitions/SUBSCRIPTION_ProblemDetailsSerializer" + } + }, + "500": { + "description": "", + "schema": { + "$ref": "#/definitions/SUBSCRIPTION_ProblemDetailsSerializer" + } + } + }, + "tags": ["NSD Management interface"] + }, + "delete": { + "operationId": "api_nsd_v1_pnf_descriptors_delete", + "description": "Delete a PNFD", + "parameters": [], + "responses": { + "204": { + "description": "No content" + }, + "500": { + "description": "", + "schema": { + "$ref": "#/definitions/SUBSCRIPTION_ProblemDetailsSerializer" + } + } + }, + "tags": ["NSD Management interface"] + }, + "parameters": [{ + "name": "pnfdInfoId", + "in": "path", + "required": true, + "type": "string" + }] + }, + "/api/nsd/v1/pnf_descriptors/{pnfdInfoId}/pnfd_content": { + "get": { + "operationId": "Fetch PNFD content", + "description": "Fetch PNFD content", + "parameters": [], + "responses": { + "200": { + "description": "PNFD file", + "schema": { + "type": "string", + "format": "binary" + } + }, + "404": { + "description": "", + "schema": { + "$ref": "#/definitions/SUBSCRIPTION_ProblemDetailsSerializer" + } + }, + "500": { + "description": "", + "schema": { + "$ref": "#/definitions/SUBSCRIPTION_ProblemDetailsSerializer" + } + } + }, + "produces": ["application/octet-stream", "application/json"], + "tags": ["NSD Management interface"] + }, + "put": { + "operationId": "api_nsd_v1_pnf_descriptors_pnfd_content_update", + "description": "Upload PNFD content", + "parameters": [], + "responses": { + "204": { + "description": "No content" + }, + "500": { + "description": "", + "schema": { + "$ref": "#/definitions/SUBSCRIPTION_ProblemDetailsSerializer" + } + } + }, + "tags": ["NSD Management interface"] + }, + "parameters": [{ + "name": "pnfdInfoId", + "in": "path", + "required": true, + "type": "string" + }] + }, + "/api/nsd/v1/subscriptions": { + "get": { + "operationId": "api_nsd_v1_subscriptions_list", + "description": "Query subscriptions for Nsd Management", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/NsdmSubscription" + } + } + }, + "400": { + "description": "", + "schema": { + "$ref": "#/definitions/SUBSCRIPTION_ProblemDetailsSerializer" + } + }, + "404": { + "description": "", + "schema": { + "$ref": "#/definitions/SUBSCRIPTION_ProblemDetailsSerializer" + } + }, + "500": { + "description": "", + "schema": { + "$ref": "#/definitions/SUBSCRIPTION_ProblemDetailsSerializer" + } + } + }, + "tags": ["NSD Management interface"] + }, + "post": { + "operationId": "api_nsd_v1_subscriptions_create", + "description": "Create Subscription for NSD Management", + "parameters": [{ + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/NsdmSubscriptionRequest" + } + }], + "responses": { + "201": { + "description": "", + "schema": { + "$ref": "#/definitions/NsdmSubscription" + } + }, + "303": { + "description": "", + "schema": { + "$ref": "#/definitions/SUBSCRIPTION_ProblemDetailsSerializer" + } + }, + "400": { + "description": "", + "schema": { + "$ref": "#/definitions/SUBSCRIPTION_ProblemDetailsSerializer" + } + }, + "500": { + "description": "", + "schema": { + "$ref": "#/definitions/SUBSCRIPTION_ProblemDetailsSerializer" + } + } + }, + "tags": ["NSD Management interface"] + }, + "parameters": [] + }, + "/api/nsd/v1/subscriptions/{subscriptionId}": { + "get": { + "operationId": "api_nsd_v1_subscriptions_read", + "description": "Query subscriptions for Nsd Management", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/NsdmSubscription" + } + }, + "400": { + "description": "", + "schema": { + "$ref": "#/definitions/SUBSCRIPTION_ProblemDetailsSerializer" + } + }, + "404": { + "description": "", + "schema": { + "$ref": "#/definitions/SUBSCRIPTION_ProblemDetailsSerializer" + } + }, + "500": { + "description": "", + "schema": { + "$ref": "#/definitions/SUBSCRIPTION_ProblemDetailsSerializer" + } + } + }, + "tags": ["NSD Management interface"] + }, + "delete": { + "operationId": "api_nsd_v1_subscriptions_delete", + "description": "Delete subscription for Nsd Management", + "parameters": [], + "responses": { + "204": { + "description": "No_Content" + }, + "400": { + "description": "", + "schema": { + "$ref": "#/definitions/SUBSCRIPTION_ProblemDetailsSerializer" + } + }, + "404": { + "description": "", + "schema": { + "$ref": "#/definitions/SUBSCRIPTION_ProblemDetailsSerializer" + } + }, + "500": { + "description": "", + "schema": { + "$ref": "#/definitions/SUBSCRIPTION_ProblemDetailsSerializer" + } + } + }, + "tags": ["NSD Management interface"] + }, + "parameters": [{ + "name": "subscriptionId", + "in": "path", + "required": true, + "type": "string" + }] + }, + "/api/parser/v1/health_check": { + "get": { + "operationId": "api_parser_v1_health_check_list", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "Active" + } + }, + "tags": ["Health Check interface"] + }, + "parameters": [] + }, + "/api/parser/v1/parser": { + "post": { + "operationId": "api_parser_v1_parser_create", + "description": "Parse model(NS, Service, VNF, PNF)", + "parameters": [{ + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/ParseModelRequest" + } + }], + "responses": { + "202": { + "description": "", + "schema": { + "$ref": "#/definitions/ParseModelResponse" + } + }, + "500": { + "description": "", + "schema": { + "$ref": "#/definitions/InternalErrorRequest" + } + } + }, + "tags": ["Parser interface"] + }, + "parameters": [] + }, + "/api/parser/v1/parsernsd": { + "post": { + "operationId": "api_parser_v1_parsernsd_create", + "description": "Parse NS model", + "parameters": [{ + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/ParseModelRequest" + } + }], + "responses": { + "202": { + "description": "", + "schema": { + "$ref": "#/definitions/ParseModelResponse" + } + }, + "500": { + "description": "", + "schema": { + "$ref": "#/definitions/InternalErrorRequest" + } + } + }, + "tags": ["Parser interface"] + }, + "parameters": [] + }, + "/api/parser/v1/parserpnfd": { + "post": { + "operationId": "api_parser_v1_parserpnfd_create", + "description": "Parse PNF model", + "parameters": [{ + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/ParseModelRequest" + } + }], + "responses": { + "202": { + "description": "", + "schema": { + "$ref": "#/definitions/ParseModelResponse" + } + }, + "500": { + "description": "", + "schema": { + "$ref": "#/definitions/InternalErrorRequest" + } + } + }, + "tags": ["Parser interface"] + }, + "parameters": [] + }, + "/api/parser/v1/parservnfd": { + "post": { + "operationId": "api_parser_v1_parservnfd_create", + "description": "Parse NF model", + "parameters": [{ + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/ParseModelRequest" + } + }], + "responses": { + "202": { + "description": "", + "schema": { + "$ref": "#/definitions/ParseModelResponse" + } + }, + "500": { + "description": "", + "schema": { + "$ref": "#/definitions/InternalErrorRequest" + } + } + }, + "tags": ["Parser interface"] + }, + "parameters": [] + }, + "/api/vnfpkgm/v1/health_check": { + "get": { + "operationId": "api_vnfpkgm_v1_health_check_list", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "Active" + } + }, + "tags": ["Health Check interface"] + }, + "parameters": [] + }, + "/api/vnfpkgm/v1/subscriptions": { + "get": { + "operationId": "api_vnfpkgm_v1_subscriptions_list", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/PkgmSubscription" + } + }, + "400": { + "description": "", + "schema": { + "$ref": "#/definitions/SUBSCRIPTION_ProblemDetailsSerializer" + } + }, + "500": { + "description": "", + "schema": { + "$ref": "#/definitions/SUBSCRIPTION_ProblemDetailsSerializer" + } + } + }, + "tags": ["VNF Package Management interface"] + }, + "post": { + "operationId": "api_vnfpkgm_v1_subscriptions_create", + "description": "", + "parameters": [{ + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/PkgmSubscriptionRequest" + } + }], + "responses": { + "201": { + "description": "", + "schema": { + "$ref": "#/definitions/PkgmSubscription" + } + }, + "400": { + "description": "", + "schema": { + "$ref": "#/definitions/SUBSCRIPTION_ProblemDetailsSerializer" + } + }, + "500": { + "description": "", + "schema": { + "$ref": "#/definitions/SUBSCRIPTION_ProblemDetailsSerializer" + } + } + }, + "tags": ["VNF Package Management interface"] + }, + "parameters": [] + }, + "/api/vnfpkgm/v1/subscriptions/{subscriptionId}": { + "get": { + "operationId": "api_vnfpkgm_v1_subscriptions_read", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/PkgmSubscription" + } + }, + "404": { + "description": "", + "schema": { + "$ref": "#/definitions/SUBSCRIPTION_ProblemDetailsSerializer" + } + }, + "500": { + "description": "", + "schema": { + "$ref": "#/definitions/SUBSCRIPTION_ProblemDetailsSerializer" + } + } + }, + "tags": ["VNF Package Management interface"] + }, + "delete": { + "operationId": "api_vnfpkgm_v1_subscriptions_delete", + "description": "", + "parameters": [], + "responses": { + "204": { + "description": "" + }, + "404": { + "description": "", + "schema": { + "$ref": "#/definitions/SUBSCRIPTION_ProblemDetailsSerializer" + } + }, + "500": { + "description": "", + "schema": { + "$ref": "#/definitions/SUBSCRIPTION_ProblemDetailsSerializer" + } + } + }, + "tags": ["VNF Package Management interface"] + }, + "parameters": [{ + "name": "subscriptionId", + "in": "path", + "required": true, + "type": "string" + }] + }, + "/api/vnfpkgm/v1/vnf_packages": { + "get": { + "operationId": "api_vnfpkgm_v1_vnf_packages_list", + "description": "Query multiple VNF package resource", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/VnfPkgInfo" + } + } + }, + "500": { + "description": "Internal error", + "schema": { + "type": "string" + } + } + }, + "tags": ["VNF Package Management interface"] + }, + "post": { + "operationId": "api_vnfpkgm_v1_vnf_packages_create", + "description": "Create an individual VNF package resource", + "parameters": [{ + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/CreateVnfPkgInfoRequest" + } + }], + "responses": { + "201": { + "description": "", + "schema": { + "$ref": "#/definitions/VnfPkgInfo" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Internal error", + "schema": { + "type": "string" + } + } + }, + "tags": ["VNF Package Management interface"] + }, + "parameters": [] + }, + "/api/vnfpkgm/v1/vnf_packages/{vnfPkgId}": { + "get": { + "operationId": "api_vnfpkgm_v1_vnf_packages_read", + "description": "Query an individual VNF package resource", + "parameters": [], + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/VnfPkgInfo" + } + }, + "404": { + "description": "VNF package does not exist", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Internal error", + "schema": { + "type": "string" + } + } + }, + "tags": ["VNF Package Management interface"] + }, + "delete": { + "operationId": "api_vnfpkgm_v1_vnf_packages_delete", + "description": "Delete an individual VNF package resource", + "parameters": [], + "responses": { + "204": { + "description": "No content" + }, + "500": { + "description": "Internal error", + "schema": { + "type": "string" + } + } + }, + "tags": ["VNF Package Management interface"] + }, + "parameters": [{ + "name": "vnfPkgId", + "in": "path", + "required": true, + "type": "string" + }] + }, + "/api/vnfpkgm/v1/vnf_packages/{vnfPkgId}/artifacts/{artifactPath}": { + "get": { + "operationId": "api_vnfpkgm_v1_vnf_packages_artifacts_read", + "description": "", + "parameters": [], + "responses": { + "200": { + "description": "Return the artifact file", + "schema": { + "type": "string", + "format": "binary" + } + }, + "404": { + "description": "Artifact not found", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Internal error", + "schema": { + "type": "string" + } + } + }, + "produces": ["application/octet-stream", "application/json"], + "tags": ["VNF Package Management interface"] + }, + "parameters": [{ + "name": "artifactPath", + "in": "path", + "required": true, + "type": "string" + }, { + "name": "vnfPkgId", + "in": "path", + "required": true, + "type": "string" + }] + }, + "/api/vnfpkgm/v1/vnf_packages/{vnfPkgId}/package_content": { + "get": { + "operationId": "api_vnfpkgm_v1_vnf_packages_package_content_list", + "description": "Fetch VNF package content", + "parameters": [], + "responses": { + "200": { + "description": "VNF package file", + "schema": { + "type": "string", + "format": "binary" + } + }, + "404": { + "description": "VNF package does not exist", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Internal error", + "schema": { + "type": "string" + } + } + }, + "produces": ["application/octet-stream", "application/json"], + "tags": ["VNF Package Management interface"] + }, + "put": { + "operationId": "api_vnfpkgm_v1_vnf_packages_package_content_update", + "description": "Upload VNF package content", + "parameters": [], + "responses": { + "202": { + "description": "Successfully" + }, + "500": { + "description": "Internal error", + "schema": { + "type": "string" + } + } + }, + "tags": ["VNF Package Management interface"] + }, + "parameters": [{ + "name": "vnfPkgId", + "in": "path", + "required": true, + "type": "string" + }] + }, + "/api/vnfpkgm/v1/vnf_packages/{vnfPkgId}/package_content/upload_from_uri": { + "post": { + "operationId": "api_vnfpkgm_v1_vnf_packages_package_content_upload_from_uri_create", + "description": "Upload VNF package content from uri", + "parameters": [{ + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/UploadVnfPackageFromUriRequest" + } + }], + "responses": { + "202": { + "description": "Successfully" + }, + "400": { + "description": "Bad Request", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Internal error", + "schema": { + "type": "string" + } + } + }, + "tags": ["VNF Package Management interface"] + }, + "parameters": [{ + "name": "vnfPkgId", + "in": "path", + "required": true, + "type": "string" + }] + }, + "/api/vnfpkgm/v1/vnf_packages/{vnfPkgId}/vnfd": { + "get": { + "operationId": "VNFD of an on-boarded VNF package", + "description": "Read VNFD of an on-boarded VNF package", + "parameters": [], + "responses": { + "200": { + "description": "VNFD of an on-boarded VNF package", + "schema": { + "type": "string", + "format": "binary" + } + }, + "404": { + "description": "VNF package does not exist", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Internal error", + "schema": { + "type": "string" + } + } + }, + "produces": ["application/octet-stream", "application/json"], + "tags": ["VNF Package Management interface"] + }, + "parameters": [{ + "name": "vnfPkgId", + "in": "path", + "required": true, + "type": "string" + }] + }, + "/samples/": { + "get": { + "operationId": "samples_list", + "description": "List all samples.", + "parameters": [], + "responses": { + "200": { + "description": "" + } + }, + "tags": ["Sample interface"] + }, + "parameters": [] + } + }, + "definitions": { + "JobResponseHistoryList": { + "description": "Response History List", + "type": "object", + "properties": { + "status": { + "title": "Status", + "description": "Status", + "type": "string", + "minLength": 1 + }, + "progress": { + "title": "Progress", + "description": "Job Progress", + "type": "string", + "minLength": 1 + }, + "statusDescription": { + "title": "Statusdescription", + "description": "Status Description", + "type": "string", + "minLength": 1 + }, + "errorCode": { + "title": "Errorcode", + "description": "Error Code", + "type": "string", + "minLength": 1, + "x-nullable": true + }, + "responseId": { + "title": "Responseid", + "description": "Response Id", + "type": "string", + "minLength": 1 + } + } + }, + "JobResponseDescriptor": { + "title": "Responsedescriptor", + "description": "Job Response Descriptor", + "type": "object", + "properties": { + "status": { + "title": "Status", + "description": "Status", + "type": "string", + "minLength": 1 + }, + "progress": { + "title": "Progress", + "description": "Job Progress", + "type": "string", + "minLength": 1 + }, + "statusDescription": { + "title": "Statusdescription", + "description": "Status Description", + "type": "string", + "minLength": 1 + }, + "errorCode": { + "title": "Errorcode", + "description": "Error Code", + "type": "string", + "minLength": 1, + "x-nullable": true + }, + "responseId": { + "title": "Responseid", + "description": "Response Id", + "type": "string", + "minLength": 1 + }, + "responseHistoryList": { + "description": "Response History List", + "type": "array", + "items": { + "$ref": "#/definitions/JobResponseHistoryList" + } + } + } + }, + "GetJobResponse": { + "type": "object", + "properties": { + "jobId": { + "title": "Jobid", + "description": "Job Id", + "type": "string", + "minLength": 1 + }, + "responseDescriptor": { + "$ref": "#/definitions/JobResponseDescriptor" + } + } + }, + "PostJobResponseResult": { + "required": ["result"], + "type": "object", + "properties": { + "result": { + "title": "Result", + "description": "Result", + "type": "string", + "minLength": 1 + }, + "msg": { + "title": "Msg", + "description": "Message", + "type": "string", + "minLength": 1 + } + } + }, + "PostJobRequest": { + "type": "object", + "properties": { + "progress": { + "title": "Progress", + "description": "Job Progress", + "type": "string", + "minLength": 1 + }, + "desc": { + "title": "Desc", + "description": "Description", + "type": "string", + "minLength": 1 + }, + "errcode": { + "title": "Errcode", + "description": "Error Code", + "type": "string", + "minLength": 1 + } + } + }, + "NsPackageInfo": { + "title": "Packageinfo", + "description": "NS Package Info", + "type": "object", + "properties": { + "nsdId": { + "title": "Nsdid", + "description": "NSD ID", + "type": "string", + "minLength": 1, + "x-nullable": true + }, + "nsPackageId": { + "title": "Nspackageid", + "description": "NS Package ID", + "type": "string", + "x-nullable": true + }, + "nsdProvider": { + "title": "Nsdprovider", + "description": "NSD Provider", + "type": "string", + "x-nullable": true + }, + "nsdVersion": { + "title": "Nsdversion", + "description": "NSD Version", + "type": "string", + "x-nullable": true + }, + "csarName": { + "title": "Csarname", + "description": "CSAR name", + "type": "string", + "x-nullable": true + }, + "nsdModel": { + "title": "Nsdmodel", + "description": "NSD Model", + "type": "string", + "x-nullable": true + }, + "downloadUrl": { + "title": "Downloadurl", + "description": "URL to download NSD Model", + "type": "string", + "minLength": 1, + "x-nullable": true + } + }, + "x-nullable": true + }, + "NsPackage": { + "type": "object", + "properties": { + "csarId": { + "title": "Csarid", + "description": "CSAR ID", + "type": "string", + "minLength": 1, + "x-nullable": true + }, + "packageInfo": { + "$ref": "#/definitions/NsPackageInfo" + } + } + }, + "InternalErrorRequest": { + "required": ["error"], + "type": "object", + "properties": { + "error": { + "title": "Error", + "description": "Error", + "type": "string", + "minLength": 1 + }, + "errorMessage": { + "title": "Errormessage", + "description": "Error Message", + "type": "string", + "minLength": 1 + } + } + }, + "NsPackageDistributeRequest": { + "required": ["csarId"], + "type": "object", + "properties": { + "csarId": { + "title": "Csarid", + "description": "csarId", + "type": "string", + "minLength": 1 + } + } + }, + "NsPackageDistributeResponse": { + "required": ["status", "statusDescription", "errorCode"], + "type": "object", + "properties": { + "status": { + "title": "Status", + "description": "status", + "type": "string", + "minLength": 1 + }, + "statusDescription": { + "title": "Statusdescription", + "description": "statusDescription", + "type": "string", + "minLength": 1 + }, + "errorCode": { + "title": "Errorcode", + "description": "errorCode", + "type": "string", + "minLength": 1 + } + } + }, + "ServicePackageInfo": { + "title": "Packageinfo", + "description": "Service Package Info", + "type": "object", + "properties": { + "servicedId": { + "title": "Servicedid", + "description": "ServiceD ID", + "type": "string", + "minLength": 1, + "x-nullable": true + }, + "servicePackageId": { + "title": "Servicepackageid", + "description": "Service Package ID", + "type": "string", + "x-nullable": true + }, + "servicedProvider": { + "title": "Servicedprovider", + "description": "ServiceD Provider", + "type": "string", + "x-nullable": true + }, + "servicedVersion": { + "title": "Servicedversion", + "description": "ServiceD Version", + "type": "string", + "x-nullable": true + }, + "csarName": { + "title": "Csarname", + "description": "CSAR name", + "type": "string", + "x-nullable": true + }, + "servicedModel": { + "title": "Servicedmodel", + "description": "ServiceD Model", + "type": "string", + "x-nullable": true + }, + "downloadUrl": { + "title": "Downloadurl", + "description": "URL to download ServiceD Model", + "type": "string", + "minLength": 1, + "x-nullable": true + } + }, + "x-nullable": true + }, + "ServicePackage": { + "type": "object", + "properties": { + "csarId": { + "title": "Csarid", + "description": "CSAR ID", + "type": "string", + "minLength": 1, + "x-nullable": true + }, + "packageInfo": { + "$ref": "#/definitions/ServicePackageInfo" + } + } + }, + "ServicePackageDistributeRequest": { + "required": ["csarId"], + "type": "object", + "properties": { + "csarId": { + "title": "Csarid", + "description": "csarId", + "type": "string", + "minLength": 1 + } + } + }, + "NfPackageInfo": { + "title": "Packageinfo", + "description": "VNF Package Info", + "required": ["vnfPackageId"], + "type": "object", + "properties": { + "vnfdId": { + "title": "Vnfdid", + "description": "VNFD ID", + "type": "string", + "x-nullable": true + }, + "vnfPackageId": { + "title": "Vnfpackageid", + "description": "VNF Package ID", + "type": "string", + "minLength": 1 + }, + "vnfdProvider": { + "title": "Vnfdprovider", + "description": "VNFD Provider", + "type": "string", + "x-nullable": true + }, + "vnfdVersion": { + "title": "Vnfdversion", + "description": "VNFD Version", + "type": "string", + "x-nullable": true + }, + "vnfVersion": { + "title": "Vnfversion", + "description": "VNF Version", + "type": "string", + "x-nullable": true + }, + "csarName": { + "title": "Csarname", + "description": "CSAR Name", + "type": "string", + "x-nullable": true + }, + "vnfdModel": { + "title": "Vnfdmodel", + "description": "VNFD Model", + "type": "string", + "x-nullable": true + }, + "downloadUrl": { + "title": "Downloadurl", + "description": "URL to download VNFD Model", + "type": "string", + "x-nullable": true + } + } + }, + "NfImageInfo": { + "description": "Image Info", + "required": ["index", "fileName", "imageId", "vimId", "vimUser", "tenant", "status"], + "type": "object", + "properties": { + "index": { + "title": "Index", + "description": "Index of VNF Image", + "type": "string", + "minLength": 1 + }, + "fileName": { + "title": "Filename", + "description": "Image file name", + "type": "string", + "minLength": 1 + }, + "imageId": { + "title": "Imageid", + "description": "Image ID", + "type": "string", + "minLength": 1 + }, + "vimId": { + "title": "Vimid", + "description": "VIM ID", + "type": "string", + "minLength": 1 + }, + "vimUser": { + "title": "Vimuser", + "description": "User of VIM", + "type": "string", + "minLength": 1 + }, + "tenant": { + "title": "Tenant", + "description": "Tenant", + "type": "string", + "minLength": 1 + }, + "status": { + "title": "Status", + "description": "Status", + "type": "string", + "minLength": 1 + } + } + }, + "NfPackage": { + "required": ["csarId", "packageInfo"], + "type": "object", + "properties": { + "csarId": { + "title": "Csarid", + "description": "CSAR ID", + "type": "string", + "minLength": 1 + }, + "packageInfo": { + "$ref": "#/definitions/NfPackageInfo" + }, + "imageInfo": { + "description": "Image Info", + "type": "array", + "items": { + "$ref": "#/definitions/NfImageInfo" + }, + "x-nullable": true + } + } + }, + "NfPackageDistributeRequest": { + "required": ["csarId"], + "type": "object", + "properties": { + "csarId": { + "title": "Csarid", + "description": "CSAR ID", + "type": "string", + "minLength": 1 + }, + "vimIds": { + "description": "A string for vimIds", + "type": "array", + "items": { + "type": "string", + "minLength": 1 + } + }, + "labVimId": { + "title": "Labvimid", + "description": "A list of VIM IDs.", + "type": "string" + } + } + }, + "PostJobResponse": { + "required": ["jobId"], + "type": "object", + "properties": { + "jobId": { + "title": "Jobid", + "description": "jobId", + "type": "string", + "minLength": 1 + } + } + }, + "ProblemDetails": { + "title": "Onboardingfailuredetails", + "description": "Failure details of current onboarding procedure.It shall be present when the nsdOnboardingState attribute is CREATED and the uploading or processing fails in NFVO.", + "required": ["title", "detail"], + "type": "object", + "properties": { + "type": { + "title": "Type", + "description": "A URI reference according to IETF RFC 3986 [10] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".", + "type": "string", + "x-nullable": true + }, + "title": { + "title": "Title", + "description": "The HTTP status code for this occurrence of the problem.", + "type": "integer" + }, + "detail": { + "title": "Detail", + "description": "A human-readable explanation specific to this occurrence of the problem.", + "type": "string", + "minLength": 1 + }, + "instance": { + "title": "Instance", + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.", + "type": "string", + "x-nullable": true + }, + "additional_attributes": { + "title": "Additional attributes", + "description": "Any number of additional attributes, as defined in a specification or by an implementation.", + "type": "object", + "additionalProperties": { + "description": "Additional attribute", + "type": "string" + }, + "x-nullable": true + } + } + }, + "UriLink": { + "title": "Self", + "description": "URI of this resource.", + "required": ["href"], + "type": "object", + "properties": { + "href": { + "title": "Href", + "description": "URI of the referenced resource", + "type": "string", + "minLength": 1 + } + } + }, + "NSD_LinkSerializer": { + "title": " links", + "description": "Links to resources related to this resource.", + "required": ["self", "nsd_content"], + "type": "object", + "properties": { + "self": { + "$ref": "#/definitions/UriLink" + }, + "nsd_content": { + "$ref": "#/definitions/UriLink" + } + } + }, + "NsdInfo": { + "required": ["id", "nsdOnboardingState", "nsdOperationalState", "nsdUsageState", "_links"], + "type": "object", + "properties": { + "id": { + "title": "Id", + "description": "Identifier of the onboarded individual NS descriptor resource.This identifier is allocated by the NFVO.", + "type": "string", + "minLength": 1 + }, + "nsdId": { + "title": "Nsdid", + "description": "This identifier, which is allocated by the NSD designer,identifies the NSD in a globally unique way.It is copied from the NSD content and shall be present after the NSD content is on-boarded.", + "type": "string", + "x-nullable": true + }, + "nsdName": { + "title": "Nsdname", + "description": "Name of the onboarded NSD.This information is copied from the NSD content and shall be present after the NSD content is on-boarded.", + "type": "string", + "x-nullable": true + }, + "nsdVersion": { + "title": "Nsdversion", + "description": "Version of the on-boarded NSD.This information is copied from the NSD content and shall be present after the NSD content is on-boarded.", + "type": "string", + "x-nullable": true + }, + "nsdDesigner": { + "title": "Nsddesigner", + "description": "Designer of the on-boarded NSD.This information is copied from the NSD content and shall be present after the NSD content is on-boarded.", + "type": "string", + "x-nullable": true + }, + "nsdInvariantId": { + "title": "Nsdinvariantid", + "description": "This identifier, which is allocated by the NSD designer,identifies an NSD in a version independent manner.This information is copied from the NSD content and shall be present after the NSD content is on-boarded.", + "type": "string", + "x-nullable": true + }, + "vnfPkgIds": { + "description": "Identifies the VNF package for the VNFD referenced by the on-boarded NS descriptor resource.", + "type": "array", + "items": { + "description": "Identifier of the VNF package", + "type": "string" + }, + "x-nullable": true + }, + "pnfdInfoIds": { + "description": "Identifies the PnfdInfo element for the PNFD referenced by the on-boarded NS descriptor resource.", + "type": "array", + "items": { + "description": "Identifier of the PnfdInfo element", + "type": "string" + }, + "x-nullable": true + }, + "nestedNsdInfoIds": { + "description": "Identifies the NsdInfo element for the nested NSD referenced by the on-boarded NS descriptor resource.", + "type": "array", + "items": { + "description": "Identifier of the NsdInfo element", + "type": "string" + }, + "x-nullable": true + }, + "nsdOnboardingState": { + "title": "Nsdonboardingstate", + "description": "Onboarding state of the individual NS descriptor resource.", + "type": "string", + "enum": ["CREATED", "UPLOADING", "PROCESSING", "ONBOARDED"] + }, + "onboardingFailureDetails": { + "$ref": "#/definitions/ProblemDetails" + }, + "nsdOperationalState": { + "title": "Nsdoperationalstate", + "description": "Operational state of the individual NS descriptor resource.This attribute can be modified with the PATCH method.", + "type": "string", + "enum": ["ENABLED", "DISABLED"] + }, + "nsdUsageState": { + "title": "Nsdusagestate", + "description": "Usage state of the individual NS descriptor resource.", + "type": "string", + "enum": ["IN_USE", "NOT_IN_USE"] + }, + "userDefinedData": { + "title": "Userdefineddata", + "description": "User defined data for the individual NS descriptor resource.This attribute can be modified with the PATCH method.", + "type": "object", + "additionalProperties": { + "description": "Key Value Pairs", + "type": "string" + }, + "x-nullable": true + }, + "_links": { + "$ref": "#/definitions/NSD_LinkSerializer" + } + } + }, + "CreateNsdInfoRequest": { + "type": "object", + "properties": { + "userDefinedData": { + "title": "Userdefineddata", + "description": "User-defined data for the NS descriptor resource to be created.It shall be present when the user defined data is set for the individual NS descriptor resource to be created.", + "type": "object", + "additionalProperties": { + "description": "Key Value Pairs", + "type": "string" + }, + "x-nullable": true + } + } + }, + "PNFD_LinkSerializer": { + "title": " links", + "description": "Links to resources related to this resource.", + "required": ["self", "pnfd_content"], + "type": "object", + "properties": { + "self": { + "$ref": "#/definitions/UriLink" + }, + "pnfd_content": { + "$ref": "#/definitions/UriLink" + } + } + }, + "PnfdInfo": { + "required": ["id", "pnfdOnboardingState", "pnfdUsageState", "_links"], + "type": "object", + "properties": { + "id": { + "title": "Id", + "description": "Identifier of the onboarded individual PNF descriptor resource. This identifier is allocated by the NFVO.", + "type": "string", + "minLength": 1 + }, + "pnfdId": { + "title": "Pnfdid", + "description": "This identifier, which is allocated by the PNFD designer, identifies the PNFD in a globally unique way. It is copied from the PNFD content and shall be present after the PNFD content is on-boarded.", + "type": "string", + "x-nullable": true + }, + "pnfdName": { + "title": "Pnfdname", + "description": "Name of the onboarded PNFD. This information is copied from the PNFD content and shall be present after the PNFD content is on-boarded.", + "type": "string", + "x-nullable": true + }, + "pnfdVersion": { + "title": "Pnfdversion", + "description": "Version of the on-boarded PNFD. This information is copied from the PNFD content and shall be present after the PNFD content is on-boarded.", + "type": "string", + "x-nullable": true + }, + "pnfdProvider": { + "title": "Pnfdprovider", + "description": "Provider of the on-boarded PNFD. This information is copied from the PNFD content and shall be present after the PNFD content is on-boarded.", + "type": "string", + "x-nullable": true + }, + "pnfdInvariantId": { + "title": "Pnfdinvariantid", + "description": "Identifies a PNFD in a version independent manner. This attribute is invariant across versions of PNFD.", + "type": "string", + "x-nullable": true + }, + "pnfdOnboardingState": { + "title": "Pnfdonboardingstate", + "description": "Onboarding state of the individual PNF descriptor resource.", + "type": "string", + "enum": ["CREATED", "UPLOADING", "PROCESSING", "ONBOARDED"] + }, + "onboardingFailureDetails": { + "$ref": "#/definitions/ProblemDetails" + }, + "pnfdUsageState": { + "title": "Pnfdusagestate", + "description": "Usage state of the individual PNF descriptor resource.", + "type": "string", + "enum": ["IN_USE", "NOT_IN_USE"] + }, + "userDefinedData": { + "title": "Userdefineddata", + "description": "User defined data for the individual PNF descriptor resource. This attribute can be modified with the PATCH method.", + "type": "object", + "additionalProperties": { + "description": "Key Value Pairs", + "type": "string" + }, + "x-nullable": true + }, + "_links": { + "$ref": "#/definitions/PNFD_LinkSerializer" + } + } + }, + "SUBSCRIPTION_ProblemDetailsSerializer": { + "required": ["status", "detail"], + "type": "object", + "properties": { + "type": { + "title": "Type", + "description": "Type", + "type": "string", + "minLength": 1, + "x-nullable": true + }, + "title": { + "title": "Title", + "description": "Title", + "type": "string", + "minLength": 1, + "x-nullable": true + }, + "status": { + "title": "Status", + "description": "Status", + "type": "integer" + }, + "detail": { + "title": "Detail", + "description": "Detail", + "type": "string", + "minLength": 1 + }, + "instance": { + "title": "Instance", + "description": "Instance", + "type": "string", + "minLength": 1, + "x-nullable": true + }, + "additional_details": { + "description": "Any number of additional attributes, as defined in a specification or by an implementation.", + "type": "array", + "items": { + "type": "string" + }, + "x-nullable": true + } + } + }, + "CreatePnfdInfoRequest": { + "type": "object", + "properties": { + "userDefinedData": { + "title": "Userdefineddata", + "description": "User-defined data for the PNF descriptor resource to be created.It shall be present when the user defined data is set for the individual PNF descriptor resource to be created.", + "type": "object", + "additionalProperties": { + "description": "Key Value Pairs", + "type": "string" + }, + "x-nullable": true + } + } + }, + "NsdmNotificationsFilter": { + "title": "Filter", + "description": "Filter settings for this subscription, to define the of all notifications this subscription relates to.", + "type": "object", + "properties": { + "notificationTypes": { + "description": "Match particular notification types", + "type": "array", + "items": { + "type": "string", + "enum": ["NsdOnBoardingNotification", "NsdOnboardingFailureNotification", "NsdChangeNotification", "NsdDeletionNotification", "PnfdOnBoardingNotification", "PnfdOnBoardingFailureNotification", "PnfdDeletionNotification"] + } + }, + "nsdInfoId": { + "description": "Match NS packages with particular nsdInfoIds", + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + }, + "nsdId": { + "description": "Match NS Packages with particular nsdIds", + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + }, + "nsdName": { + "description": "Match NS Packages with particular nsdNames", + "type": "array", + "items": { + "type": "string", + "maxLength": 255, + "minLength": 1 + } + }, + "nsdVersion": { + "description": "match NS packages that belong to certain nsdversion", + "type": "array", + "items": { + "type": "string", + "maxLength": 255, + "minLength": 1 + } + }, + "nsdInvariantId": { + "description": "Match NS Packages with particular nsdInvariantIds", + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + }, + "vnfPkgIds": { + "description": "Match NS Packages that has VNF PackageIds", + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + }, + "nestedNsdInfoIds": { + "description": "Match NS Packages with particular nsdInvariantIds", + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + }, + "nsdOnboardingState": { + "description": "Match NS Packages with particular NS Onboarding State", + "type": "array", + "items": { + "type": "string", + "enum": ["CREATED", "UPLOADING", "PROCESSING", "ONBOARDED"] + } + }, + "nsdOperationalState": { + "description": "Match NS Packages with particular NS Operational State", + "type": "array", + "items": { + "type": "string", + "enum": ["ENABLED", "DISABLED"] + } + }, + "nsdUsageState": { + "description": "Match NS Packages with particular NS Usage State", + "type": "array", + "items": { + "type": "string", + "enum": ["IN_USE", "NOT_IN_USE"] + } + }, + "pnfdInfoIds": { + "description": "Match PF packages with particular pnfdInfoIds", + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + }, + "pnfdId": { + "description": "Match PF packages with particular pnfdInfoIds", + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + }, + "pnfdName": { + "description": "Match PF Packages with particular pnfdNames", + "type": "array", + "items": { + "type": "string", + "maxLength": 255, + "minLength": 1 + } + }, + "pnfdVersion": { + "description": "match PF packages that belong to certain pnfd version", + "type": "array", + "items": { + "type": "string", + "maxLength": 255, + "minLength": 1 + } + }, + "pnfdProvider": { + "description": "Match PF Packages with particular pnfdProvider", + "type": "array", + "items": { + "type": "string", + "maxLength": 255, + "minLength": 1 + } + }, + "pnfdInvariantId": { + "description": "Match PF Packages with particular pnfdInvariantIds", + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + }, + "pnfdOnboardingState": { + "description": "Match PF Packages with particular PNF Onboarding State ", + "type": "array", + "items": { + "type": "string", + "enum": ["CREATED", "UPLOADING", "PROCESSING", "ONBOARDED"] + } + }, + "pnfdUsageState": { + "description": "Match PF Packages with particular PNF usage State", + "type": "array", + "items": { + "type": "string", + "enum": ["IN_USE", "NOT_IN_USE"] + } + } + } + }, + "NSDM_SUB_LinkSerializer": { + "title": " links", + "description": "Links to resources related to this resource.", + "required": ["self"], + "type": "object", + "properties": { + "self": { + "$ref": "#/definitions/UriLink" + } + } + }, + "NsdmSubscription": { + "required": ["id", "callbackUri", "_links"], + "type": "object", + "properties": { + "id": { + "title": "Id", + "description": "Identifier of this subscription resource.", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "callbackUri": { + "title": "Callbackuri", + "description": "The URI of the endpoint to send the notification to.", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "filter": { + "$ref": "#/definitions/NsdmNotificationsFilter" + }, + "_links": { + "$ref": "#/definitions/NSDM_SUB_LinkSerializer" + } + } + }, + "BasicAuth": { + "title": "Paramsbasic", + "description": "Parameters for authentication/authorization using BASIC.", + "type": "object", + "properties": { + "userName": { + "title": "Username", + "description": "Username to be used in HTTP Basic authentication.", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "password": { + "title": "Password", + "description": "Password to be used in HTTP Basic authentication.", + "type": "string", + "maxLength": 255, + "minLength": 1 + } + } + }, + "OAuthCredentials": { + "title": "Paramsoauth2clientcredentials", + "description": "Parameters for authentication/authorization using OAUTH2_CLIENT_CREDENTIALS.", + "type": "object", + "properties": { + "clientId": { + "title": "Clientid", + "description": "Client identifier to be used in the access token request of the OAuth 2.0 client credentials grant type.", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "clientPassword": { + "title": "Clientpassword", + "description": "Client password to be used in the access token request of the OAuth 2.0 client credentials grant type.", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "tokenEndpoint": { + "title": "Tokenendpoint", + "description": "The token endpoint from which the access token can be obtained.", + "type": "string", + "maxLength": 255, + "minLength": 1 + } + } + }, + "SubscriptionAuthentication": { + "title": "Authentication", + "description": "Authentication parameters to configure the use of Authorization when sending notifications corresponding to this subscription.", + "required": ["authType"], + "type": "object", + "properties": { + "authType": { + "description": "Defines the types of Authentication / Authorization which the API consumer is willing to accept when receiving a notification.", + "type": "array", + "items": { + "type": "string", + "enum": ["BASIC", "OAUTH2_CLIENT_CREDENTIALS", "TLS_CERT"] + } + }, + "paramsBasic": { + "$ref": "#/definitions/BasicAuth" + }, + "paramsOauth2ClientCredentials": { + "$ref": "#/definitions/OAuthCredentials" + } + } + }, + "NsdmSubscriptionRequest": { + "required": ["callbackUri"], + "type": "object", + "properties": { + "callbackUri": { + "title": "Callbackuri", + "description": "The URI of the endpoint to send the notification to.", + "type": "string", + "minLength": 1 + }, + "filter": { + "$ref": "#/definitions/NsdmNotificationsFilter" + }, + "authentication": { + "$ref": "#/definitions/SubscriptionAuthentication" + } + } + }, + "ParseModelRequest": { + "required": ["csarId"], + "type": "object", + "properties": { + "csarId": { + "title": "Csarid", + "description": "CSAR ID", + "type": "string", + "minLength": 1 + }, + "packageType": { + "title": "Packagetype", + "description": "Package type: VNF, PNF, NS, Service", + "type": "string", + "minLength": 1 + }, + "inputs": { + "title": "Inputs", + "description": "Inputs", + "type": "string" + } + } + }, + "ParseModelResponse": { + "required": ["model"], + "type": "object", + "properties": { + "model": { + "title": "Model", + "description": "Model", + "type": "string" + } + } + }, + "VNF_SUBSCRIPTION_LINKSERIALIZER": { + "title": "Self", + "description": "URI of this resource.", + "required": ["href"], + "type": "object", + "properties": { + "href": { + "title": "Href", + "description": "URI of the referenced resource.", + "type": "string", + "minLength": 1 + } + } + }, + "LinkSelf": { + "title": " links", + "description": "Links to resources related to this resource.", + "required": ["self"], + "type": "object", + "properties": { + "self": { + "$ref": "#/definitions/VNF_SUBSCRIPTION_LINKSERIALIZER" + } + } + }, + "Version": { + "title": "Versions", + "description": "match VNF packages that contain VNF products with certain versions", + "required": ["vnfSoftwareVersion"], + "type": "object", + "properties": { + "vnfSoftwareVersion": { + "title": "Vnfsoftwareversion", + "description": "VNF software version to match.", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "vnfdVersions": { + "description": "Match VNF packages that contain VNF products with certain VNFD versions", + "type": "array", + "items": { + "type": "string", + "minLength": 1 + } + } + } + }, + "vnfProducts": { + "title": "Vnfproducts", + "description": "match VNF packages that contain VNF products with certain product names, from one particular provider", + "required": ["vnfProductName"], + "type": "object", + "properties": { + "vnfProductName": { + "title": "Vnfproductname", + "description": "Name of the VNF product to match.", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "versions": { + "$ref": "#/definitions/Version" + } + } + }, + "vnfProductsProviders": { + "required": ["vnfProvider"], + "type": "object", + "properties": { + "vnfProvider": { + "title": "Vnfprovider", + "description": "Name of the VNFprovider to match.", + "type": "string", + "maxLength": 255, + "minLength": 1 + }, + "vnfProducts": { + "$ref": "#/definitions/vnfProducts" + } + } + }, + "PkgmNotificationsFilter": { + "title": "Filter", + "description": "Filter settings for this subscription, to define the subset of all notifications this subscription relates to", + "type": "object", + "properties": { + "notificationTypes": { + "description": "Match particular notification types", + "type": "array", + "items": { + "type": "string", + "enum": ["VnfPackageOnboardingNotification", "VnfPackageChangeNotification"] + } + }, + "vnfProductsFromProviders": { + "description": "Match VNF packages that contain VNF products from certain providers.", + "type": "array", + "items": { + "$ref": "#/definitions/vnfProductsProviders" + } + }, + "vnfdId": { + "description": "Match VNF packages with a VNFD identifierlisted in the attribute", + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + }, + "vnfPkgId": { + "description": "Match VNF packages with a VNFD identifierlisted in the attribute", + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + }, + "operationalState": { + "description": "Operational state of the VNF package.", + "type": "array", + "items": { + "type": "string", + "enum": ["ENABLED", "DISABLED"] + } + }, + "usageState": { + "description": "Operational state of the VNF package.", + "type": "array", + "items": { + "type": "string", + "enum": ["IN_USE", "NOT_IN_USE"] + } + } + } + }, + "PkgmSubscription": { + "required": ["id", "callbackUri", "_links"], + "type": "object", + "properties": { + "id": { + "title": "Id", + "description": "Identifier of this subscription resource.", + "type": "string", + "format": "uuid" + }, + "callbackUri": { + "title": "Callbackuri", + "description": "The URI of the endpoint to send the notification to.", + "type": "string", + "format": "uri", + "minLength": 1 + }, + "_links": { + "$ref": "#/definitions/LinkSelf" + }, + "filter": { + "$ref": "#/definitions/PkgmNotificationsFilter" + } + } + }, + "PkgmSubscriptionRequest": { + "required": ["callbackUri"], + "type": "object", + "properties": { + "filters": { + "$ref": "#/definitions/PkgmNotificationsFilter" + }, + "callbackUri": { + "title": "Callbackuri", + "description": "Callback URI to sendthe notification", + "type": "string", + "format": "uri", + "minLength": 1 + }, + "authentication": { + "$ref": "#/definitions/SubscriptionAuthentication" + } + } + }, + "Checksum": { + "title": "Checksum", + "description": "Checksum of the on-boarded VNF package.", + "required": ["algorithm", "hash"], + "type": "object", + "properties": { + "algorithm": { + "title": "Algorithm", + "description": "Name of the algorithm used to generate the checksum.", + "type": "string", + "minLength": 1 + }, + "hash": { + "title": "Hash", + "description": "The hexadecimal value of the checksum.", + "type": "string", + "minLength": 1 + } + } + }, + "VnfPackageSoftwareImageInfo": { + "description": "Information about VNF package artifacts that are software images.", + "required": ["id", "name", "provider", "version", "checksum", "containerFormat", "diskFormat", "createdAt", "minDisk", "minRam", "size", "imagePath"], + "type": "object", + "properties": { + "id": { + "title": "Id", + "description": "Identifier of the software image.", + "type": "string", + "minLength": 1 + }, + "name": { + "title": "Name", + "description": "Name of the software image.", + "type": "string", + "minLength": 1 + }, + "provider": { + "title": "Provider", + "description": "Provider of the software image.", + "type": "string", + "minLength": 1 + }, + "version": { + "title": "Version", + "description": "Version of the software image.", + "type": "string", + "minLength": 1 + }, + "checksum": { + "$ref": "#/definitions/Checksum" + }, + "containerFormat": { + "title": "Containerformat", + "description": "terminationType: Indicates whether forceful or graceful termination is requested.", + "type": "string", + "enum": ["AKI", "AMI", "ARI", "BARE", "DOCKER", "OVA", "OVF"] + }, + "diskFormat": { + "title": "Diskformat", + "description": "Disk format of a software image is the format of the underlying disk image.", + "type": "string", + "enum": ["AKI", "AMI", "ARI", "ISO", "QCOW2", "RAW", "VDI", "VHD", "VHDX", "VMDK"] + }, + "createdAt": { + "title": "Createdat", + "description": "Time when this software image was created.", + "type": "string", + "format": "date-time" + }, + "minDisk": { + "title": "Mindisk", + "description": "The minimal disk for this software image in bytes.", + "type": "integer" + }, + "minRam": { + "title": "Minram", + "description": "The minimal RAM for this software image in bytes.", + "type": "integer" + }, + "size": { + "title": "Size", + "description": "Size of this software image in bytes.", + "type": "integer" + }, + "userMetadata": { + "title": "Usermetadata", + "description": "User-defined data.", + "type": "object", + "additionalProperties": { + "description": "KeyValue Pairs", + "type": "string" + }, + "x-nullable": true + }, + "imagePath": { + "title": "Imagepath", + "description": "Path in the VNF package.", + "type": "string", + "minLength": 1 + } + } + }, + "VnfPackageArtifactInfo": { + "description": "Information about VNF package artifacts contained in the VNF package that are not software images.", + "required": ["artifactPath", "checksum"], + "type": "object", + "properties": { + "artifactPath": { + "title": "Artifactpath", + "description": "Path in the VNF package.", + "type": "string", + "minLength": 1 + }, + "checksum": { + "$ref": "#/definitions/Checksum" + }, + "metadata": { + "title": "Metadata", + "description": "The metadata of the artifact that are available in the VNF package", + "type": "object", + "additionalProperties": { + "description": "KeyValue Pairs", + "type": "string" + }, + "x-nullable": true + } + } + }, + "VNF_PKGM_Link_Serializer": { + "title": " links", + "description": "Links to resources related to this resource.", + "required": ["self", "packageContent"], + "type": "object", + "properties": { + "self": { + "$ref": "#/definitions/UriLink" + }, + "vnfd": { + "$ref": "#/definitions/UriLink" + }, + "packageContent": { + "$ref": "#/definitions/UriLink" + } + } + }, + "VnfPkgInfo": { + "required": ["id", "onboardingState", "operationalState", "usageState", "_links"], + "type": "object", + "properties": { + "id": { + "title": "Id", + "description": "Identifier of the on-boarded VNF package.", + "type": "string", + "minLength": 1 + }, + "vnfdId": { + "title": "Vnfdid", + "description": "This identifier, which is managed by the VNF provider, identifies the VNF package and the VNFD in a globally unique way.", + "type": "string", + "x-nullable": true + }, + "vnfProvider": { + "title": "Vnfprovider", + "description": "Provider of the VNF package and the VNFD.", + "type": "string", + "x-nullable": true + }, + "vnfProductName": { + "title": "Vnfproductname", + "description": "Name to identify the VNF product.", + "type": "string", + "x-nullable": true + }, + "vnfSoftwareVersion": { + "title": "Vnfsoftwareversion", + "description": "Software version of the VNF.", + "type": "string", + "x-nullable": true + }, + "vnfdVersion": { + "title": "Vnfdversion", + "description": "The version of the VNvFD.", + "type": "string", + "x-nullable": true + }, + "checksum": { + "$ref": "#/definitions/Checksum" + }, + "softwareImages": { + "description": "Information about VNF package artifacts that are software images.", + "type": "array", + "items": { + "$ref": "#/definitions/VnfPackageSoftwareImageInfo" + }, + "x-nullable": true + }, + "additionalArtifacts": { + "description": "Information about VNF package artifacts contained in the VNF package that are not software images.", + "type": "array", + "items": { + "$ref": "#/definitions/VnfPackageArtifactInfo" + }, + "x-nullable": true + }, + "onboardingState": { + "title": "Onboardingstate", + "description": "On-boarding state of the VNF package.", + "type": "string", + "enum": ["CREATED", "UPLOADING", "PROCESSING", "ONBOARDED"] + }, + "operationalState": { + "title": "Operationalstate", + "description": "Operational state of the VNF package.", + "type": "string", + "enum": ["ENABLED", "DISABLED"] + }, + "usageState": { + "title": "Usagestate", + "description": "Usage state of the VNF package.", + "type": "string", + "enum": ["IN_USE", "NOT_IN_USE"] + }, + "userDefinedData": { + "title": "Userdefineddata", + "description": "User defined data for the VNF package.", + "type": "object", + "additionalProperties": { + "description": "KeyValue Pairs", + "type": "string" + }, + "x-nullable": true + }, + "_links": { + "$ref": "#/definitions/VNF_PKGM_Link_Serializer" + } + } + }, + "CreateVnfPkgInfoRequest": { + "type": "object", + "properties": { + "userDefinedData": { + "title": "Userdefineddata", + "description": "User defined data for the VNF package.", + "type": "object", + "additionalProperties": { + "description": "KeyValue Pairs", + "type": "string" + }, + "x-nullable": true + } + } + }, + "UploadVnfPackageFromUriRequest": { + "required": ["addressInformation"], + "type": "object", + "properties": { + "addressInformation": { + "title": "Addressinformation", + "description": "Address information of the VNF package content.", + "type": "string", + "minLength": 1 + }, + "userName": { + "title": "Username", + "description": "User name to be used for authentication.", + "type": "string", + "minLength": 1 + }, + "password": { + "title": "Password", + "description": "Password to be used for authentication.", + "type": "string", + "minLength": 1 + } + } + } + } +}
\ No newline at end of file diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-adapter-ext-clients/src/main/resources/SOL003-VNFPackageManagement-API.json b/adapters/mso-vnfm-adapter/mso-vnfm-adapter-ext-clients/src/main/resources/SOL003-VNFPackageManagement-API.json new file mode 100644 index 0000000000..1f4a8ac306 --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-adapter-ext-clients/src/main/resources/SOL003-VNFPackageManagement-API.json @@ -0,0 +1,7311 @@ +{ + "swagger": "2.0", + "info": { + "version": "1.2.0-impl:etsi.org:ETSI_NFV_OpenAPI:1", + "title": "SOL003 - VNF Package Management interface", + "description": "SOL003 - VNF Package Management interface\n\nIMPORTANT: Please note that this file might be not aligned to the current version of the ETSI Group Specification it refers to. In case of discrepancies the published ETSI Group Specification takes precedence.\n\nIn clause 4.3.2 of ETSI GS NFV-SOL 003 v2.4.1, an attribute-based filtering mechanism is defined. This mechanism is currently not included in the corresponding OpenAPI design for this GS version. Changes to the attribute-based filtering mechanism are being considered in v2.5.1 of this GS for inclusion in the corresponding future ETSI NFV OpenAPI design.\nPlease report bugs to https://forge.etsi.org/bugzilla/buglist.cgi?component=Nfv-Openapis&list_id=61&product=NFV&resolution=\n", + "license": { + "name": "ETSI Forge copyright notice", + "url": "https://forge.etsi.org/etsi-forge-copyright-notice.txt" + } + }, + "externalDocs": { + "description": "ETSI GS NFV-SOL 003 V2.5.1", + "url": "https://www.etsi.org/deliver/etsi_gs/NFV-SOL/001_099/003/02.05.01_60/gs_nfv-sol003v020501p.pdf" + }, + "basePath": "/vnfpkgm/v1", + "schemes": [ + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/api-versions": { + "parameters": [ + { + "name": "Version", + "description": "Version of the API requested to use when responding to this request.\n", + "in": "header", + "required": false, + "type": "string" + } + ], + "get": { + "summary": "Retrieve API version information", + "description": "The GET method reads API version information. This method shall follow the provisions specified in table 4.6.3.3.3.2-1 for request and response data structures, and response codes. URI query parameters are not supported.\n", + "responses": { + "200": { + "description": "200 OK\nAPI version information was read successfully. The response body shall contain 4.4 API version information, as defined in clause 4.4.1.13.\n", + "schema": { + "description": "This type represents API version information. It shall comply with the provisions defined in table 4.4.1.13-1 (SOL003).\n", + "type": "object", + "required": [ + "uriPrefix", + "apiVersions" + ], + "properties": { + "uriPrefix": { + "description": "Specifies the URI prefix for the API, in the following form {apiRoot}/{apiName}/{apiMajorVersion}/\n", + "type": "string" + }, + "apiVersions": { + "description": "Version(s) supported for the API signaled by the uriPrefix attribute.\n", + "type": "array", + "items": { + "type": "object", + "required": [ + "version" + ], + "properties": { + "version": { + "description": "Identifies a supported version. The value of the version attribute shall be a version identifier as specified in clause 4.6.1.\n", + "type": "string" + }, + "isDeprecated": { + "description": "If such information is available, this attribute indicates whether use of the version signaled by the version attribute is deprecated (true) or not (false). A deprecated version is still supported by the API producer but is recommended not to be used any longer. When a version is no longer supported, it does not appear in the response body.\n", + "type": "boolean" + }, + "retirementDate": { + "description": "Date-time stamp. Representation: String formatted according to IETF RFC 3339.\n", + "type": "string", + "format": "date-time" + } + } + } + } + } + }, + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "Version": { + "description": "The used API version.", + "type": "string", + "maximum": 1, + "minimum": 1 + } + } + }, + "400": { + "description": "400 BAD REQUEST\n400 code can be returned in the following specified cases, the specific cause has to be proper specified in the \"ProblemDetails\" structure to be returned.\nIf the request is malformed or syntactically incorrect (e.g. if the request URI contains incorrect query parameters or the payload body contains a syntactically incorrect data structure), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and should include in the \"detail\" attribute more information about the source of the problem.\nIf the response to a GET request which queries a container resource would be so big that the performance of the API producer is adversely affected, and the API producer does not support paging for the affected resource, it shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and should include in the \"detail\" attribute more information about the source of the problem.\nIf there is an application error related to the client's input that cannot be easily mapped to any other HTTP response code (\"catch all error\"), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and shall include in the \"detail\" attribute more information about the source of the problem.\nIf the request contains a malformed access token, the API producer should respond with this response. The details of the error shall be returned in the WWW Authenticate HTTP header, as defined in IETF RFC 6750 and IETF RFC 7235. The ProblemDetails structure may be provided.\nThe use of this HTTP error response code described above is applicable to the use of the OAuth 2.0 for the authorization of API requests and notifications, as defined in clauses 4.5.3.3 and 4.5.3.4.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "401": { + "description": "401 UNAUTHORIZED\nIf the request contains no access token even though one is required, or if the request contains an authorization token that is invalid (e.g. expired or revoked), the API producer should respond with this response. The details of the error shall be returned in the WWW-Authenticate HTTP header, as defined in IETF RFC 6750 and IETF RFC 7235. The ProblemDetails structure may be provided.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "403": { + "description": "403 FORBIDDEN\nIf the API consumer is not allowed to perform a particular request to a particular resource, the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided. It should include in the \"detail\" attribute information about the source of the problem, and may indicate how to solve it.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "404": { + "description": "404 NOT FOUND\nIf the API producer did not find a current representation for the resource addressed by the URI passed in the request or is not willing to disclose that one exists, it shall respond with this response code. The \"ProblemDetails\" structure may be provided, including in the \"detail\" attribute information about the source of the problem, e.g. a wrong resource URI variable.\nThis response code is not appropriate in case the resource addressed by the URI is a container resource which is designed to contain child resources, but does not contain any child resource at the time the request is received. For a GET request to an existing empty container resource, a typical response contains a 200 OK response code and a payload body with an empty array.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "405": { + "description": "405 METHOD NOT ALLOWED\nIf a particular HTTP method is not supported for a particular resource, the API producer shall respond with this response code. The \"ProblemDetails\" structure may be omitted.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "406": { + "description": "406 NOT ACCEPTABLE\nIf the \"Accept\" header does not contain at least one name of a content type that is acceptable to the API producer, the API producer shall respond with this response code. The \"ProblemDetails\" structure may be omitted.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "413": { + "description": "413 PAYLOAD TOO LARGE\nIf the payload body of a request is larger than the amount of data the API producer is willing or able to process, it shall respond with this response code, following the provisions in IETF RFC 7231 for the use of the \"Retry-After\" HTTP header and for closing the connection. The \"ProblemDetails\" structure may be omitted.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "414": { + "description": "414 URI TOO LONG\nIf the request URI of a request is longer than the API producer is willing or able to process, it shall respond with this response code. This condition can e.g. be caused by passing long queries in the request URI of a GET request. The \"ProblemDetails\" structure may be omitted.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "416": { + "description": "416 RANGE NOT SATISFIABLE\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "422": { + "description": "422 UNPROCESSABLE ENTITY\nIf the payload body of a request contains syntactically correct data (e.g. well-formed JSON) but the data cannot be processed (e.g. because it fails validation against a schema), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and should include in the \"detail\" attribute more information about the source of the problem.\nThis error response code is only applicable for methods that have a request body.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "429": { + "description": "429 TOO MANY REQUESTS\nIf the API consumer has sent too many requests in a defined period of time and the API producer is able to detect that condition (\"rate limiting\"), the API producer shall respond with this response code, following the provisions in IETF RFC 6585 [17] for the use of the \"Retry-After\" HTTP header. The \"ProblemDetails\" structure shall be provided and shall include in the \"detail\" attribute more information about the source of the problem.\nThe period of time and allowed number of requests are configured within the API producer by means outside the scope of the present document.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "500": { + "description": "500 INTERNAL SERVER ERROR\nIf there is an application error not related to the client's input that cannot be easily mapped to any other HTTP response code (\"catch all error\"), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and shall include in the \"detail\" attribute more information about the source of the problem.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "503": { + "description": "503 SERVICE UNAVAILABLE\nIf the API producer encounters an internal overload situation of itself or of a system it relies on, it should respond with this response code, following the provisions in IETF RFC 7231 for the use of the \"Retry-After\" HTTP header and for the alternative to refuse the connection. The \"ProblemDetails\" structure may be omitted.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "504": { + "description": "504 GATEWAY TIMEOUT\nIf the API producer encounters a timeout while waiting for a response from an upstream server (i.e. a server that the API producer communicates with when fulfilling a request), it should respond with this response code.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + } + } + } + }, + "/vnf_packages": { + "get": { + "description": "Query VNF Package Info\n\nThe GET method queries the information of the VNF packages matching the filter.\n", + "parameters": [ + { + "name": "Accept", + "description": "Content-Types that are acceptable for the response. Reference: IETF RFC 7231\n", + "in": "header", + "required": true, + "type": "string" + }, + { + "name": "Authorization", + "description": "The authorization token for the request. Reference: IETF RFC 7235\n", + "in": "header", + "required": false, + "type": "string" + }, + { + "name": "filter", + "description": "Attribute-based filtering expression according to clause 4.3.2. The VNFM shall support receiving this parameter as part of the URI query string. The NFVO may supply this parameter. All attribute names that appear in the VnfPkgInfo and in data types referenced from it shall be supported by the VNFM in the filter expression.\n", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "all_fields", + "description": "Include all complex attributes in the response. See clause 4.3.3 for details. The VNFM shall support this parameter.\n", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "fields", + "description": "Complex attributes to be included into the response. See clause 4.3.3 for details. The VNFM should support this parameter.\n", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "exclude_fields", + "description": "Complex attributes to be excluded from the response. See clause 4.3.3 for details. The VNFM should support this parameter.\n", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "exclude_default", + "description": "Indicates to exclude the following complex attributes from the response. See clause 4.3.3 for details. The VNFM shall support this parameter. The following attributes shall be excluded from the VnfPkgInfo structure in the response body if this parameter is provided, or none of the parameters \"all_fields,\" \"fields\", \"exclude_fields\", \"exclude_default\" are provided: -\tsoftwareImages -\tadditionalArtifacts -\tuserDefinedData.\n", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "nextpage_opaque_marker", + "description": "Marker to obtain the next page of a paged response. Shall be supported by the VNFM if the VNFM supports alternative 2 (paging) according to clause 4.7.2.1 for this resource.\n", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "Version", + "description": "Version of the API requested to use when responding to this request.\n", + "in": "header", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "200 OK\nInformation about zero or more VNF packages was queried successfully. The response body shall contain in an array the VNF package info representations that match the attribute filter, i.e. zero or more VNF package representations as defined in clause 10.5.2.2. If the VNFM supports alternative 2 (paging) according to clause 4.7.2.1 for this resource, inclusion of the Link HTTP header in this response shall follow the provisions in clause 4.7.2.3.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "Link": { + "description": "Reference to other resources. Used for paging in the present document, see clause 4.7.2.1.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + } + }, + "schema": { + "type": "array", + "items": { + "description": "This type represents the information of an VNF package.\n", + "type": "object", + "required": [ + "id", + "operationalState", + "usageState", + "_links" + ], + "properties": { + "id": { + "description": "An identifier with the intention of being globally unique.\n", + "type": "string" + }, + "vnfdId": { + "description": "An identifier with the intention of being globally unique.\n", + "type": "string" + }, + "vnfProvider": { + "description": "Provider of the VNF package and the VNFD. This information is copied from the VNFD.\n", + "type": "string" + }, + "vnfProductName": { + "description": "Name to identify the VNF product. Invariant for the VNF product lifetime. This information is copied from the VNFD. It shall be present after the VNF package content has been on-boarded and absent otherwise.\n", + "type": "string" + }, + "vnfSoftwareVersion": { + "description": "A Version.\n", + "type": "string" + }, + "vnfdVersion": { + "description": "A Version.\n", + "type": "string" + }, + "checksum": { + "description": "This type represents the checksum of a VNF package or an artifact file.\n", + "type": "object", + "required": [ + "algorithm", + "hash" + ], + "properties": { + "algorithm": { + "description": "Name of the algorithm used to generate the checksum, as defined in ETSI GS NFV-SOL 004. For example, SHA-256, SHA-512.\n", + "type": "string" + }, + "hash": { + "description": "The hexadecimal value of the checksum.\n", + "type": "string" + } + } + }, + "softwareImages": { + "description": "Information about VNF package artifacts that are software images. This attribute shall not be present before the VNF package content is on-boarded. Otherwise, this attribute shall be present unless it has been requested to be excluded per attribute selector.\n", + "type": "array", + "items": { + "description": "This type represents an artifact contained in a VNF package which represents a software image.\n", + "type": "object", + "required": [ + "id", + "name", + "provider", + "version", + "checksum", + "containerFormat", + "diskFormat", + "createdAt", + "minDisk", + "minRam", + "size", + "imagePath" + ], + "properties": { + "id": { + "description": "An identifier that is unique within a VNF descriptor.\n", + "type": "string" + }, + "name": { + "description": "Name of the software image.\n", + "type": "string" + }, + "provider": { + "description": "Provider of the software image.\n", + "type": "string" + }, + "version": { + "description": "A Version.\n", + "type": "string" + }, + "checksum": { + "description": "This type represents the checksum of a VNF package or an artifact file.\n", + "type": "object", + "required": [ + "algorithm", + "hash" + ], + "properties": { + "algorithm": { + "description": "Name of the algorithm used to generate the checksum, as defined in ETSI GS NFV-SOL 004. For example, SHA-256, SHA-512.\n", + "type": "string" + }, + "hash": { + "description": "The hexadecimal value of the checksum.\n", + "type": "string" + } + } + }, + "containerFormat": { + "description": "Container format indicates whether the software image is in a file format that also contains metadata about the actual software. Permitted values: - AKI: a kernel image format - AMI: a machine image format - ARI: a ramdisk image format - BARE: the image does not have a container or metadata envelope - DOCKER: docker container format - OVA: OVF package in a tarfile - OVF: OVF container format The list of permitted values was taken from \"Container formats\" in http://docs.openstack.org/image-guide/image-formats.html\n", + "type": "string", + "enum": [ + "AKI", + "AMI", + "ARI", + "BARE", + "DOCKER", + "OVA", + "OVF" + ] + }, + "diskFormat": { + "description": "Disk format of a software image is the format of the underlying disk image. Permitted values: - AKI: a kernel image format - AMI: a machine image format - ARI: a ramdisk image format - ISO: an archive format for the data contents of an optical disc, such as CD-ROM\n- QCOW2: a common disk image format, which can expand dynamically and supports copy on write\n- RAW: an unstructured disk image format - VDI: a common disk image format - VHD: a common disk image format - VHDX: enhanced version of VHD format - VMDK: a common disk image format The list of permitted values was adapted from \"Disk formats\" in http://docs.openstack.org/image-guide/image-formats.html\n", + "type": "string", + "enum": [ + "AKI", + "AMI", + "ISO", + "QCOW2", + "RAW", + "VDI", + "VHD", + "VHDX", + "VMDK" + ] + }, + "createdAt": { + "description": "Date-time stamp. Representation: String formatted according to IETF RFC 3339.\n", + "type": "string", + "format": "date-time" + }, + "minDisk": { + "description": "The minimal disk for this software image in bytes.\n", + "type": "integer" + }, + "minRam": { + "description": "The minimal RAM for this software image in bytes.\n", + "type": "integer" + }, + "size": { + "description": "Size of this software image in bytes.\n", + "type": "integer" + }, + "userMetadata": { + "description": "This type represents a list of key-value pairs. The order of the pairs in the list is not significant. In JSON, a set of key- value pairs is represented as an object. It shall comply with the provisions defined in clause 4 of IETF RFC 7159.\n", + "type": "object" + }, + "imagePath": { + "description": "Path in the VNF package, which identifies the image artifact and also allows to access a copy of the image artifact.\n", + "type": "string" + } + } + } + }, + "additionalArtifacts": { + "description": "Information about VNF package artifacts contained in the VNF package that are not software images. This attribute shall not be present before the VNF package content is on-boarded. Otherwise, this attribute shall be present if the VNF package contains additional artifacts.\n", + "type": "array", + "items": { + "description": "This type represents an artifact other than a software image which is contained in a VNF package.\n", + "type": "object", + "required": [ + "artifactPath", + "checksum" + ], + "properties": { + "artifactPath": { + "description": "Path in the VNF package, which identifies the artifact and also allows to access a copy of the artifact.\n", + "type": "string" + }, + "checksum": { + "description": "This type represents the checksum of a VNF package or an artifact file.\n", + "type": "object", + "required": [ + "algorithm", + "hash" + ], + "properties": { + "algorithm": { + "description": "Name of the algorithm used to generate the checksum, as defined in ETSI GS NFV-SOL 004. For example, SHA-256, SHA-512.\n", + "type": "string" + }, + "hash": { + "description": "The hexadecimal value of the checksum.\n", + "type": "string" + } + } + }, + "metadata": { + "description": "This type represents a list of key-value pairs. The order of the pairs in the list is not significant. In JSON, a set of key- value pairs is represented as an object. It shall comply with the provisions defined in clause 4 of IETF RFC 7159.\n", + "type": "object" + } + } + } + }, + "onboardingState": { + "description": "CREATED: The VNF package resource has been created. UPLOADING: The associated VNF package content is being uploaded. PROCESSING: The associated VNF package content is being processed, e.g., validation.\nONBOARDED: The associated VNF package content has been successfully on-boarded.\n", + "type": "string", + "enum": [ + "CREATED", + "UPLOADING", + "PROCESSING", + "ONBOARDED" + ] + }, + "operationalState": { + "description": "- ENABLED: The VNF package is enabled, i.e. it can be used for instantiation of new VNF instances.\n- DISABLED: The VNF package is disabled, i.e. it cannot be used for further VNF instantiation requests (unless and until the VNF package\n is re-enabled).\n", + "type": "string", + "enum": [ + "ENABLED", + "DISABLED" + ] + }, + "usageState": { + "description": "- IN_USE: VNF instances instantiated from this VNF package exist. - NOT_IN_USE: No existing VNF instance is instantiated from this VNF package.\n" + }, + "userDefinedData": { + "description": "This type represents a list of key-value pairs. The order of the pairs in the list is not significant. In JSON, a set of key- value pairs is represented as an object. It shall comply with the provisions defined in clause 4 of IETF RFC 7159.\n", + "type": "object" + }, + "_links": { + "description": "Links to resources related to this resource.\n", + "type": "object", + "required": [ + "self", + "packageContent" + ], + "properties": { + "self": { + "description": "This type represents a link to a resource using an absolute URI. It shall comply with the provisions defined in table 4.4.1.3-1.\n", + "type": "object", + "required": [ + "href" + ], + "properties": { + "href": { + "description": "String formatted according to IETF RFC 3986.\n", + "type": "string" + } + } + }, + "vnfd": { + "description": "This type represents a link to a resource using an absolute URI. It shall comply with the provisions defined in table 4.4.1.3-1.\n", + "type": "object", + "required": [ + "href" + ], + "properties": { + "href": { + "description": "String formatted according to IETF RFC 3986.\n", + "type": "string" + } + } + }, + "packageContent": { + "description": "This type represents a link to a resource using an absolute URI. It shall comply with the provisions defined in table 4.4.1.3-1.\n", + "type": "object", + "required": [ + "href" + ], + "properties": { + "href": { + "description": "String formatted according to IETF RFC 3986.\n", + "type": "string" + } + } + } + } + } + } + } + } + }, + "400": { + "description": "400 BAD REQUEST\n400 code can be returned in the following specified cases, the specific cause has to be proper specified in the \"ProblemDetails\" structure to be returned.\nIf the request is malformed or syntactically incorrect (e.g. if the request URI contains incorrect query parameters or the payload body contains a syntactically incorrect data structure), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and should include in the \"detail\" attribute more information about the source of the problem.\nIf the response to a GET request which queries a container resource would be so big that the performance of the API producer is adversely affected, and the API producer does not support paging for the affected resource, it shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and should include in the \"detail\" attribute more information about the source of the problem.\nIf there is an application error related to the client's input that cannot be easily mapped to any other HTTP response code (\"catch all error\"), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and shall include in the \"detail\" attribute more information about the source of the problem.\nIf the request contains a malformed access token, the API producer should respond with this response. The details of the error shall be returned in the WWW Authenticate HTTP header, as defined in IETF RFC 6750 and IETF RFC 7235. The ProblemDetails structure may be provided.\nThe use of this HTTP error response code described above is applicable to the use of the OAuth 2.0 for the authorization of API requests and notifications, as defined in clauses 4.5.3.3 and 4.5.3.4.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "401": { + "description": "401 UNAUTHORIZED\nIf the request contains no access token even though one is required, or if the request contains an authorization token that is invalid (e.g. expired or revoked), the API producer should respond with this response. The details of the error shall be returned in the WWW-Authenticate HTTP header, as defined in IETF RFC 6750 and IETF RFC 7235. The ProblemDetails structure may be provided.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "403": { + "description": "403 FORBIDDEN\nIf the API consumer is not allowed to perform a particular request to a particular resource, the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided. It should include in the \"detail\" attribute information about the source of the problem, and may indicate how to solve it.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "404": { + "description": "404 NOT FOUND\nIf the API producer did not find a current representation for the resource addressed by the URI passed in the request or is not willing to disclose that one exists, it shall respond with this response code. The \"ProblemDetails\" structure may be provided, including in the \"detail\" attribute information about the source of the problem, e.g. a wrong resource URI variable.\nThis response code is not appropriate in case the resource addressed by the URI is a container resource which is designed to contain child resources, but does not contain any child resource at the time the request is received. For a GET request to an existing empty container resource, a typical response contains a 200 OK response code and a payload body with an empty array.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "405": { + "description": "404 NOT FOUND\nIf the API producer did not find a current representation for the resource addressed by the URI passed in the request or is not willing to disclose that one exists, it shall respond with this response code. The \"ProblemDetails\" structure may be provided, including in the \"detail\" attribute information about the source of the problem, e.g. a wrong resource URI variable.\nThis response code is not appropriate in case the resource addressed by the URI is a container resource which is designed to contain child resources, but does not contain any child resource at the time the request is received. For a GET request to an existing empty container resource, a typical response contains a 200 OK response code and a payload body with an empty array.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "406": { + "description": "406 NOT ACCEPTABLE\nIf the \"Accept\" header does not contain at least one name of a content type that is acceptable to the API producer, the API producer shall respond with this response code. The \"ProblemDetails\" structure may be omitted.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "416": { + "description": "416 RANGE NOT SATISFIABLE\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "500": { + "description": "500 INTERNAL SERVER ERROR\nIf there is an application error not related to the client's input that cannot be easily mapped to any other HTTP response code (\"catch all error\"), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and shall include in the \"detail\" attribute more information about the source of the problem.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "503": { + "description": "503 SERVICE UNAVAILABLE\nIf the API producer encounters an internal overload situation of itself or of a system it relies on, it should respond with this response code, following the provisions in IETF RFC 7231 for the use of the \"Retry-After\" HTTP header and for the alternative to refuse the connection. The \"ProblemDetails\" structure may be omitted.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + } + } + } + }, + "/vnf_packages/{vnfPkgId}": { + "parameters": [ + { + "name": "vnfPkgId", + "description": "Identifier of the VNF package. The identifier is allocated by the NFVO. This identifier can be retrieved from the \"vnfPkgId\" attribute in the VnfPackageOnboardingNotification or VnfPackageChangeNotification.\n", + "in": "path", + "type": "string", + "required": true + } + ], + "get": { + "description": "Query VNF Package Info\n\nThe GET method reads the information of an individual VNF package.\n", + "parameters": [ + { + "name": "Accept", + "description": "Content-Types that are acceptable for the response. Reference: IETF RFC 7231\n", + "in": "header", + "required": true, + "type": "string" + }, + { + "name": "Authorization", + "description": "The authorization token for the request. Reference: IETF RFC 7235\n", + "in": "header", + "required": false, + "type": "string" + }, + { + "name": "Version", + "description": "Version of the API requested to use when responding to this request.\n", + "in": "header", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "200 OK\nInformation of the selected VNF packages.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "This type represents the information of an VNF package.\n", + "type": "object", + "required": [ + "id", + "operationalState", + "usageState", + "_links" + ], + "properties": { + "id": { + "description": "An identifier with the intention of being globally unique.\n", + "type": "string" + }, + "vnfdId": { + "description": "An identifier with the intention of being globally unique.\n", + "type": "string" + }, + "vnfProvider": { + "description": "Provider of the VNF package and the VNFD. This information is copied from the VNFD.\n", + "type": "string" + }, + "vnfProductName": { + "description": "Name to identify the VNF product. Invariant for the VNF product lifetime. This information is copied from the VNFD. It shall be present after the VNF package content has been on-boarded and absent otherwise.\n", + "type": "string" + }, + "vnfSoftwareVersion": { + "description": "A Version.\n", + "type": "string" + }, + "vnfdVersion": { + "description": "A Version.\n", + "type": "string" + }, + "checksum": { + "description": "This type represents the checksum of a VNF package or an artifact file.\n", + "type": "object", + "required": [ + "algorithm", + "hash" + ], + "properties": { + "algorithm": { + "description": "Name of the algorithm used to generate the checksum, as defined in ETSI GS NFV-SOL 004. For example, SHA-256, SHA-512.\n", + "type": "string" + }, + "hash": { + "description": "The hexadecimal value of the checksum.\n", + "type": "string" + } + } + }, + "softwareImages": { + "description": "Information about VNF package artifacts that are software images. This attribute shall not be present before the VNF package content is on-boarded. Otherwise, this attribute shall be present unless it has been requested to be excluded per attribute selector.\n", + "type": "array", + "items": { + "description": "This type represents an artifact contained in a VNF package which represents a software image.\n", + "type": "object", + "required": [ + "id", + "name", + "provider", + "version", + "checksum", + "containerFormat", + "diskFormat", + "createdAt", + "minDisk", + "minRam", + "size", + "imagePath" + ], + "properties": { + "id": { + "description": "An identifier that is unique within a VNF descriptor.\n", + "type": "string" + }, + "name": { + "description": "Name of the software image.\n", + "type": "string" + }, + "provider": { + "description": "Provider of the software image.\n", + "type": "string" + }, + "version": { + "description": "A Version.\n", + "type": "string" + }, + "checksum": { + "description": "This type represents the checksum of a VNF package or an artifact file.\n", + "type": "object", + "required": [ + "algorithm", + "hash" + ], + "properties": { + "algorithm": { + "description": "Name of the algorithm used to generate the checksum, as defined in ETSI GS NFV-SOL 004. For example, SHA-256, SHA-512.\n", + "type": "string" + }, + "hash": { + "description": "The hexadecimal value of the checksum.\n", + "type": "string" + } + } + }, + "containerFormat": { + "description": "Container format indicates whether the software image is in a file format that also contains metadata about the actual software. Permitted values: - AKI: a kernel image format - AMI: a machine image format - ARI: a ramdisk image format - BARE: the image does not have a container or metadata envelope - DOCKER: docker container format - OVA: OVF package in a tarfile - OVF: OVF container format The list of permitted values was taken from \"Container formats\" in http://docs.openstack.org/image-guide/image-formats.html\n", + "type": "string", + "enum": [ + "AKI", + "AMI", + "ARI", + "BARE", + "DOCKER", + "OVA", + "OVF" + ] + }, + "diskFormat": { + "description": "Disk format of a software image is the format of the underlying disk image. Permitted values: - AKI: a kernel image format - AMI: a machine image format - ARI: a ramdisk image format - ISO: an archive format for the data contents of an optical disc, such as CD-ROM\n- QCOW2: a common disk image format, which can expand dynamically and supports copy on write\n- RAW: an unstructured disk image format - VDI: a common disk image format - VHD: a common disk image format - VHDX: enhanced version of VHD format - VMDK: a common disk image format The list of permitted values was adapted from \"Disk formats\" in http://docs.openstack.org/image-guide/image-formats.html\n", + "type": "string", + "enum": [ + "AKI", + "AMI", + "ISO", + "QCOW2", + "RAW", + "VDI", + "VHD", + "VHDX", + "VMDK" + ] + }, + "createdAt": { + "description": "Date-time stamp. Representation: String formatted according to IETF RFC 3339.\n", + "type": "string", + "format": "date-time" + }, + "minDisk": { + "description": "The minimal disk for this software image in bytes.\n", + "type": "integer" + }, + "minRam": { + "description": "The minimal RAM for this software image in bytes.\n", + "type": "integer" + }, + "size": { + "description": "Size of this software image in bytes.\n", + "type": "integer" + }, + "userMetadata": { + "description": "This type represents a list of key-value pairs. The order of the pairs in the list is not significant. In JSON, a set of key- value pairs is represented as an object. It shall comply with the provisions defined in clause 4 of IETF RFC 7159.\n", + "type": "object" + }, + "imagePath": { + "description": "Path in the VNF package, which identifies the image artifact and also allows to access a copy of the image artifact.\n", + "type": "string" + } + } + } + }, + "additionalArtifacts": { + "description": "Information about VNF package artifacts contained in the VNF package that are not software images. This attribute shall not be present before the VNF package content is on-boarded. Otherwise, this attribute shall be present if the VNF package contains additional artifacts.\n", + "type": "array", + "items": { + "description": "This type represents an artifact other than a software image which is contained in a VNF package.\n", + "type": "object", + "required": [ + "artifactPath", + "checksum" + ], + "properties": { + "artifactPath": { + "description": "Path in the VNF package, which identifies the artifact and also allows to access a copy of the artifact.\n", + "type": "string" + }, + "checksum": { + "description": "This type represents the checksum of a VNF package or an artifact file.\n", + "type": "object", + "required": [ + "algorithm", + "hash" + ], + "properties": { + "algorithm": { + "description": "Name of the algorithm used to generate the checksum, as defined in ETSI GS NFV-SOL 004. For example, SHA-256, SHA-512.\n", + "type": "string" + }, + "hash": { + "description": "The hexadecimal value of the checksum.\n", + "type": "string" + } + } + }, + "metadata": { + "description": "This type represents a list of key-value pairs. The order of the pairs in the list is not significant. In JSON, a set of key- value pairs is represented as an object. It shall comply with the provisions defined in clause 4 of IETF RFC 7159.\n", + "type": "object" + } + } + } + }, + "onboardingState": { + "description": "CREATED: The VNF package resource has been created. UPLOADING: The associated VNF package content is being uploaded. PROCESSING: The associated VNF package content is being processed, e.g., validation.\nONBOARDED: The associated VNF package content has been successfully on-boarded.\n", + "type": "string", + "enum": [ + "CREATED", + "UPLOADING", + "PROCESSING", + "ONBOARDED" + ] + }, + "operationalState": { + "description": "- ENABLED: The VNF package is enabled, i.e. it can be used for instantiation of new VNF instances.\n- DISABLED: The VNF package is disabled, i.e. it cannot be used for further VNF instantiation requests (unless and until the VNF package\n is re-enabled).\n", + "type": "string", + "enum": [ + "ENABLED", + "DISABLED" + ] + }, + "usageState": { + "description": "- IN_USE: VNF instances instantiated from this VNF package exist. - NOT_IN_USE: No existing VNF instance is instantiated from this VNF package.\n" + }, + "userDefinedData": { + "description": "This type represents a list of key-value pairs. The order of the pairs in the list is not significant. In JSON, a set of key- value pairs is represented as an object. It shall comply with the provisions defined in clause 4 of IETF RFC 7159.\n", + "type": "object" + }, + "_links": { + "description": "Links to resources related to this resource.\n", + "type": "object", + "required": [ + "self", + "packageContent" + ], + "properties": { + "self": { + "description": "This type represents a link to a resource using an absolute URI. It shall comply with the provisions defined in table 4.4.1.3-1.\n", + "type": "object", + "required": [ + "href" + ], + "properties": { + "href": { + "description": "String formatted according to IETF RFC 3986.\n", + "type": "string" + } + } + }, + "vnfd": { + "description": "This type represents a link to a resource using an absolute URI. It shall comply with the provisions defined in table 4.4.1.3-1.\n", + "type": "object", + "required": [ + "href" + ], + "properties": { + "href": { + "description": "String formatted according to IETF RFC 3986.\n", + "type": "string" + } + } + }, + "packageContent": { + "description": "This type represents a link to a resource using an absolute URI. It shall comply with the provisions defined in table 4.4.1.3-1.\n", + "type": "object", + "required": [ + "href" + ], + "properties": { + "href": { + "description": "String formatted according to IETF RFC 3986.\n", + "type": "string" + } + } + } + } + } + } + } + }, + "400": { + "description": "400 BAD REQUEST\n400 code can be returned in the following specified cases, the specific cause has to be proper specified in the \"ProblemDetails\" structure to be returned.\nIf the request is malformed or syntactically incorrect (e.g. if the request URI contains incorrect query parameters or the payload body contains a syntactically incorrect data structure), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and should include in the \"detail\" attribute more information about the source of the problem.\nIf the response to a GET request which queries a container resource would be so big that the performance of the API producer is adversely affected, and the API producer does not support paging for the affected resource, it shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and should include in the \"detail\" attribute more information about the source of the problem.\nIf there is an application error related to the client's input that cannot be easily mapped to any other HTTP response code (\"catch all error\"), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and shall include in the \"detail\" attribute more information about the source of the problem.\nIf the request contains a malformed access token, the API producer should respond with this response. The details of the error shall be returned in the WWW Authenticate HTTP header, as defined in IETF RFC 6750 and IETF RFC 7235. The ProblemDetails structure may be provided.\nThe use of this HTTP error response code described above is applicable to the use of the OAuth 2.0 for the authorization of API requests and notifications, as defined in clauses 4.5.3.3 and 4.5.3.4.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "401": { + "description": "401 UNAUTHORIZED\nIf the request contains no access token even though one is required, or if the request contains an authorization token that is invalid (e.g. expired or revoked), the API producer should respond with this response. The details of the error shall be returned in the WWW-Authenticate HTTP header, as defined in IETF RFC 6750 and IETF RFC 7235. The ProblemDetails structure may be provided.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "403": { + "description": "403 FORBIDDEN\nIf the API consumer is not allowed to perform a particular request to a particular resource, the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided. It should include in the \"detail\" attribute information about the source of the problem, and may indicate how to solve it.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "404": { + "description": "404 NOT FOUND\nIf the API producer did not find a current representation for the resource addressed by the URI passed in the request or is not willing to disclose that one exists, it shall respond with this response code. The \"ProblemDetails\" structure may be provided, including in the \"detail\" attribute information about the source of the problem, e.g. a wrong resource URI variable.\nThis response code is not appropriate in case the resource addressed by the URI is a container resource which is designed to contain child resources, but does not contain any child resource at the time the request is received. For a GET request to an existing empty container resource, a typical response contains a 200 OK response code and a payload body with an empty array.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "405": { + "description": "404 NOT FOUND\nIf the API producer did not find a current representation for the resource addressed by the URI passed in the request or is not willing to disclose that one exists, it shall respond with this response code. The \"ProblemDetails\" structure may be provided, including in the \"detail\" attribute information about the source of the problem, e.g. a wrong resource URI variable.\nThis response code is not appropriate in case the resource addressed by the URI is a container resource which is designed to contain child resources, but does not contain any child resource at the time the request is received. For a GET request to an existing empty container resource, a typical response contains a 200 OK response code and a payload body with an empty array.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "406": { + "description": "406 NOT ACCEPTABLE\nIf the \"Accept\" header does not contain at least one name of a content type that is acceptable to the API producer, the API producer shall respond with this response code. The \"ProblemDetails\" structure may be omitted.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "416": { + "description": "416 RANGE NOT SATISFIABLE\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "500": { + "description": "500 INTERNAL SERVER ERROR\nIf there is an application error not related to the client's input that cannot be easily mapped to any other HTTP response code (\"catch all error\"), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and shall include in the \"detail\" attribute more information about the source of the problem.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "503": { + "description": "503 SERVICE UNAVAILABLE\nIf the API producer encounters an internal overload situation of itself or of a system it relies on, it should respond with this response code, following the provisions in IETF RFC 7231 for the use of the \"Retry-After\" HTTP header and for the alternative to refuse the connection. The \"ProblemDetails\" structure may be omitted.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + } + } + } + }, + "/vnf_packages/{vnfPkgId}/vnfd": { + "parameters": [ + { + "name": "vnfPkgId", + "description": "Identifier of the on-boarded VNF package. The identifier is allocated by the NFVO. This identifier can be retrieved from the \"vnfPkgId\" attribute in the VnfPackageOnboardingNotification or VnfPackageChangeNotification.\n", + "in": "path", + "type": "string", + "required": true + } + ], + "get": { + "description": "Query VNF Package Info\n\nThe GET method reads the content of the VNFD within a VNF package. The VNFD can be implemented as a single file or as a collection of multiple files. If the VNFD is implemented in the form of multiple files, a ZIP file embedding these files shall be returned. If the VNFD is implemented as a single file, either that file or a ZIP file embedding that file shall be returned. The selection of the format is controlled by the \"Accept\" HTTP header passed in the GET request. * If the \"Accept\" header contains only \"text/plain\" and the VNFD is implemented as a single file, the file shall be returned;\n otherwise, an error message shall be returned.\n* If the \"Accept\" header contains only \"application/zip\", the single file or the multiple files that make up the VNFD shall be returned\n embedded in a ZIP file.\n* If the \"Accept\" header contains both \"text/plain\" and \"application/zip\", it is up to the NFVO to choose the format to\n return for a single-file VNFD; for a multi-file VNFD, a ZIP file\n shall be returned.\nThe default format of the ZIP file shall be the one specified in ETSI GS NFV-SOL 004 where only the YAML files representing the VNFD, and information needed to navigate the ZIP file and to identify the file that is the entry point for parsing the VNFD (such as TOSCA-meta or manifest files or naming conventions) are included.\n", + "parameters": [ + { + "name": "Accept", + "description": "Content-Types that are acceptable for the response. Permitted values: \"text/plain\" and/or \"application/zip\" Reference: IETF RFC 7231\n", + "in": "header", + "required": true, + "type": "string", + "enum": [ + "text/plain", + "application/zip", + "text/plain+application/zip" + ] + }, + { + "name": "Authorization", + "description": "The authorization token for the request. Reference: IETF RFC 7235\n", + "in": "header", + "required": false, + "type": "string" + }, + { + "name": "Version", + "description": "Version of the API requested to use when responding to this request.\n", + "in": "header", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "200 OK\nOn success, the content of the VNFD is returned. The payload body shall contain a copy of the file representing the VNFD or a ZIP file that contains the file or multiple files representing the VNFD, as specified above. The \"Content-Type\" HTTP header shall be set according to the format of the returned file, i.e. to \"text/plain\" for a YAML file or to \"application/zip\" for a ZIP file.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "enum": [ + "text/plain", + "application/zip" + ], + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + } + }, + "400": { + "description": "400 BAD REQUEST\n400 code can be returned in the following specified cases, the specific cause has to be proper specified in the \"ProblemDetails\" structure to be returned.\nIf the request is malformed or syntactically incorrect (e.g. if the request URI contains incorrect query parameters or the payload body contains a syntactically incorrect data structure), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and should include in the \"detail\" attribute more information about the source of the problem.\nIf the response to a GET request which queries a container resource would be so big that the performance of the API producer is adversely affected, and the API producer does not support paging for the affected resource, it shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and should include in the \"detail\" attribute more information about the source of the problem.\nIf there is an application error related to the client's input that cannot be easily mapped to any other HTTP response code (\"catch all error\"), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and shall include in the \"detail\" attribute more information about the source of the problem.\nIf the request contains a malformed access token, the API producer should respond with this response. The details of the error shall be returned in the WWW Authenticate HTTP header, as defined in IETF RFC 6750 and IETF RFC 7235. The ProblemDetails structure may be provided.\nThe use of this HTTP error response code described above is applicable to the use of the OAuth 2.0 for the authorization of API requests and notifications, as defined in clauses 4.5.3.3 and 4.5.3.4.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "401": { + "description": "401 UNAUTHORIZED\nIf the request contains no access token even though one is required, or if the request contains an authorization token that is invalid (e.g. expired or revoked), the API producer should respond with this response. The details of the error shall be returned in the WWW-Authenticate HTTP header, as defined in IETF RFC 6750 and IETF RFC 7235. The ProblemDetails structure may be provided.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "403": { + "description": "403 FORBIDDEN\nIf the API consumer is not allowed to perform a particular request to a particular resource, the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided. It should include in the \"detail\" attribute information about the source of the problem, and may indicate how to solve it.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "404": { + "description": "404 NOT FOUND\nIf the API producer did not find a current representation for the resource addressed by the URI passed in the request or is not willing to disclose that one exists, it shall respond with this response code. The \"ProblemDetails\" structure may be provided, including in the \"detail\" attribute information about the source of the problem, e.g. a wrong resource URI variable.\nThis response code is not appropriate in case the resource addressed by the URI is a container resource which is designed to contain child resources, but does not contain any child resource at the time the request is received. For a GET request to an existing empty container resource, a typical response contains a 200 OK response code and a payload body with an empty array.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "405": { + "description": "404 NOT FOUND\nIf the API producer did not find a current representation for the resource addressed by the URI passed in the request or is not willing to disclose that one exists, it shall respond with this response code. The \"ProblemDetails\" structure may be provided, including in the \"detail\" attribute information about the source of the problem, e.g. a wrong resource URI variable.\nThis response code is not appropriate in case the resource addressed by the URI is a container resource which is designed to contain child resources, but does not contain any child resource at the time the request is received. For a GET request to an existing empty container resource, a typical response contains a 200 OK response code and a payload body with an empty array.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "406": { + "description": "Not Acceptable\nIf the \"Accept\" header does not contain at least one name of a content type for which the NFVO can provide a representation of the VNFD, the NFVO shall respond with this response code. The \"ProblemDetails\" structure may be included with the \"detail\" attribute providing more information about the error.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "409": { + "description": "Conflict\nError: The operation cannot be executed currently, due to a conflict with the state of the resource. Typically, this is due to the fact that \"onboardingState\" of the VNF package has a value different from \"ONBOARDED\". The response body shall contain a ProblemDetails structure, in which the \"detail\" attribute shall convey more information about the error.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "416": { + "description": "416 RANGE NOT SATISFIABLE\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "500": { + "description": "500 INTERNAL SERVER ERROR\nIf there is an application error not related to the client's input that cannot be easily mapped to any other HTTP response code (\"catch all error\"), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and shall include in the \"detail\" attribute more information about the source of the problem.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "503": { + "description": "503 SERVICE UNAVAILABLE\nIf the API producer encounters an internal overload situation of itself or of a system it relies on, it should respond with this response code, following the provisions in IETF RFC 7231 for the use of the \"Retry-After\" HTTP header and for the alternative to refuse the connection. The \"ProblemDetails\" structure may be omitted.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + } + } + } + }, + "/vnf_packages/{vnfPkgId}/package_content": { + "parameters": [ + { + "name": "vnfPkgId", + "description": "Identifier of the VNF package. The identifier is allocated by the NFVO. This identifier can be retrieved from the \"vnfPkgId\" attribute in the VnfPackageOnboardingNotification or VnfPackageChangeNotification.\n", + "in": "path", + "type": "string", + "required": true + } + ], + "get": { + "description": "Fetch VNF Package\n\nThe GET method fetches the content of a VNF package identified by the VNF package identifier allocated by the NFVO.\n", + "parameters": [ + { + "name": "Accept", + "description": "Content-Types that are acceptable for the response.\n", + "in": "header", + "required": true, + "type": "string", + "enum": [ + "text/plain", + "application/zip" + ] + }, + { + "name": "Authorization", + "description": "The authorization token for the request. Reference: IETF RFC 7235\n", + "in": "header", + "required": false, + "type": "string" + }, + { + "name": "Range", + "description": "The request may contain a \"Range\" HTTP header to obtain single range of bytes from the VNF package file. This can be used to continue an aborted transmission. If the NFVO does not support range requests, it should return the whole file with a 200 OK response instead.\n", + "in": "header", + "type": "string" + }, + { + "name": "Version", + "description": "Version of the API requested to use when responding to this request.\n", + "in": "header", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "200 OK\nOn success, a copy of the VNF package file is returned. The response body shall include a copy of the VNF package file. The \"Content-Type HTTP\" header shall be set according to the type of the file, i.e. to \"application/zip\" for a VNF Package as defined in ETSI GS NFV-SOL 004.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + } + }, + "206": { + "description": "206 PARTIAL CONTENT\nOn success, if the NFVO supports range requests, a single consecutive byte range from the content of the VNF package file is returned. The response body shall contain the requested part of the VNF package file. The \"Content-Range\" HTTP header shall be provided according to IETF RFC 7233. The \"Content-Type\" HTTP header shall be set as defined above for the \"200 OK\" response.\n", + "headers": { + "Content-Range": { + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + } + }, + "400": { + "description": "400 BAD REQUEST\n400 code can be returned in the following specified cases, the specific cause has to be proper specified in the \"ProblemDetails\" structure to be returned.\nIf the request is malformed or syntactically incorrect (e.g. if the request URI contains incorrect query parameters or the payload body contains a syntactically incorrect data structure), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and should include in the \"detail\" attribute more information about the source of the problem.\nIf the response to a GET request which queries a container resource would be so big that the performance of the API producer is adversely affected, and the API producer does not support paging for the affected resource, it shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and should include in the \"detail\" attribute more information about the source of the problem.\nIf there is an application error related to the client's input that cannot be easily mapped to any other HTTP response code (\"catch all error\"), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and shall include in the \"detail\" attribute more information about the source of the problem.\nIf the request contains a malformed access token, the API producer should respond with this response. The details of the error shall be returned in the WWW Authenticate HTTP header, as defined in IETF RFC 6750 and IETF RFC 7235. The ProblemDetails structure may be provided.\nThe use of this HTTP error response code described above is applicable to the use of the OAuth 2.0 for the authorization of API requests and notifications, as defined in clauses 4.5.3.3 and 4.5.3.4.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "401": { + "description": "401 UNAUTHORIZED\nIf the request contains no access token even though one is required, or if the request contains an authorization token that is invalid (e.g. expired or revoked), the API producer should respond with this response. The details of the error shall be returned in the WWW-Authenticate HTTP header, as defined in IETF RFC 6750 and IETF RFC 7235. The ProblemDetails structure may be provided.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "403": { + "description": "403 FORBIDDEN\nIf the API consumer is not allowed to perform a particular request to a particular resource, the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided. It should include in the \"detail\" attribute information about the source of the problem, and may indicate how to solve it.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "404": { + "description": "404 NOT FOUND\nIf the API producer did not find a current representation for the resource addressed by the URI passed in the request or is not willing to disclose that one exists, it shall respond with this response code. The \"ProblemDetails\" structure may be provided, including in the \"detail\" attribute information about the source of the problem, e.g. a wrong resource URI variable.\nThis response code is not appropriate in case the resource addressed by the URI is a container resource which is designed to contain child resources, but does not contain any child resource at the time the request is received. For a GET request to an existing empty container resource, a typical response contains a 200 OK response code and a payload body with an empty array.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "405": { + "description": "404 NOT FOUND\nIf the API producer did not find a current representation for the resource addressed by the URI passed in the request or is not willing to disclose that one exists, it shall respond with this response code. The \"ProblemDetails\" structure may be provided, including in the \"detail\" attribute information about the source of the problem, e.g. a wrong resource URI variable.\nThis response code is not appropriate in case the resource addressed by the URI is a container resource which is designed to contain child resources, but does not contain any child resource at the time the request is received. For a GET request to an existing empty container resource, a typical response contains a 200 OK response code and a payload body with an empty array.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "406": { + "description": "406 NOT ACCEPTABLE\nIf the \"Accept\" header does not contain at least one name of a content type that is acceptable to the API producer, the API producer shall respond with this response code. The \"ProblemDetails\" structure may be omitted.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "409": { + "description": "Conflict\nError: The operation cannot be executed currently, due to a conflict with the state of the resource. Typically, this is due to the fact that \"onboardingState\" of the VNF package has a value different from \"ONBOARDED\". The response body shall contain a ProblemDetails structure, in which the \"detail\" attribute shall convey more information about the error.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "416": { + "description": "Requested Range Not Satisfiable\nThe byte range passed in the \"Range\" header did not match any available byte range in the VNF package file (e.g. \"access after end of file\"). The response body may contain a ProblemDetails structure.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "500": { + "description": "500 INTERNAL SERVER ERROR\nIf there is an application error not related to the client's input that cannot be easily mapped to any other HTTP response code (\"catch all error\"), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and shall include in the \"detail\" attribute more information about the source of the problem.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "503": { + "description": "503 SERVICE UNAVAILABLE\nIf the API producer encounters an internal overload situation of itself or of a system it relies on, it should respond with this response code, following the provisions in IETF RFC 7231 for the use of the \"Retry-After\" HTTP header and for the alternative to refuse the connection. The \"ProblemDetails\" structure may be omitted.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + } + } + } + }, + "/vnf_packages/{vnfPkgId}/artifacts/{artifactPath}": { + "parameters": [ + { + "name": "artifactPath", + "description": "Sequence of one or more path segments representing the path of the artifact within the VNF package. EXAMPLE: foo/bar/run.sh This identifier can be retrieved from the \"artifactPath\" attribute of the applicable \"additionalArtifacts\" entry in the body of the response to a GET request querying the \"Individual VNF package\" or the \"VNF packages\" resource.\n", + "in": "path", + "type": "string", + "required": true + }, + { + "name": "vnfPkgId", + "description": "Identifier of the VNF package. The identifier is allocated by the NFVO. This identifier can be retrieved from the \"vnfPkgId\" attribute in the VnfPackageOnboardingNotification or VnfPackageChangeNotification.\n", + "in": "path", + "type": "string", + "required": true + } + ], + "get": { + "description": "Fetch VNF Package Artifacts\n\nThe GET method fetches the content of an artifact within a VNF package.\n", + "parameters": [ + { + "name": "Accept", + "description": "Content-Types that are acceptable for the response.\n", + "in": "header", + "required": true, + "type": "string" + }, + { + "name": "Authorization", + "description": "The authorization token for the request. Reference: IETF RFC 7235\n", + "in": "header", + "required": false, + "type": "string" + }, + { + "name": "Range", + "description": "The request may contain a \"Range\" HTTP header to obtain single range of bytes from the VNF package file. This can be used to continue an aborted transmission. If the NFVO does not support range requests, it should return the whole file with a 200 OK response instead.\n", + "in": "header", + "type": "string" + }, + { + "name": "Version", + "description": "Version of the API requested to use when responding to this request.\n", + "in": "header", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "200 OK\nOn success, the content of the artifact is returned. The payload body shall contain a copy of the artifact file from the VNF package, as defined by ETSI GS NFV-SOL 004. The \"Content-Type\" HTTP header shall be set according to the content type of the artifact file. If the content type cannot be determined, the header shall be set to the value \"application/octet-stream\".\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response. The \"Content-Type\" HTTP header shall be set according to the content type of the artifact file. If the content type cannot be determined, the header shall be set to the value \"application/octet-stream\".\n", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + } + }, + "206": { + "description": "206 PARTIAL CONTENT\nOn success, if the NFVO supports range requests, a single consecutive byte range from the content of the VNF package file is returned. The response body shall contain the requested part of the VNF package file. The \"Content-Range\" HTTP header shall be provided according to IETF RFC 7233. The \"Content-Type\" HTTP header shall be set as defined above for the \"200 OK\" response.\n", + "headers": { + "Content-Range": { + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + } + }, + "400": { + "description": "400 BAD REQUEST\n400 code can be returned in the following specified cases, the specific cause has to be proper specified in the \"ProblemDetails\" structure to be returned.\nIf the request is malformed or syntactically incorrect (e.g. if the request URI contains incorrect query parameters or the payload body contains a syntactically incorrect data structure), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and should include in the \"detail\" attribute more information about the source of the problem.\nIf the response to a GET request which queries a container resource would be so big that the performance of the API producer is adversely affected, and the API producer does not support paging for the affected resource, it shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and should include in the \"detail\" attribute more information about the source of the problem.\nIf there is an application error related to the client's input that cannot be easily mapped to any other HTTP response code (\"catch all error\"), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and shall include in the \"detail\" attribute more information about the source of the problem.\nIf the request contains a malformed access token, the API producer should respond with this response. The details of the error shall be returned in the WWW Authenticate HTTP header, as defined in IETF RFC 6750 and IETF RFC 7235. The ProblemDetails structure may be provided.\nThe use of this HTTP error response code described above is applicable to the use of the OAuth 2.0 for the authorization of API requests and notifications, as defined in clauses 4.5.3.3 and 4.5.3.4.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "401": { + "description": "401 UNAUTHORIZED\nIf the request contains no access token even though one is required, or if the request contains an authorization token that is invalid (e.g. expired or revoked), the API producer should respond with this response. The details of the error shall be returned in the WWW-Authenticate HTTP header, as defined in IETF RFC 6750 and IETF RFC 7235. The ProblemDetails structure may be provided.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "403": { + "description": "403 FORBIDDEN\nIf the API consumer is not allowed to perform a particular request to a particular resource, the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided. It should include in the \"detail\" attribute information about the source of the problem, and may indicate how to solve it.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "404": { + "description": "404 NOT FOUND\nIf the API producer did not find a current representation for the resource addressed by the URI passed in the request or is not willing to disclose that one exists, it shall respond with this response code. The \"ProblemDetails\" structure may be provided, including in the \"detail\" attribute information about the source of the problem, e.g. a wrong resource URI variable.\nThis response code is not appropriate in case the resource addressed by the URI is a container resource which is designed to contain child resources, but does not contain any child resource at the time the request is received. For a GET request to an existing empty container resource, a typical response contains a 200 OK response code and a payload body with an empty array.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "405": { + "description": "404 NOT FOUND\nIf the API producer did not find a current representation for the resource addressed by the URI passed in the request or is not willing to disclose that one exists, it shall respond with this response code. The \"ProblemDetails\" structure may be provided, including in the \"detail\" attribute information about the source of the problem, e.g. a wrong resource URI variable.\nThis response code is not appropriate in case the resource addressed by the URI is a container resource which is designed to contain child resources, but does not contain any child resource at the time the request is received. For a GET request to an existing empty container resource, a typical response contains a 200 OK response code and a payload body with an empty array.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "406": { + "description": "406 NOT ACCEPTABLE\nIf the \"Accept\" header does not contain at least one name of a content type that is acceptable to the API producer, the API producer shall respond with this response code. The \"ProblemDetails\" structure may be omitted.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "409": { + "description": "Conflict\nError: The operation cannot be executed currently, due to a conflict with the state of the resource. Typically, this is due to the fact that \"onboardingState\" of the VNF package has a value different from \"ONBOARDED\". The response body shall contain a ProblemDetails structure, in which the \"detail\" attribute shall convey more information about the error.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "416": { + "description": "Requested Range Not Satisfiable\nThe byte range passed in the \"Range\" header did not match any available byte range in the VNF package file (e.g. \"access after end of file\"). The response body may contain a ProblemDetails structure.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "500": { + "description": "500 INTERNAL SERVER ERROR\nIf there is an application error not related to the client's input that cannot be easily mapped to any other HTTP response code (\"catch all error\"), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and shall include in the \"detail\" attribute more information about the source of the problem.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "503": { + "description": "503 SERVICE UNAVAILABLE\nIf the API producer encounters an internal overload situation of itself or of a system it relies on, it should respond with this response code, following the provisions in IETF RFC 7231 for the use of the \"Retry-After\" HTTP header and for the alternative to refuse the connection. The \"ProblemDetails\" structure may be omitted.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + } + } + } + }, + "/subscriptions": { + "post": { + "description": "Subscribe\n\nThe POST method creates a new subscription. Creation of two subscription resources with the same callbackURI and the same filter can result in performance degradation and will provide duplicates of notifications to the VNFM, and might make sense only in very rare use cases. Consequently, the NFVO may either allow creating a subscription resource if another subscription resource with the same filter and callbackUri already exists (in which case it shall return the “201 Created” response code), or may decide to not create a duplicate subscription resource (in which case it shall return a “303 See Other” response code referencing the existing subscription resource with the same filter and callbackUri).\n", + "parameters": [ + { + "name": "PkgmSubscriptionRequest", + "description": "Representation of the created subscription resource. The HTTP response shall include a \"Location\" HTTP header that points to the created subscription resource.\n", + "in": "body", + "required": true, + "schema": { + "description": "This type represents a subscription request related to VNF package management notifications about VNF package on-boarding or changes.\n", + "type": "object", + "required": [ + "callbackUri" + ], + "properties": { + "filter": { + "description": "This type represents a subscription filter related to notifications related to VNF package management. At a particular nesting level in the filter structure, the following applies: All attributes shall match in order for the filter to match (logical \"and\" between different filter attributes). If an attribute is an array, the attribute shall match if at least one of the values in the array matches (logical \"or\" between the values of one filter attribute).\n", + "type": "object", + "properties": { + "notificationTypes": { + "description": "Match particular notification types. Permitted values: - VnfPackageOnboardingNotification - VnfPackageChangeNotification The permitted values of the \"notificationTypes\" attribute are spelled exactly as the names of the notification types to facilitate automated code generation systems.\n", + "type": "array", + "items": { + "type": "string", + "enum": [ + "VnfPackageOnboardingNotification", + "VnfPackageChangeNotification" + ] + } + }, + "vnfProductsFromProviders": { + "description": "If present, match VNF packages that contain VNF products from certain providers. The attributes \"vnfProductsFromProviders\", \"vnfdId\" and \"vnfPkgId\" are alternatives to reference to particular VNF packages in a filter. They should not be used both in the same filter instance, but one alternative should be chosen.\n", + "type": "array", + "items": { + "type": "object", + "required": [ + "vnfProvider" + ], + "properties": { + "vnfProvider": { + "description": "Name of the VNF provider to match.\n", + "type": "string" + }, + "vnfProducts": { + "description": "If present, match VNF packages that contain VNF products with certain product names, from one particular provider.\n", + "type": "array", + "items": { + "type": "object", + "required": [ + "vnfProductName" + ], + "properties": { + "vnfProductName": { + "description": "Name of the VNF product to match.\n", + "type": "string" + }, + "versions": { + "description": "If present, match VNF packages that contain VNF products with certain versions and a certain product name, from one particular provider.\n", + "type": "array", + "items": { + "type": "object", + "required": [ + "vnfSoftwareVersion" + ], + "properties": { + "vnfSoftwareVersion": { + "description": "A Version.\n", + "type": "string" + }, + "vnfdVersions": { + "description": "If present, match VNF packages that contain VNF products with certain VNFD versions, a certain software version and a certain product name, from one particular provider.\n", + "type": "array", + "items": { + "description": "A Version.\n", + "type": "string" + } + } + } + } + } + } + } + } + } + } + }, + "vnfdId": { + "description": "Match VNF packages with a VNFD identifier listed in the attribute. The attributes \"vnfProductsFromProviders\", \"vnfdId\" and \"vnfPkgId\" are alternatives to reference to particular VNF packages in a filter. They should not be used both in the same filter instance, but one alternative should be chosen.\n", + "type": "array", + "items": { + "description": "An identifier with the intention of being globally unique.\n", + "type": "string" + } + }, + "vnfPkgId": { + "description": "Match VNF packages with a package identifier listed in the attribute. May be present if the \"notificationTypes\" attribute contains the value \"VnfPackageChangeNotification\", and shall be absent otherwise. The attributes \"vnfProductsFromProviders\", \"vnfdId\" and \"vnfPkgId\" are alternatives to reference to particular VNF packages in a filter. They should not be used both in the same filter instance, but one alternative should be chosen.\n", + "type": "array", + "items": { + "description": "An identifier with the intention of being globally unique.\n", + "type": "string" + } + }, + "operationalState": { + "description": "- ENABLED: The VNF package is enabled, i.e. it can be used for instantiation of new VNF instances.\n- DISABLED: The VNF package is disabled, i.e. it cannot be used for further VNF instantiation requests (unless and until the VNF package\n is re-enabled).\n", + "type": "string", + "enum": [ + "ENABLED", + "DISABLED" + ] + }, + "usageState": { + "description": "- IN_USE: VNF instances instantiated from this VNF package exist. - NOT_IN_USE: No existing VNF instance is instantiated from this VNF package.\n" + } + } + }, + "callbackUri": { + "description": "String formatted according to IETF RFC 3986.\n", + "type": "string" + }, + "authentication": { + "type": "object", + "required": [ + "authType" + ], + "properties": { + "authType": { + "description": "Defines the types of Authentication / Authorization which the API consumer is willing to accept when receiving a notification. Permitted values: * BASIC: In every HTTP request to the notification endpoint, use HTTP Basic authentication with the client credentials. \n* OAUTH2_CLIENT_CREDENTIALS: In every HTTP request to the notification endpoint, use an OAuth 2.0 Bearer token, obtained\n using the client credentials grant type.\n* TLS_CERT: Every HTTP request to the notification endpoint is sent over a mutually authenticated TLS session, i.e. not only the\n server is authenticated, but also the client is authenticated\n during the TLS tunnel setup.\n", + "type": "array", + "items": { + "type": "string", + "enum": [ + "BASIC", + "OAUTH2_CLIENT_CREDENTIALS", + "TLS_CERT" + ] + } + }, + "paramsBasic": { + "description": "Parameters for authentication/authorization using BASIC. Shall be present if authType is \"BASIC\" and the contained information has not been provisioned out of band. Shall be absent otherwise.\n", + "type": "object", + "properties": { + "userName": { + "description": "Username to be used in HTTP Basic authentication. Shall be present if it has not been provisioned out of band.\n", + "type": "string" + }, + "password": { + "description": "Password to be used in HTTP Basic authentication. Shall be present if it has not been provisioned out of band.\n", + "type": "string" + } + } + }, + "paramsOauth2ClientCredentials": { + "description": "Parameters for authentication/authorization using OAUTH2_CLIENT_CREDENTIALS. Shall be present if authType is \"OAUTH2_CLIENT_CREDENTIALS\" and the contained information has not been provisioned out of band. Shall be absent otherwise.\n", + "type": "object", + "properties": { + "clientId": { + "description": "Client identifier to be used in the access token request of the OAuth 2.0 client credentials grant type. Shall be present if it has not been provisioned out of band. The clientId and clientPassword passed in a subscription shall not be the same as the clientId and clientPassword that are used to obtain authorization for API requests. Client credentials may differ between subscriptions. The value of clientPassword should be generated by a random process.\n", + "type": "string" + }, + "clientPassword": { + "description": "Client password to be used in the access token request of the OAuth 2.0 client credentials grant type. Shall be present if it has not been provisioned out of band. The clientId and clientPassword passed in a subscription shall not be the same as the clientId and clientPassword that are used to obtain authorization for API requests. Client credentials may differ between subscriptions. The value of clientPassword should be generated by a random process.\n", + "type": "string" + }, + "tokenEndpoint": { + "description": "String formatted according to IETF RFC 3986.\n", + "type": "string" + } + } + } + } + } + } + } + }, + { + "name": "Accept", + "description": "Content-Types that are acceptable for the response. Reference: IETF RFC 7231\n", + "in": "header", + "required": true, + "type": "string" + }, + { + "name": "Authorization", + "description": "The authorization token for the request. Reference: IETF RFC 7235\n", + "in": "header", + "required": false, + "type": "string" + }, + { + "name": "Content-Type", + "description": "The MIME type of the body of the request. Reference: IETF RFC 7231\n", + "in": "header", + "required": true, + "type": "string" + }, + { + "name": "Version", + "description": "Version of the API requested to use when responding to this request.\n", + "in": "header", + "required": true, + "type": "string" + } + ], + "responses": { + "201": { + "description": "201 CREATED\nRepresentation of the created subscription resource. The HTTP response shall include a \"Location\" HTTP header that points to the created subscription resource.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "Location": { + "description": "The resource URI of the created VNF instance", + "type": "string", + "format": "url" + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "type": "array", + "items": { + "description": "This type represents a subscription related to notifications about VNF package management.\n", + "type": "object", + "required": [ + "id", + "callbackUri", + "_links" + ], + "properties": { + "id": { + "description": "An identifier with the intention of being globally unique.\n", + "type": "string" + }, + "filter": { + "description": "This type represents a subscription filter related to notifications related to VNF package management. At a particular nesting level in the filter structure, the following applies: All attributes shall match in order for the filter to match (logical \"and\" between different filter attributes). If an attribute is an array, the attribute shall match if at least one of the values in the array matches (logical \"or\" between the values of one filter attribute).\n", + "type": "object", + "properties": { + "notificationTypes": { + "description": "Match particular notification types. Permitted values: - VnfPackageOnboardingNotification - VnfPackageChangeNotification The permitted values of the \"notificationTypes\" attribute are spelled exactly as the names of the notification types to facilitate automated code generation systems.\n", + "type": "array", + "items": { + "type": "string", + "enum": [ + "VnfPackageOnboardingNotification", + "VnfPackageChangeNotification" + ] + } + }, + "vnfProductsFromProviders": { + "description": "If present, match VNF packages that contain VNF products from certain providers. The attributes \"vnfProductsFromProviders\", \"vnfdId\" and \"vnfPkgId\" are alternatives to reference to particular VNF packages in a filter. They should not be used both in the same filter instance, but one alternative should be chosen.\n", + "type": "array", + "items": { + "type": "object", + "required": [ + "vnfProvider" + ], + "properties": { + "vnfProvider": { + "description": "Name of the VNF provider to match.\n", + "type": "string" + }, + "vnfProducts": { + "description": "If present, match VNF packages that contain VNF products with certain product names, from one particular provider.\n", + "type": "array", + "items": { + "type": "object", + "required": [ + "vnfProductName" + ], + "properties": { + "vnfProductName": { + "description": "Name of the VNF product to match.\n", + "type": "string" + }, + "versions": { + "description": "If present, match VNF packages that contain VNF products with certain versions and a certain product name, from one particular provider.\n", + "type": "array", + "items": { + "type": "object", + "required": [ + "vnfSoftwareVersion" + ], + "properties": { + "vnfSoftwareVersion": { + "description": "A Version.\n", + "type": "string" + }, + "vnfdVersions": { + "description": "If present, match VNF packages that contain VNF products with certain VNFD versions, a certain software version and a certain product name, from one particular provider.\n", + "type": "array", + "items": { + "description": "A Version.\n", + "type": "string" + } + } + } + } + } + } + } + } + } + } + }, + "vnfdId": { + "description": "Match VNF packages with a VNFD identifier listed in the attribute. The attributes \"vnfProductsFromProviders\", \"vnfdId\" and \"vnfPkgId\" are alternatives to reference to particular VNF packages in a filter. They should not be used both in the same filter instance, but one alternative should be chosen.\n", + "type": "array", + "items": { + "description": "An identifier with the intention of being globally unique.\n", + "type": "string" + } + }, + "vnfPkgId": { + "description": "Match VNF packages with a package identifier listed in the attribute. May be present if the \"notificationTypes\" attribute contains the value \"VnfPackageChangeNotification\", and shall be absent otherwise. The attributes \"vnfProductsFromProviders\", \"vnfdId\" and \"vnfPkgId\" are alternatives to reference to particular VNF packages in a filter. They should not be used both in the same filter instance, but one alternative should be chosen.\n", + "type": "array", + "items": { + "description": "An identifier with the intention of being globally unique.\n", + "type": "string" + } + }, + "operationalState": { + "description": "- ENABLED: The VNF package is enabled, i.e. it can be used for instantiation of new VNF instances.\n- DISABLED: The VNF package is disabled, i.e. it cannot be used for further VNF instantiation requests (unless and until the VNF package\n is re-enabled).\n", + "type": "string", + "enum": [ + "ENABLED", + "DISABLED" + ] + }, + "usageState": { + "description": "- IN_USE: VNF instances instantiated from this VNF package exist. - NOT_IN_USE: No existing VNF instance is instantiated from this VNF package.\n" + } + } + }, + "callbackUri": { + "description": "String formatted according to IETF RFC 3986.\n", + "type": "string" + }, + "_links": { + "description": "Links to resources related to this resource.\n", + "type": "object", + "required": [ + "self" + ], + "properties": { + "self": { + "description": "This type represents a link to a resource using an absolute URI. It shall comply with the provisions defined in table 4.4.1.3-1.\n", + "type": "object", + "required": [ + "href" + ], + "properties": { + "href": { + "description": "String formatted according to IETF RFC 3986.\n", + "type": "string" + } + } + } + } + } + } + } + } + }, + "303": { + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + } + }, + "400": { + "description": "400 BAD REQUEST\n400 code can be returned in the following specified cases, the specific cause has to be proper specified in the \"ProblemDetails\" structure to be returned.\nIf the request is malformed or syntactically incorrect (e.g. if the request URI contains incorrect query parameters or the payload body contains a syntactically incorrect data structure), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and should include in the \"detail\" attribute more information about the source of the problem.\nIf the response to a GET request which queries a container resource would be so big that the performance of the API producer is adversely affected, and the API producer does not support paging for the affected resource, it shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and should include in the \"detail\" attribute more information about the source of the problem.\nIf there is an application error related to the client's input that cannot be easily mapped to any other HTTP response code (\"catch all error\"), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and shall include in the \"detail\" attribute more information about the source of the problem.\nIf the request contains a malformed access token, the API producer should respond with this response. The details of the error shall be returned in the WWW Authenticate HTTP header, as defined in IETF RFC 6750 and IETF RFC 7235. The ProblemDetails structure may be provided.\nThe use of this HTTP error response code described above is applicable to the use of the OAuth 2.0 for the authorization of API requests and notifications, as defined in clauses 4.5.3.3 and 4.5.3.4.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "401": { + "description": "401 UNAUTHORIZED\nIf the request contains no access token even though one is required, or if the request contains an authorization token that is invalid (e.g. expired or revoked), the API producer should respond with this response. The details of the error shall be returned in the WWW-Authenticate HTTP header, as defined in IETF RFC 6750 and IETF RFC 7235. The ProblemDetails structure may be provided.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "403": { + "description": "403 FORBIDDEN\nIf the API consumer is not allowed to perform a particular request to a particular resource, the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided. It should include in the \"detail\" attribute information about the source of the problem, and may indicate how to solve it.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "404": { + "description": "404 NOT FOUND\nIf the API producer did not find a current representation for the resource addressed by the URI passed in the request or is not willing to disclose that one exists, it shall respond with this response code. The \"ProblemDetails\" structure may be provided, including in the \"detail\" attribute information about the source of the problem, e.g. a wrong resource URI variable.\nThis response code is not appropriate in case the resource addressed by the URI is a container resource which is designed to contain child resources, but does not contain any child resource at the time the request is received. For a GET request to an existing empty container resource, a typical response contains a 200 OK response code and a payload body with an empty array.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "405": { + "description": "404 NOT FOUND\nIf the API producer did not find a current representation for the resource addressed by the URI passed in the request or is not willing to disclose that one exists, it shall respond with this response code. The \"ProblemDetails\" structure may be provided, including in the \"detail\" attribute information about the source of the problem, e.g. a wrong resource URI variable.\nThis response code is not appropriate in case the resource addressed by the URI is a container resource which is designed to contain child resources, but does not contain any child resource at the time the request is received. For a GET request to an existing empty container resource, a typical response contains a 200 OK response code and a payload body with an empty array.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "406": { + "description": "406 NOT ACCEPTABLE\nIf the \"Accept\" header does not contain at least one name of a content type that is acceptable to the API producer, the API producer shall respond with this response code. The \"ProblemDetails\" structure may be omitted.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "416": { + "description": "416 RANGE NOT SATISFIABLE\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "500": { + "description": "500 INTERNAL SERVER ERROR\nIf there is an application error not related to the client's input that cannot be easily mapped to any other HTTP response code (\"catch all error\"), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and shall include in the \"detail\" attribute more information about the source of the problem.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "503": { + "description": "503 SERVICE UNAVAILABLE\nIf the API producer encounters an internal overload situation of itself or of a system it relies on, it should respond with this response code, following the provisions in IETF RFC 7231 for the use of the \"Retry-After\" HTTP header and for the alternative to refuse the connection. The \"ProblemDetails\" structure may be omitted.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + } + } + }, + "get": { + "description": "Query Subscription Information\n\nThe GET method queries the list of active subscriptions of the functional block that invokes the method. It can be used e.g. for resynchronization after error situations.\n", + "parameters": [ + { + "name": "Accept", + "description": "Content-Types that are acceptable for the response. Reference: IETF RFC 7231\n", + "in": "header", + "required": true, + "type": "string" + }, + { + "name": "Authorization", + "description": "The authorization token for the request. Reference: IETF RFC 7235\n", + "in": "header", + "required": false, + "type": "string" + }, + { + "name": "filter", + "description": "Attribute-based filtering expression according to clause 4.3.2. The VNFM shall support receiving this parameter as part of the URI query string. The NFVO may supply this parameter. All attribute names that appear in the PkgmSubscription and in data types referenced from it shall be supported by the VNFM in the filter expression.\n", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "nextpage_opaque_marker", + "description": "Marker to obtain the next page of a paged response. Shall be supported by the VNFM if the VNFM supports alternative 2 (paging) according to clause 4.7.2.1 for this resource.\n", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "Version", + "description": "Version of the API requested to use when responding to this request.\n", + "in": "header", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "200 OK\nThe list of subscriptions was queried successfully. The representations body shall contain in an array the representations of all active subscriptions of the functional block that invokes the method , i.e. zero or more representations of VNF package Management subscriptions as defined in clause 10.5.2.4. If the VNFM supports alternative 2 (paging) according to clause 4.7.2.1 for this resource, inclusion of the Link HTTP header in this response shall follow the provisions in clause 4.7.2.3.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "Link": { + "description": "Reference to other resources. Used for paging in the present document, see clause 4.7.2.1.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + } + }, + "schema": { + "type": "array", + "items": { + "description": "This type represents a subscription related to notifications about VNF package management.\n", + "type": "object", + "required": [ + "id", + "callbackUri", + "_links" + ], + "properties": { + "id": { + "description": "An identifier with the intention of being globally unique.\n", + "type": "string" + }, + "filter": { + "description": "This type represents a subscription filter related to notifications related to VNF package management. At a particular nesting level in the filter structure, the following applies: All attributes shall match in order for the filter to match (logical \"and\" between different filter attributes). If an attribute is an array, the attribute shall match if at least one of the values in the array matches (logical \"or\" between the values of one filter attribute).\n", + "type": "object", + "properties": { + "notificationTypes": { + "description": "Match particular notification types. Permitted values: - VnfPackageOnboardingNotification - VnfPackageChangeNotification The permitted values of the \"notificationTypes\" attribute are spelled exactly as the names of the notification types to facilitate automated code generation systems.\n", + "type": "array", + "items": { + "type": "string", + "enum": [ + "VnfPackageOnboardingNotification", + "VnfPackageChangeNotification" + ] + } + }, + "vnfProductsFromProviders": { + "description": "If present, match VNF packages that contain VNF products from certain providers. The attributes \"vnfProductsFromProviders\", \"vnfdId\" and \"vnfPkgId\" are alternatives to reference to particular VNF packages in a filter. They should not be used both in the same filter instance, but one alternative should be chosen.\n", + "type": "array", + "items": { + "type": "object", + "required": [ + "vnfProvider" + ], + "properties": { + "vnfProvider": { + "description": "Name of the VNF provider to match.\n", + "type": "string" + }, + "vnfProducts": { + "description": "If present, match VNF packages that contain VNF products with certain product names, from one particular provider.\n", + "type": "array", + "items": { + "type": "object", + "required": [ + "vnfProductName" + ], + "properties": { + "vnfProductName": { + "description": "Name of the VNF product to match.\n", + "type": "string" + }, + "versions": { + "description": "If present, match VNF packages that contain VNF products with certain versions and a certain product name, from one particular provider.\n", + "type": "array", + "items": { + "type": "object", + "required": [ + "vnfSoftwareVersion" + ], + "properties": { + "vnfSoftwareVersion": { + "description": "A Version.\n", + "type": "string" + }, + "vnfdVersions": { + "description": "If present, match VNF packages that contain VNF products with certain VNFD versions, a certain software version and a certain product name, from one particular provider.\n", + "type": "array", + "items": { + "description": "A Version.\n", + "type": "string" + } + } + } + } + } + } + } + } + } + } + }, + "vnfdId": { + "description": "Match VNF packages with a VNFD identifier listed in the attribute. The attributes \"vnfProductsFromProviders\", \"vnfdId\" and \"vnfPkgId\" are alternatives to reference to particular VNF packages in a filter. They should not be used both in the same filter instance, but one alternative should be chosen.\n", + "type": "array", + "items": { + "description": "An identifier with the intention of being globally unique.\n", + "type": "string" + } + }, + "vnfPkgId": { + "description": "Match VNF packages with a package identifier listed in the attribute. May be present if the \"notificationTypes\" attribute contains the value \"VnfPackageChangeNotification\", and shall be absent otherwise. The attributes \"vnfProductsFromProviders\", \"vnfdId\" and \"vnfPkgId\" are alternatives to reference to particular VNF packages in a filter. They should not be used both in the same filter instance, but one alternative should be chosen.\n", + "type": "array", + "items": { + "description": "An identifier with the intention of being globally unique.\n", + "type": "string" + } + }, + "operationalState": { + "description": "- ENABLED: The VNF package is enabled, i.e. it can be used for instantiation of new VNF instances.\n- DISABLED: The VNF package is disabled, i.e. it cannot be used for further VNF instantiation requests (unless and until the VNF package\n is re-enabled).\n", + "type": "string", + "enum": [ + "ENABLED", + "DISABLED" + ] + }, + "usageState": { + "description": "- IN_USE: VNF instances instantiated from this VNF package exist. - NOT_IN_USE: No existing VNF instance is instantiated from this VNF package.\n" + } + } + }, + "callbackUri": { + "description": "String formatted according to IETF RFC 3986.\n", + "type": "string" + }, + "_links": { + "description": "Links to resources related to this resource.\n", + "type": "object", + "required": [ + "self" + ], + "properties": { + "self": { + "description": "This type represents a link to a resource using an absolute URI. It shall comply with the provisions defined in table 4.4.1.3-1.\n", + "type": "object", + "required": [ + "href" + ], + "properties": { + "href": { + "description": "String formatted according to IETF RFC 3986.\n", + "type": "string" + } + } + } + } + } + } + } + } + }, + "400": { + "description": "400 BAD REQUEST\n400 code can be returned in the following specified cases, the specific cause has to be proper specified in the \"ProblemDetails\" structure to be returned.\nIf the request is malformed or syntactically incorrect (e.g. if the request URI contains incorrect query parameters or the payload body contains a syntactically incorrect data structure), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and should include in the \"detail\" attribute more information about the source of the problem.\nIf the response to a GET request which queries a container resource would be so big that the performance of the API producer is adversely affected, and the API producer does not support paging for the affected resource, it shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and should include in the \"detail\" attribute more information about the source of the problem.\nIf there is an application error related to the client's input that cannot be easily mapped to any other HTTP response code (\"catch all error\"), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and shall include in the \"detail\" attribute more information about the source of the problem.\nIf the request contains a malformed access token, the API producer should respond with this response. The details of the error shall be returned in the WWW Authenticate HTTP header, as defined in IETF RFC 6750 and IETF RFC 7235. The ProblemDetails structure may be provided.\nThe use of this HTTP error response code described above is applicable to the use of the OAuth 2.0 for the authorization of API requests and notifications, as defined in clauses 4.5.3.3 and 4.5.3.4.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "401": { + "description": "401 UNAUTHORIZED\nIf the request contains no access token even though one is required, or if the request contains an authorization token that is invalid (e.g. expired or revoked), the API producer should respond with this response. The details of the error shall be returned in the WWW-Authenticate HTTP header, as defined in IETF RFC 6750 and IETF RFC 7235. The ProblemDetails structure may be provided.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "403": { + "description": "403 FORBIDDEN\nIf the API consumer is not allowed to perform a particular request to a particular resource, the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided. It should include in the \"detail\" attribute information about the source of the problem, and may indicate how to solve it.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "404": { + "description": "404 NOT FOUND\nIf the API producer did not find a current representation for the resource addressed by the URI passed in the request or is not willing to disclose that one exists, it shall respond with this response code. The \"ProblemDetails\" structure may be provided, including in the \"detail\" attribute information about the source of the problem, e.g. a wrong resource URI variable.\nThis response code is not appropriate in case the resource addressed by the URI is a container resource which is designed to contain child resources, but does not contain any child resource at the time the request is received. For a GET request to an existing empty container resource, a typical response contains a 200 OK response code and a payload body with an empty array.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "405": { + "description": "404 NOT FOUND\nIf the API producer did not find a current representation for the resource addressed by the URI passed in the request or is not willing to disclose that one exists, it shall respond with this response code. The \"ProblemDetails\" structure may be provided, including in the \"detail\" attribute information about the source of the problem, e.g. a wrong resource URI variable.\nThis response code is not appropriate in case the resource addressed by the URI is a container resource which is designed to contain child resources, but does not contain any child resource at the time the request is received. For a GET request to an existing empty container resource, a typical response contains a 200 OK response code and a payload body with an empty array.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "406": { + "description": "406 NOT ACCEPTABLE\nIf the \"Accept\" header does not contain at least one name of a content type that is acceptable to the API producer, the API producer shall respond with this response code. The \"ProblemDetails\" structure may be omitted.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "416": { + "description": "416 RANGE NOT SATISFIABLE\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "500": { + "description": "500 INTERNAL SERVER ERROR\nIf there is an application error not related to the client's input that cannot be easily mapped to any other HTTP response code (\"catch all error\"), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and shall include in the \"detail\" attribute more information about the source of the problem.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "503": { + "description": "503 SERVICE UNAVAILABLE\nIf the API producer encounters an internal overload situation of itself or of a system it relies on, it should respond with this response code, following the provisions in IETF RFC 7231 for the use of the \"Retry-After\" HTTP header and for the alternative to refuse the connection. The \"ProblemDetails\" structure may be omitted.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + } + } + } + }, + "/subscriptions/{subscriptionId}": { + "parameters": [ + { + "name": "subscriptionId", + "description": "Identifier of this subscription. This identifier can be retrieved from the resource referenced by the \"Location\" HTTP header in the response to a POST request creating a new subscription resource. It can also be retrieved from the \"id\" attribute in the payload body of that response.\n", + "in": "path", + "type": "string", + "required": true + } + ], + "get": { + "description": "Query Subscription Information\n\nThe GET method reads an individual subscription.\n", + "parameters": [ + { + "name": "Accept", + "description": "Content-Types that are acceptable for the response. Reference: IETF RFC 7231\n", + "in": "header", + "required": true, + "type": "string" + }, + { + "name": "Authorization", + "description": "The authorization token for the request. Reference: IETF RFC 7235\n", + "in": "header", + "required": false, + "type": "string" + }, + { + "name": "Version", + "description": "Version of the API requested to use when responding to this request.\n", + "in": "header", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "200 OK\nRepresentation of the subscription resource.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "This type represents a subscription related to notifications about VNF package management.\n", + "type": "object", + "required": [ + "id", + "callbackUri", + "_links" + ], + "properties": { + "id": { + "description": "An identifier with the intention of being globally unique.\n", + "type": "string" + }, + "filter": { + "description": "This type represents a subscription filter related to notifications related to VNF package management. At a particular nesting level in the filter structure, the following applies: All attributes shall match in order for the filter to match (logical \"and\" between different filter attributes). If an attribute is an array, the attribute shall match if at least one of the values in the array matches (logical \"or\" between the values of one filter attribute).\n", + "type": "object", + "properties": { + "notificationTypes": { + "description": "Match particular notification types. Permitted values: - VnfPackageOnboardingNotification - VnfPackageChangeNotification The permitted values of the \"notificationTypes\" attribute are spelled exactly as the names of the notification types to facilitate automated code generation systems.\n", + "type": "array", + "items": { + "type": "string", + "enum": [ + "VnfPackageOnboardingNotification", + "VnfPackageChangeNotification" + ] + } + }, + "vnfProductsFromProviders": { + "description": "If present, match VNF packages that contain VNF products from certain providers. The attributes \"vnfProductsFromProviders\", \"vnfdId\" and \"vnfPkgId\" are alternatives to reference to particular VNF packages in a filter. They should not be used both in the same filter instance, but one alternative should be chosen.\n", + "type": "array", + "items": { + "type": "object", + "required": [ + "vnfProvider" + ], + "properties": { + "vnfProvider": { + "description": "Name of the VNF provider to match.\n", + "type": "string" + }, + "vnfProducts": { + "description": "If present, match VNF packages that contain VNF products with certain product names, from one particular provider.\n", + "type": "array", + "items": { + "type": "object", + "required": [ + "vnfProductName" + ], + "properties": { + "vnfProductName": { + "description": "Name of the VNF product to match.\n", + "type": "string" + }, + "versions": { + "description": "If present, match VNF packages that contain VNF products with certain versions and a certain product name, from one particular provider.\n", + "type": "array", + "items": { + "type": "object", + "required": [ + "vnfSoftwareVersion" + ], + "properties": { + "vnfSoftwareVersion": { + "description": "A Version.\n", + "type": "string" + }, + "vnfdVersions": { + "description": "If present, match VNF packages that contain VNF products with certain VNFD versions, a certain software version and a certain product name, from one particular provider.\n", + "type": "array", + "items": { + "description": "A Version.\n", + "type": "string" + } + } + } + } + } + } + } + } + } + } + }, + "vnfdId": { + "description": "Match VNF packages with a VNFD identifier listed in the attribute. The attributes \"vnfProductsFromProviders\", \"vnfdId\" and \"vnfPkgId\" are alternatives to reference to particular VNF packages in a filter. They should not be used both in the same filter instance, but one alternative should be chosen.\n", + "type": "array", + "items": { + "description": "An identifier with the intention of being globally unique.\n", + "type": "string" + } + }, + "vnfPkgId": { + "description": "Match VNF packages with a package identifier listed in the attribute. May be present if the \"notificationTypes\" attribute contains the value \"VnfPackageChangeNotification\", and shall be absent otherwise. The attributes \"vnfProductsFromProviders\", \"vnfdId\" and \"vnfPkgId\" are alternatives to reference to particular VNF packages in a filter. They should not be used both in the same filter instance, but one alternative should be chosen.\n", + "type": "array", + "items": { + "description": "An identifier with the intention of being globally unique.\n", + "type": "string" + } + }, + "operationalState": { + "description": "- ENABLED: The VNF package is enabled, i.e. it can be used for instantiation of new VNF instances.\n- DISABLED: The VNF package is disabled, i.e. it cannot be used for further VNF instantiation requests (unless and until the VNF package\n is re-enabled).\n", + "type": "string", + "enum": [ + "ENABLED", + "DISABLED" + ] + }, + "usageState": { + "description": "- IN_USE: VNF instances instantiated from this VNF package exist. - NOT_IN_USE: No existing VNF instance is instantiated from this VNF package.\n" + } + } + }, + "callbackUri": { + "description": "String formatted according to IETF RFC 3986.\n", + "type": "string" + }, + "_links": { + "description": "Links to resources related to this resource.\n", + "type": "object", + "required": [ + "self" + ], + "properties": { + "self": { + "description": "This type represents a link to a resource using an absolute URI. It shall comply with the provisions defined in table 4.4.1.3-1.\n", + "type": "object", + "required": [ + "href" + ], + "properties": { + "href": { + "description": "String formatted according to IETF RFC 3986.\n", + "type": "string" + } + } + } + } + } + } + } + }, + "400": { + "description": "400 BAD REQUEST\n400 code can be returned in the following specified cases, the specific cause has to be proper specified in the \"ProblemDetails\" structure to be returned.\nIf the request is malformed or syntactically incorrect (e.g. if the request URI contains incorrect query parameters or the payload body contains a syntactically incorrect data structure), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and should include in the \"detail\" attribute more information about the source of the problem.\nIf the response to a GET request which queries a container resource would be so big that the performance of the API producer is adversely affected, and the API producer does not support paging for the affected resource, it shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and should include in the \"detail\" attribute more information about the source of the problem.\nIf there is an application error related to the client's input that cannot be easily mapped to any other HTTP response code (\"catch all error\"), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and shall include in the \"detail\" attribute more information about the source of the problem.\nIf the request contains a malformed access token, the API producer should respond with this response. The details of the error shall be returned in the WWW Authenticate HTTP header, as defined in IETF RFC 6750 and IETF RFC 7235. The ProblemDetails structure may be provided.\nThe use of this HTTP error response code described above is applicable to the use of the OAuth 2.0 for the authorization of API requests and notifications, as defined in clauses 4.5.3.3 and 4.5.3.4.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "401": { + "description": "401 UNAUTHORIZED\nIf the request contains no access token even though one is required, or if the request contains an authorization token that is invalid (e.g. expired or revoked), the API producer should respond with this response. The details of the error shall be returned in the WWW-Authenticate HTTP header, as defined in IETF RFC 6750 and IETF RFC 7235. The ProblemDetails structure may be provided.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "403": { + "description": "403 FORBIDDEN\nIf the API consumer is not allowed to perform a particular request to a particular resource, the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided. It should include in the \"detail\" attribute information about the source of the problem, and may indicate how to solve it.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "404": { + "description": "404 NOT FOUND\nIf the API producer did not find a current representation for the resource addressed by the URI passed in the request or is not willing to disclose that one exists, it shall respond with this response code. The \"ProblemDetails\" structure may be provided, including in the \"detail\" attribute information about the source of the problem, e.g. a wrong resource URI variable.\nThis response code is not appropriate in case the resource addressed by the URI is a container resource which is designed to contain child resources, but does not contain any child resource at the time the request is received. For a GET request to an existing empty container resource, a typical response contains a 200 OK response code and a payload body with an empty array.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "405": { + "description": "404 NOT FOUND\nIf the API producer did not find a current representation for the resource addressed by the URI passed in the request or is not willing to disclose that one exists, it shall respond with this response code. The \"ProblemDetails\" structure may be provided, including in the \"detail\" attribute information about the source of the problem, e.g. a wrong resource URI variable.\nThis response code is not appropriate in case the resource addressed by the URI is a container resource which is designed to contain child resources, but does not contain any child resource at the time the request is received. For a GET request to an existing empty container resource, a typical response contains a 200 OK response code and a payload body with an empty array.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "406": { + "description": "406 NOT ACCEPTABLE\nIf the \"Accept\" header does not contain at least one name of a content type that is acceptable to the API producer, the API producer shall respond with this response code. The \"ProblemDetails\" structure may be omitted.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "416": { + "description": "416 RANGE NOT SATISFIABLE\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "500": { + "description": "500 INTERNAL SERVER ERROR\nIf there is an application error not related to the client's input that cannot be easily mapped to any other HTTP response code (\"catch all error\"), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and shall include in the \"detail\" attribute more information about the source of the problem.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "503": { + "description": "503 SERVICE UNAVAILABLE\nIf the API producer encounters an internal overload situation of itself or of a system it relies on, it should respond with this response code, following the provisions in IETF RFC 7231 for the use of the \"Retry-After\" HTTP header and for the alternative to refuse the connection. The \"ProblemDetails\" structure may be omitted.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + } + } + }, + "delete": { + "description": "Terminate subscription\n\nThe DELETE method terminates an individual subscription.\n", + "parameters": [ + { + "name": "Authorization", + "description": "The authorization token for the request. Reference: IETF RFC 7235\n", + "in": "header", + "required": false, + "type": "string" + }, + { + "name": "Version", + "description": "Version of the API requested to use when responding to this request.\n", + "in": "header", + "required": true, + "type": "string" + } + ], + "responses": { + "204": { + "description": "204 NO CONTENT\nThe subscription resource was deleted successfully.\n", + "headers": { + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + } + }, + "400": { + "description": "400 BAD REQUEST\n400 code can be returned in the following specified cases, the specific cause has to be proper specified in the \"ProblemDetails\" structure to be returned.\nIf the request is malformed or syntactically incorrect (e.g. if the request URI contains incorrect query parameters or the payload body contains a syntactically incorrect data structure), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and should include in the \"detail\" attribute more information about the source of the problem.\nIf the response to a GET request which queries a container resource would be so big that the performance of the API producer is adversely affected, and the API producer does not support paging for the affected resource, it shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and should include in the \"detail\" attribute more information about the source of the problem.\nIf there is an application error related to the client's input that cannot be easily mapped to any other HTTP response code (\"catch all error\"), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and shall include in the \"detail\" attribute more information about the source of the problem.\nIf the request contains a malformed access token, the API producer should respond with this response. The details of the error shall be returned in the WWW Authenticate HTTP header, as defined in IETF RFC 6750 and IETF RFC 7235. The ProblemDetails structure may be provided.\nThe use of this HTTP error response code described above is applicable to the use of the OAuth 2.0 for the authorization of API requests and notifications, as defined in clauses 4.5.3.3 and 4.5.3.4.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "401": { + "description": "401 UNAUTHORIZED\nIf the request contains no access token even though one is required, or if the request contains an authorization token that is invalid (e.g. expired or revoked), the API producer should respond with this response. The details of the error shall be returned in the WWW-Authenticate HTTP header, as defined in IETF RFC 6750 and IETF RFC 7235. The ProblemDetails structure may be provided.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "403": { + "description": "403 FORBIDDEN\nIf the API consumer is not allowed to perform a particular request to a particular resource, the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided. It should include in the \"detail\" attribute information about the source of the problem, and may indicate how to solve it.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "404": { + "description": "404 NOT FOUND\nIf the API producer did not find a current representation for the resource addressed by the URI passed in the request or is not willing to disclose that one exists, it shall respond with this response code. The \"ProblemDetails\" structure may be provided, including in the \"detail\" attribute information about the source of the problem, e.g. a wrong resource URI variable.\nThis response code is not appropriate in case the resource addressed by the URI is a container resource which is designed to contain child resources, but does not contain any child resource at the time the request is received. For a GET request to an existing empty container resource, a typical response contains a 200 OK response code and a payload body with an empty array.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "405": { + "description": "404 NOT FOUND\nIf the API producer did not find a current representation for the resource addressed by the URI passed in the request or is not willing to disclose that one exists, it shall respond with this response code. The \"ProblemDetails\" structure may be provided, including in the \"detail\" attribute information about the source of the problem, e.g. a wrong resource URI variable.\nThis response code is not appropriate in case the resource addressed by the URI is a container resource which is designed to contain child resources, but does not contain any child resource at the time the request is received. For a GET request to an existing empty container resource, a typical response contains a 200 OK response code and a payload body with an empty array.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "406": { + "description": "406 NOT ACCEPTABLE\nIf the \"Accept\" header does not contain at least one name of a content type that is acceptable to the API producer, the API producer shall respond with this response code. The \"ProblemDetails\" structure may be omitted.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "416": { + "description": "416 RANGE NOT SATISFIABLE\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "500": { + "description": "500 INTERNAL SERVER ERROR\nIf there is an application error not related to the client's input that cannot be easily mapped to any other HTTP response code (\"catch all error\"), the API producer shall respond with this response code. The \"ProblemDetails\" structure shall be provided, and shall include in the \"detail\" attribute more information about the source of the problem.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + }, + "503": { + "description": "503 SERVICE UNAVAILABLE\nIf the API producer encounters an internal overload situation of itself or of a system it relies on, it should respond with this response code, following the provisions in IETF RFC 7231 for the use of the \"Retry-After\" HTTP header and for the alternative to refuse the connection. The \"ProblemDetails\" structure may be omitted.\n", + "headers": { + "Content-Type": { + "description": "The MIME type of the body of the response.", + "type": "string", + "maximum": 1, + "minimum": 1 + }, + "WWW-Authenticate": { + "description": "Challenge if the corresponding HTTP request has not provided authorization, or error details if the corresponding HTTP request has provided an invalid authorization token.\n", + "type": "string", + "maximum": 1, + "minimum": 0 + }, + "Version": { + "description": "Version of the API used in the response.\n", + "type": "string", + "maximum": 1, + "minimum": 1 + } + }, + "schema": { + "description": "The definition of the general \"ProblemDetails\" data structure from IETF RFC 7807 [19] is reproduced inthis structure. Compared to the general framework defined in IETF RFC 7807 [19], the \"status\" and \"detail\" attributes are mandated to be included by the present document, to ensure that the response contains additional textual information about an error. IETF RFC 7807 [19] foresees extensibility of the \"ProblemDetails\" type. It is possible that particular APIs in the present document, or particular implementations, define extensions to define additional attributes that provide more information about the error. The description column only provides some explanation of the meaning to Facilitate understanding of the design. For a full description, see IETF RFC 7807 [19].\n", + "type": "object", + "required": [ + "status", + "detail" + ], + "properties": { + "type": { + "description": "A URI reference according to IETF RFC 3986 [5] that identifies the problem type. It is encouraged that the URI provides human-readable documentation for the problem (e.g. using HTML) when dereferenced. When this member is not present, its value is assumed to be \"about:blank\".\n", + "type": "string", + "format": "URI" + }, + "title": { + "description": "A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization. If type is given and other than \"about:blank\", this attribute shall also be provided. A short, human-readable summary of the problem type. It SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization (e.g., using proactive content negotiation; see [RFC7231], Section 3.4).\n", + "type": "string" + }, + "status": { + "description": "The HTTP status code for this occurrence of the problem. The HTTP status code ([RFC7231], Section 6) generated by the origin server for this occurrence of the problem.\n", + "type": "integer" + }, + "detail": { + "description": "A human-readable explanation specific to this occurrence of the problem.\n", + "type": "string" + }, + "instance": { + "description": "A URI reference that identifies the specific occurrence of the problem. It may yield further information if dereferenced.\n", + "type": "string", + "format": "URI" + } + } + } + } + } + } + } + } +}
\ No newline at end of file diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/Readme.txt b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/Readme.txt index 66876311db..aaad60320d 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/Readme.txt +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/Readme.txt @@ -1,5 +1,9 @@ The following describes how to configure authentication for the VNFM adapter.
+TLS should always be configured to ensure secure communication between the VNFM-adapter <-> BPMN infra and VNFM-adapter <-> VNFM
+If two-way TLS is configured then there is no need for any further authentication (i.e. no need for token or basic auth).
+If two-way TLS is NOT configured then authentication is REQUIRED. Oauth token based authentication must be used for requests, while for notifications either oauth tokens or basic auth can be used.
+
==========================================
To confgure TLS
@@ -12,8 +16,8 @@ The following parameters can be set to configure the certificate for the VNFM ad server:
ssl:
key-alias: so@so.onap.org
- key--store-password: 'I,re7WWEJR$e]x370wRgx?qE'
- key-store: classpath:org.onap.so.p12
+ key--store-password: 'ywsqCy:EEo#j}HJHM7z^Rk[L'
+ key-store: classpath:so-vnfm-adapter.p12
key-store-type: PKCS12
The values shown above relate to the certificate included in the VNFM adapter jar which has been generated from AAF. If a different certificate is to be used then these values should be changed accordingly.
@@ -21,8 +25,8 @@ The following paramters can be set to configure the trust store for the VNFM ada http:
client:
ssl:
- trust-store: org.onap.so.trust.jks
- trust-store-password: NyRD](z:EJJNIt?},QgM3o7H
+ trust-store: classpath:org.onap.so.trust.jks
+ trust-store-password: ',sx#.C*W)]wVgJC6ccFHI#:H'
The values shown above relate to the trust store included in the VNFM adapter jar which has been generated from AAI. If a different trust store is to be used then these values should be changed accordingly.
Ensure the value for the below parameter uses https instead of http
diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/Constants.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/Constants.java index 1695b39c85..40be4411c8 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/Constants.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/Constants.java @@ -28,6 +28,8 @@ public class Constants { public static final String SERVICE_NAME = "vnfm-adapter"; public static final String SERVICE_VERSION = "v1"; public static final String BASE_URL = "/so/" + SERVICE_NAME + "/" + SERVICE_VERSION; + public static final String PACKAGE_MANAGEMENT_BASE_URL = BASE_URL + "/vnfpkgm/v1"; + public static final String APPLICATION_ZIP = "application/zip"; public static final String OPERATION_NOTIFICATION_ENDPOINT = "/lcn/VnfLcmOperationOccurrenceNotification"; private Constants() {} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/MessageConverterConfiguration.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/MessageConverterConfiguration.java index 32c22356b3..84282e0c7f 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/MessageConverterConfiguration.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/MessageConverterConfiguration.java @@ -23,10 +23,13 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import java.util.ArrayList; import java.util.Collection; +import org.onap.so.adapters.vnfmadapter.converters.Sol003EtsiVnfPkgInfoToPkgmInlineResponse2001Converter; import org.onap.so.adapters.vnfmadapter.oauth.OAuth2AccessTokenAdapter; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.GsonHttpMessageConverter; import org.springframework.security.oauth2.common.OAuth2AccessToken; @@ -38,6 +41,13 @@ import org.springframework.security.oauth2.common.OAuth2AccessToken; public class MessageConverterConfiguration { @Bean + public ConversionService conversionService() { + final DefaultConversionService service = new DefaultConversionService(); + service.addConverter(new Sol003EtsiVnfPkgInfoToPkgmInlineResponse2001Converter()); + return service; + } + + @Bean public HttpMessageConverters customConverters() { final Collection<HttpMessageConverter<?>> messageConverters = new ArrayList<>(); final Gson gson = new GsonBuilder() diff --git a/adapters/mso-requests-db-adapter/src/main/java/org/onap/so/adapters/requestsdb/WebSecurityConfigImpl.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/VnfmBasicWebSecurityConfigurerAdapter.java index b8bada298e..4f3bbe6c5b 100644 --- a/adapters/mso-requests-db-adapter/src/main/java/org/onap/so/adapters/requestsdb/WebSecurityConfigImpl.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/VnfmBasicWebSecurityConfigurerAdapter.java @@ -20,31 +20,34 @@ * ============LICENSE_END========================================================= */ -package org.onap.so.adapters.requestsdb; +package org.onap.so.adapters.vnfmadapter; -import org.onap.so.security.MSOSpringFirewall; -import org.onap.so.security.WebSecurityConfig; +import org.onap.so.security.SoBasicWebSecurityConfigurerAdapter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.web.firewall.StrictHttpFirewall; -import org.springframework.util.StringUtils; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ @EnableWebSecurity -public class WebSecurityConfigImpl extends WebSecurityConfig { +@Configuration +public class VnfmBasicWebSecurityConfigurerAdapter extends SoBasicWebSecurityConfigurerAdapter { - @Override - protected void configure(HttpSecurity http) throws Exception { - http.csrf().disable().authorizeRequests().antMatchers("/manage/health", "/manage/info").permitAll() - .antMatchers("/**").hasAnyRole(StringUtils.collectionToDelimitedString(getRoles(), ",")).and() - .httpBasic(); - } + @Value("${server.ssl.client-auth:none}") + private String clientAuth; @Override - public void configure(WebSecurity web) throws Exception { - super.configure(web); - StrictHttpFirewall firewall = new MSOSpringFirewall(); - web.httpFirewall(firewall); + protected void configure(final HttpSecurity http) throws Exception { + if (("need").equalsIgnoreCase(clientAuth)) { + http.csrf().disable().authorizeRequests().anyRequest().permitAll(); + } else { + super.configure(http); + } } } + diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/WebSecurityConfigImpl.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/WebSecurityConfigImpl.java deleted file mode 100644 index f45d5a0219..0000000000 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/WebSecurityConfigImpl.java +++ /dev/null @@ -1,59 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2019 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. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.so.adapters.vnfmadapter; - -import org.onap.so.security.MSOSpringFirewall; -import org.onap.so.security.WebSecurityConfig; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.builders.WebSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.web.firewall.StrictHttpFirewall; -import org.springframework.util.StringUtils; - -/** - * Configure the web security for the application. - */ -@EnableWebSecurity -public class WebSecurityConfigImpl extends WebSecurityConfig { - - @Value("${server.ssl.client-auth:none}") - private String clientAuth; - - @Override - protected void configure(final HttpSecurity http) throws Exception { - if (clientAuth.equalsIgnoreCase("need")) { - http.csrf().disable().authorizeRequests().anyRequest().permitAll(); - } else { - http.csrf().disable().authorizeRequests().antMatchers("/manage/health", "/manage/info").permitAll() - .antMatchers("/**").hasAnyRole(StringUtils.collectionToDelimitedString(getRoles(), ",")).and() - .httpBasic(); - } - } - - @Override - public void configure(final WebSecurity web) throws Exception { - super.configure(web); - final StrictHttpFirewall firewall = new MSOSpringFirewall(); - web.httpFirewall(firewall); - } - -} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/converters/Sol003EtsiVnfPkgInfoToPkgmInlineResponse2001Converter.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/converters/Sol003EtsiVnfPkgInfoToPkgmInlineResponse2001Converter.java new file mode 100644 index 0000000000..de18ecc43e --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/converters/Sol003EtsiVnfPkgInfoToPkgmInlineResponse2001Converter.java @@ -0,0 +1,180 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnfmadapter.converters; + +import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.model.*; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.convert.converter.Converter; +import org.springframework.stereotype.Service; +import java.util.ArrayList; +import java.util.List; + +/** + * Converter to convert from an Etsi Catalog Model {@link VnfPkgInfo} Object to a PackageManagement Model + * {@link InlineResponse2001} Object + * + * @author andrew.a.lamb@est.tech + */ +@Service +public class Sol003EtsiVnfPkgInfoToPkgmInlineResponse2001Converter + implements Converter<VnfPkgInfo, InlineResponse2001> { + private static final Logger logger = + LoggerFactory.getLogger(Sol003EtsiVnfPkgInfoToPkgmInlineResponse2001Converter.class); + + /** + * Convert a {@link VnfPkgInfo} Object to an {@link InlineResponse2001} Object + * + * @param vnfPkgInfo The VnfPkgInfo Object to Convert + * @return The Converted InlineResponse2001 Object + */ + @Override + public InlineResponse2001 convert(final VnfPkgInfo vnfPkgInfo) { + if (vnfPkgInfo == null) { + logger.info("No VnfPkgInfo Object Provided for Conversion. (Null object received, returning Null)"); + return null; + } + final InlineResponse2001 response = new InlineResponse2001(); + response.setId(vnfPkgInfo.getId()); + response.setVnfdId(vnfPkgInfo.getVnfdId()); + response.setVnfProvider(vnfPkgInfo.getVnfProvider()); + response.setVnfProductName(vnfPkgInfo.getVnfProductName()); + response.setVnfSoftwareVersion(vnfPkgInfo.getVnfSoftwareVersion()); + response.setVnfdVersion(vnfPkgInfo.getVnfdVersion()); + response.setChecksum(convertChecksumToVnfPackagesChecksum(vnfPkgInfo.getChecksum())); + response.setSoftwareImages( + convertVnfPackageSoftwareImageInfoListToVnfPackagesSoftwareImagesList(vnfPkgInfo.getSoftwareImages())); + response.setAdditionalArtifacts(convertVnfPackageArtifactInfoListToVnfPackagesAdditionalArtifactsList( + vnfPkgInfo.getAdditionalArtifacts())); + + if (vnfPkgInfo.getOnboardingState() != null) { + response.setOnboardingState( + InlineResponse2001.OnboardingStateEnum.fromValue(vnfPkgInfo.getOnboardingState().getValue())); + } + + if (vnfPkgInfo.getOperationalState() != null) { + response.setOperationalState( + InlineResponse2001.OperationalStateEnum.fromValue(vnfPkgInfo.getOperationalState().getValue())); + } + + response.setUserDefinedData((vnfPkgInfo.getUserDefinedData())); + + if (vnfPkgInfo.getLinks() != null) { + response.setLinks(convertVNFPKGMLinkSerializerToVnfPackagesLinks(vnfPkgInfo.getLinks())); + } + + return response; + } + + private VnfPackagesChecksum convertChecksumToVnfPackagesChecksum(final Checksum checksum) { + final VnfPackagesChecksum vnfPackagesChecksum = new VnfPackagesChecksum(); + if (checksum != null) { + vnfPackagesChecksum.setAlgorithm(checksum.getAlgorithm()); + vnfPackagesChecksum.setHash(checksum.getHash()); + } + return vnfPackagesChecksum; + } + + private List<VnfPackagesSoftwareImages> convertVnfPackageSoftwareImageInfoListToVnfPackagesSoftwareImagesList( + final List<VnfPackageSoftwareImageInfo> vnfPackageSoftwareImageInfoList) { + final List<VnfPackagesSoftwareImages> vnfPackagesSoftwareImages = new ArrayList<>(); + if (vnfPackageSoftwareImageInfoList != null) { + for (final VnfPackageSoftwareImageInfo vnfPackageSoftwareImageInfo : vnfPackageSoftwareImageInfoList) { + final VnfPackagesSoftwareImages softwareImage = + convertVnfPackageSoftwareImageInfoToVnfPackagesSoftwareImages(vnfPackageSoftwareImageInfo); + vnfPackagesSoftwareImages.add(softwareImage); + } + } + return vnfPackagesSoftwareImages; + } + + private VnfPackagesSoftwareImages convertVnfPackageSoftwareImageInfoToVnfPackagesSoftwareImages( + final VnfPackageSoftwareImageInfo vnfPackageSoftwareImageInfo) { + final VnfPackagesSoftwareImages vnfPackagesSoftwareImages = new VnfPackagesSoftwareImages(); + vnfPackagesSoftwareImages.setId(vnfPackageSoftwareImageInfo.getId()); + vnfPackagesSoftwareImages.setName(vnfPackageSoftwareImageInfo.getName()); + vnfPackagesSoftwareImages.setProvider(vnfPackageSoftwareImageInfo.getProvider()); + vnfPackagesSoftwareImages.setVersion(vnfPackageSoftwareImageInfo.getVersion()); + vnfPackagesSoftwareImages + .setChecksum(convertChecksumToVnfPackagesChecksum(vnfPackageSoftwareImageInfo.getChecksum())); + if (vnfPackageSoftwareImageInfo.getContainerFormat() != null) { + vnfPackagesSoftwareImages.setContainerFormat(VnfPackagesSoftwareImages.ContainerFormatEnum + .fromValue(vnfPackageSoftwareImageInfo.getContainerFormat().getValue())); + } + + if (vnfPackageSoftwareImageInfo.getDiskFormat() != null) { + vnfPackagesSoftwareImages.setDiskFormat(VnfPackagesSoftwareImages.DiskFormatEnum + .fromValue(vnfPackageSoftwareImageInfo.getDiskFormat().getValue())); + } + + vnfPackagesSoftwareImages.setCreatedAt(vnfPackageSoftwareImageInfo.getCreatedAt()); + vnfPackagesSoftwareImages.setMinDisk(vnfPackageSoftwareImageInfo.getMinDisk()); + vnfPackagesSoftwareImages.setMinRam(vnfPackageSoftwareImageInfo.getMinRam()); + vnfPackagesSoftwareImages.setSize(vnfPackageSoftwareImageInfo.getSize()); + vnfPackagesSoftwareImages.setUserMetadata(vnfPackageSoftwareImageInfo.getUserMetadata()); + vnfPackagesSoftwareImages.setImagePath(vnfPackageSoftwareImageInfo.getImagePath()); + return vnfPackagesSoftwareImages; + } + + private List<VnfPackagesAdditionalArtifacts> convertVnfPackageArtifactInfoListToVnfPackagesAdditionalArtifactsList( + final List<VnfPackageArtifactInfo> vnfPackageArtifactInfoList) { + if (vnfPackageArtifactInfoList != null) { + final List<VnfPackagesAdditionalArtifacts> additionalArtifacts = new ArrayList<>(); + for (final VnfPackageArtifactInfo artifactInfo : vnfPackageArtifactInfoList) { + final VnfPackagesAdditionalArtifacts artifact = + convertVnfPackageArtifactInfoToVnfPackagesAdditionalArtifacts(artifactInfo); + additionalArtifacts.add(artifact); + } + return additionalArtifacts; + } + return null; + } + + private VnfPackagesAdditionalArtifacts convertVnfPackageArtifactInfoToVnfPackagesAdditionalArtifacts( + final VnfPackageArtifactInfo vnfPackageArtifactInfo) { + final VnfPackagesAdditionalArtifacts vnfPackagesAdditionalArtifacts = new VnfPackagesAdditionalArtifacts(); + vnfPackagesAdditionalArtifacts.setArtifactPath(vnfPackageArtifactInfo.getArtifactPath()); + vnfPackagesAdditionalArtifacts + .setChecksum(convertChecksumToVnfPackagesChecksum(vnfPackageArtifactInfo.getChecksum())); + vnfPackagesAdditionalArtifacts.setMetadata(vnfPackageArtifactInfo.getMetadata()); + return vnfPackagesAdditionalArtifacts; + } + + private VnfPackagesLinks convertVNFPKGMLinkSerializerToVnfPackagesLinks( + final VNFPKGMLinkSerializer vnfpkgmLinkSerializer) { + final VnfPackagesLinks vnfPackagesLinks = new VnfPackagesLinks(); + vnfPackagesLinks.setSelf(convertUriLinkToVnfPackagesLinksSelf(vnfpkgmLinkSerializer.getSelf())); + vnfPackagesLinks.setVnfd(convertUriLinkToVnfPackagesLinksSelf(vnfpkgmLinkSerializer.getVnfd())); + vnfPackagesLinks + .setPackageContent(convertUriLinkToVnfPackagesLinksSelf(vnfpkgmLinkSerializer.getPackageContent())); + return vnfPackagesLinks; + } + + private VnfPackagesLinksSelf convertUriLinkToVnfPackagesLinksSelf(final UriLink uriLink) { + final VnfPackagesLinksSelf vnfPackagesLinksSelf = new VnfPackagesLinksSelf(); + if (uriLink != null) { + vnfPackagesLinksSelf.setHref(uriLink.getHref()); + } + return vnfPackagesLinksSelf; + } + +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/AbstractServiceProviderConfiguration.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/AbstractServiceProviderConfiguration.java new file mode 100644 index 0000000000..8f6d853997 --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/AbstractServiceProviderConfiguration.java @@ -0,0 +1,49 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnfmadapter.extclients; + +import com.google.gson.Gson; +import java.util.Iterator; +import org.onap.vnfmadapter.v1.JSON; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.json.GsonHttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.web.client.RestTemplate; + +/** + * A base class that can be extended by classes for configuring HttpRestServiceProvider classes. Provides common methods + * that will be useful to some such classes. + * + * @author gareth.roper@est.tech + */ +public abstract class AbstractServiceProviderConfiguration { + + public void setGsonMessageConverter(final RestTemplate restTemplate) { + final Iterator<HttpMessageConverter<?>> iterator = restTemplate.getMessageConverters().iterator(); + while (iterator.hasNext()) { + if (iterator.next() instanceof MappingJackson2HttpMessageConverter) { + iterator.remove(); + } + } + final Gson gson = new JSON().getGson(); + restTemplate.getMessageConverters().add(new GsonHttpMessageConverter(gson)); + } +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiHelper.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiHelper.java index 110bbabdb2..fc9efef947 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiHelper.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiHelper.java @@ -31,14 +31,10 @@ import org.onap.aai.domain.yang.EsrVnfmList; import org.onap.aai.domain.yang.GenericVnf; import org.onap.aai.domain.yang.Relationship; import org.onap.aai.domain.yang.RelationshipData; -import org.onap.aai.domain.yang.RelationshipList; import org.onap.aai.domain.yang.Vserver; import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs; import org.onap.so.adapters.vnfmadapter.rest.exceptions.TenantNotFoundException; import org.onap.so.adapters.vnfmadapter.rest.exceptions.VnfmNotFoundException; -import org.onap.so.client.aai.AAIObjectType; -import org.onap.so.client.aai.AAIVersion; -import org.onap.so.client.aai.entities.uri.AAIUriFactory; import org.onap.vnfmadapter.v1.model.Tenant; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -61,38 +57,6 @@ public class AaiHelper { } /** - * Add a relationship to the given generic VNF to the given VNFM. - * - * @param vnf the generic VNF - * @param vnfmId the ID of the VNFM - */ - public void addRelationshipFromGenericVnfToVnfm(final GenericVnf vnf, final String vnfmId) { - if (vnf.getRelationshipList() == null) { - vnf.setRelationshipList(new RelationshipList()); - } - final RelationshipList vnfmRelationshiplist = vnf.getRelationshipList(); - vnfmRelationshiplist.getRelationship().add(createRelationshipToVnfm(vnfmId)); - - } - - private Relationship createRelationshipToVnfm(final String vnfmId) { - final Relationship relationship = new Relationship(); - relationship.setRelatedTo("esr-vnfm"); - relationship.setRelationshipLabel("tosca.relationships.DependsOn"); - relationship.setRelatedLink("/aai/" + AAIVersion.LATEST - + AAIUriFactory.createResourceUri(AAIObjectType.VNFM, vnfmId).build().toString()); - relationship.getRelationshipData().add(createRelationshipData("esr-vnfm.vnfm-id", vnfmId)); - return relationship; - } - - private RelationshipData createRelationshipData(final String key, final String value) { - final RelationshipData data = new RelationshipData(); - data.setRelationshipKey(key); - data.setRelationshipValue(value); - return data; - } - - /** * Get the VNFM assigned for use for the given generic VNF. * * @param vnf the generic VNF @@ -242,30 +206,6 @@ public class AaiHelper { return vserver; } - /** - * Add a relationship to the given vserver to the given VNF. - * - * @param vnf the vserver - * @param vnfmId the ID of the VNF - */ - public void addRelationshipFromVserverVnfToGenericVnf(final Vserver vserver, final String vnfId) { - if (vserver.getRelationshipList() == null) { - vserver.setRelationshipList(new RelationshipList()); - } - final RelationshipList vserverRelationshiplist = vserver.getRelationshipList(); - vserverRelationshiplist.getRelationship().add(createRelationshipToGenericVnf(vnfId)); - } - - private Relationship createRelationshipToGenericVnf(final String vnfId) { - final Relationship relationship = new Relationship(); - relationship.setRelatedTo("generic-vnf"); - relationship.setRelationshipLabel("tosca.relationships.HostedOn"); - relationship.setRelatedLink("/aai/" + AAIVersion.LATEST - + AAIUriFactory.createResourceUri(AAIObjectType.GENERIC_VNF, vnfId).build().toString()); - relationship.getRelationshipData().add(createRelationshipData("generic-vnf.vnf-id", vnfId)); - return relationship; - } - public void setOamIpAddressSource(final String vnfId, final OamIpAddressSource oamIpAddressSource) { mapOfVnfIdToOamIpAddressHolder.put(vnfId, oamIpAddressSource); } @@ -274,32 +214,4 @@ public class AaiHelper { return mapOfVnfIdToOamIpAddressHolder.get(vnfId); } - /** - * Add a relationship to the given tenant to the given VNF. - * - * @param vnf the generic vnf - * @param tenant the Tenant - */ - - public void addRelationshipFromGenericVnfToTenant(final GenericVnf vnf, final Tenant tenant) { - if (vnf.getRelationshipList() == null) { - vnf.setRelationshipList(new RelationshipList()); - } - final RelationshipList vnfmRelationshiplist = vnf.getRelationshipList(); - vnfmRelationshiplist.getRelationship().add(createRelationshipToTenant(tenant)); - } - - private Relationship createRelationshipToTenant(final Tenant tenant) { - final Relationship relationship = new Relationship(); - relationship.setRelatedTo("tenant"); - relationship.setRelatedLink("/aai/" + AAIVersion.LATEST + AAIUriFactory.createResourceUri(AAIObjectType.TENANT, - tenant.getCloudOwner(), tenant.getRegionName(), tenant.getTenantId()).build().toString()); - relationship.getRelationshipData() - .add(createRelationshipData("cloud-region.cloud-owner", tenant.getCloudOwner())); - relationship.getRelationshipData() - .add(createRelationshipData("cloud-region.cloud-region-id", tenant.getRegionName())); - relationship.getRelationshipData().add(createRelationshipData("tenant.tenant-id", tenant.getTenantId())); - return relationship; - } - } diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiServiceProvider.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiServiceProvider.java index 7021c02511..d19190d88e 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiServiceProvider.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiServiceProvider.java @@ -72,12 +72,22 @@ public interface AaiServiceProvider { EsrVnfm invokeGetVnfm(final String vnfmId); /** - * Invoke a PUT request for a generic vnf. + * Invoke a PATCH request for a generic vnf. * * @param vnf the generic vnf * @return */ - void invokePutGenericVnf(GenericVnf vnf); + void invokePatchGenericVnf(GenericVnf vnf); + + /** + * Invoke a PUT request for a relationship from a generic vnf to a VNFM. + * + * @param vnf the generic vnf + * @param vnfmId the ID of the VNFM + * @return + */ + void invokePutGenericVnfToVnfmRelationship(GenericVnf vnf, final String vnfmId); + /** * Invoke a PUT request for a vserver. @@ -92,6 +102,19 @@ public interface AaiServiceProvider { final Vserver vserver); /** + * Invoke a PUT request for a relationship from a vserver to a generic vnf. + * + * @param cloudOwner the cloud owner + * @param cloudRegion the cloud region the vserver is deployed on + * @param tenantId the ID of the tenant the vserver is deployed on + * @param vserver the vserver + * @param vnfId the ID of the generic vnf + * @return + */ + void invokePutVserverToVnfRelationship(final String cloudOwner, final String cloudRegion, final String tenantId, + final Vserver vserver, final String vnfId); + + /** * Invoke a DELETE request for a vserver. * * @param cloudOwner the cloud owner diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiServiceProviderImpl.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiServiceProviderImpl.java index 019a08af78..6dc6020834 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiServiceProviderImpl.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiServiceProviderImpl.java @@ -98,12 +98,18 @@ public class AaiServiceProviderImpl implements AaiServiceProvider { } @Override - public void invokePutGenericVnf(final GenericVnf vnf) { + public void invokePatchGenericVnf(final GenericVnf vnf) { aaiClientProvider.getAaiClient() .update(AAIUriFactory.createResourceUri(AAIObjectType.GENERIC_VNF, vnf.getVnfId()), vnf); } @Override + public void invokePutGenericVnfToVnfmRelationship(final GenericVnf vnf, final String vnfmId) { + aaiClientProvider.getAaiClient().connect(AAIUriFactory.createResourceUri(AAIObjectType.VNFM, vnfmId), + AAIUriFactory.createResourceUri(AAIObjectType.GENERIC_VNF, vnf.getVnfId())); + } + + @Override public void invokePutVserver(final String cloudOwner, final String cloudRegion, final String tenant, final Vserver vserver) { aaiClientProvider.getAaiClient().create(AAIUriFactory.createResourceUri(AAIObjectType.VSERVER, cloudOwner, @@ -111,6 +117,16 @@ public class AaiServiceProviderImpl implements AaiServiceProvider { } @Override + public void invokePutVserverToVnfRelationship(final String cloudOwner, final String cloudRegion, + final String tenant, final Vserver vserver, final String vnfId) { + aaiClientProvider.getAaiClient() + .connect( + AAIUriFactory.createResourceUri(AAIObjectType.VSERVER, cloudOwner, cloudRegion, tenant, + vserver.getVserverId()), + AAIUriFactory.createResourceUri(AAIObjectType.GENERIC_VNF, vnfId)); + } + + @Override public void invokeDeleteVserver(final String cloudOwner, final String cloudRegion, final String tenant, final String vserverId) { aaiClientProvider.getAaiClient().delete( diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/etsicatalog/EtsiCatalogServiceProvider.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/etsicatalog/EtsiCatalogServiceProvider.java new file mode 100644 index 0000000000..34fc2645a2 --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/etsicatalog/EtsiCatalogServiceProvider.java @@ -0,0 +1,74 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnfmadapter.extclients.etsicatalog; + +import java.util.Optional; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.InlineResponse2001; + +/** + * Provides methods for invoking REST calls to the ETSI Catalog Manager. + * + * @author gareth.roper@est.tech + */ +public interface EtsiCatalogServiceProvider { + + /** + * GET Package Content, from VNF Package. + * + * @param vnfPkgId The ID of the VNF Package from which the "package_content" will be retrieved. + * @return The Package Content of a VNF Package ("vnfPkgId"). + */ + Optional<byte[]> getVnfPackageContent(final String vnfPkgId); + + /** + * GET VNF packages information from ETSI Catalog. Will return zero or more VNF package representations. + * + * @return An Array of all VNF packages retrieved from the ETSI Catalog. + */ + Optional<InlineResponse2001[]> getVnfPackages(); + + /** + * GET specific VNF package information from ETSI Catalog. + * + * @param vnfPkgId The ID of the VNF Package that you want to query. + * @return The VNF package retrieved from the ETSI Catalog + */ + Optional<InlineResponse2001> getVnfPackage(final String vnfPkgId); + + /** + * GET specific VNF package VNFD from ETSI Catalog. + * + * @param vnfPkgId The ID of the VNF Package that you want to query. + * @return The VNF package retrieved from the ETSI Catalog + */ + Optional<byte[]> getVnfPackageVnfd(final String vnfPkgId); + + /** + * GET Package Artifact, from VNF Package. + * + * @param vnfPkgId The ID of the VNF Package from which the artifact will be retrieved. + * @param artifactPath Sequence of one or more path segments representing the path of the artifact within the VNF + * Package, e.g., foo/bar/run.sh + * @return The Package Artifact of a VNF Package ("vnfPkgId", "artifactPath"). + */ + Optional<byte[]> getVnfPackageArtifact(final String vnfPkgId, final String artifactPath); + +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/etsicatalog/EtsiCatalogServiceProviderConfiguration.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/etsicatalog/EtsiCatalogServiceProviderConfiguration.java new file mode 100644 index 0000000000..6840dd388b --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/etsicatalog/EtsiCatalogServiceProviderConfiguration.java @@ -0,0 +1,56 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnfmadapter.extclients.etsicatalog; + +import static org.onap.so.client.RestTemplateConfig.CONFIGURABLE_REST_TEMPLATE; +import org.onap.so.adapters.vnfmadapter.extclients.AbstractServiceProviderConfiguration; +import org.onap.so.configuration.rest.BasicHttpHeadersProvider; +import org.onap.so.configuration.rest.HttpHeadersProvider; +import org.onap.so.rest.service.HttpRestServiceProvider; +import org.onap.so.rest.service.HttpRestServiceProviderImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; + +/** + * Configures the HttpRestServiceProvider to make REST calls to the ETSI Catalog Manager + * + * @author gareth.roper@est.tech + */ + +@Configuration +public class EtsiCatalogServiceProviderConfiguration extends AbstractServiceProviderConfiguration { + + @Bean(name = "etsiCatalogServiceProvider") + public HttpRestServiceProvider httpRestServiceProvider( + @Qualifier(CONFIGURABLE_REST_TEMPLATE) @Autowired final RestTemplate restTemplate) { + return getHttpRestServiceProvider(restTemplate, new BasicHttpHeadersProvider()); + } + + private HttpRestServiceProvider getHttpRestServiceProvider(final RestTemplate restTemplate, + final HttpHeadersProvider httpHeadersProvider) { + setGsonMessageConverter(restTemplate); + return new HttpRestServiceProviderImpl(restTemplate, httpHeadersProvider); + } + +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/etsicatalog/EtsiCatalogServiceProviderImpl.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/etsicatalog/EtsiCatalogServiceProviderImpl.java new file mode 100644 index 0000000000..779cb2a7a6 --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/etsicatalog/EtsiCatalogServiceProviderImpl.java @@ -0,0 +1,195 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnfmadapter.extclients.etsicatalog; + +import java.util.Optional; +import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.model.VnfPkgInfo; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.InlineResponse2001; +import org.onap.so.adapters.vnfmadapter.rest.exceptions.*; +import org.onap.so.rest.exceptions.HttpResouceNotFoundException; +import org.onap.so.rest.exceptions.InvalidRestRequestException; +import org.onap.so.rest.exceptions.RestProcessingException; +import org.onap.so.rest.service.HttpRestServiceProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.core.convert.ConversionService; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +/** + * Provides the implementations of the REST Requests to the ETSI Catalog Manager. + * + * @author gareth.roper@est.tech + */ +@Service +public class EtsiCatalogServiceProviderImpl implements EtsiCatalogServiceProvider { + private static final Logger logger = LoggerFactory.getLogger(EtsiCatalogServiceProviderImpl.class); + + @Qualifier("etsiCatalogServiceProvider") + private final HttpRestServiceProvider httpServiceProvider; + private final EtsiCatalogUrlProvider etsiCatalogUrlProvider; + private final ConversionService conversionService; + + @Autowired + public EtsiCatalogServiceProviderImpl(final EtsiCatalogUrlProvider etsiCatalogUrlProvider, + final HttpRestServiceProvider httpServiceProvider, final ConversionService conversionService) { + this.etsiCatalogUrlProvider = etsiCatalogUrlProvider; + this.httpServiceProvider = httpServiceProvider; + this.conversionService = conversionService; + } + + @Override + public Optional<byte[]> getVnfPackageContent(final String vnfPkgId) + throws EtsiCatalogManagerRequestFailureException { + final String vnfRequestUrl = etsiCatalogUrlProvider.getVnfPackageContentUrl(vnfPkgId); + final String vnfRequestName = "getVnfPackageContent"; + return requestVnfElement(vnfPkgId, vnfRequestUrl, vnfRequestName); + } + + @Override + public Optional<byte[]> getVnfPackageArtifact(final String vnfPkgId, final String artifactPath) { + try { + final ResponseEntity<byte[]> response = httpServiceProvider.getHttpResponse( + etsiCatalogUrlProvider.getVnfPackageArtifactUrl(vnfPkgId, artifactPath), byte[].class); + logger.info("getVnfPackageArtifact Request to ETSI Catalog Manager Status Code: {}", + response.getStatusCodeValue()); + if (response.getStatusCode() == HttpStatus.OK) { + return Optional.ofNullable(response.getBody()); + } + } catch (final HttpResouceNotFoundException httpResouceNotFoundException) { + logger.error("Caught HttpResouceNotFoundException", httpResouceNotFoundException); + throw new VnfPkgNotFoundException("No Vnf Package Artifact found with vnfPkgId: \"" + vnfPkgId + + "\" and artifactPath: \"" + artifactPath + "\"."); + } catch (final RestProcessingException restProcessingException) { + logger.error("Caught RestProcessingException with Status Code: {}", restProcessingException.getStatusCode(), + restProcessingException); + if (restProcessingException.getStatusCode() == HttpStatus.CONFLICT.value()) { + throw new VnfPkgConflictException("A conflict occurred with the state of the resource,\n" + + "due to the attribute: onboardingState not being set to ONBOARDED."); + } + } + throw new EtsiCatalogManagerRequestFailureException("Internal Server Error Occurred."); + } + + @Override + public Optional<InlineResponse2001[]> getVnfPackages() { + try { + final ResponseEntity<VnfPkgInfo[]> response = + httpServiceProvider.getHttpResponse(etsiCatalogUrlProvider.getVnfPackagesUrl(), VnfPkgInfo[].class); + logger.info("getVnfPackages Request to ETSI Catalog Manager Status Code: {}", + response.getStatusCodeValue()); + if (response.getStatusCode() == HttpStatus.OK) { + if (response.hasBody()) { + final VnfPkgInfo[] vnfPackages = response.getBody(); + final InlineResponse2001[] responses = new InlineResponse2001[vnfPackages.length]; + for (int index = 0; index < vnfPackages.length; index++) { + if (conversionService.canConvert(vnfPackages[index].getClass(), InlineResponse2001.class)) { + final InlineResponse2001 inlineResponse2001 = + conversionService.convert(vnfPackages[index], InlineResponse2001.class); + if (inlineResponse2001 != null) { + responses[index] = inlineResponse2001; + } + } + logger.error("Unable to find Converter for response class: {}", vnfPackages[index].getClass()); + } + return Optional.ofNullable(responses); + } + logger.error("Received response without body ..."); + } + logger.error("Unexpected status code received {}", response.getStatusCode()); + return Optional.empty(); + } catch (final InvalidRestRequestException invalidRestRequestException) { + logger.error("Caught InvalidRestRequestException", invalidRestRequestException); + throw new VnfPkgBadRequestException("Error: Bad Request Received"); + } catch (final HttpResouceNotFoundException httpResouceNotFoundException) { + logger.error("Caught HttpResouceNotFoundException", httpResouceNotFoundException); + throw new VnfPkgNotFoundException("No Vnf Packages found"); + } catch (final RestProcessingException restProcessingException) { + logger.error("Caught RestProcessingException with Status Code: {}", restProcessingException.getStatusCode(), + restProcessingException); + throw new EtsiCatalogManagerRequestFailureException("Internal Server Error Occurred."); + } + } + + @Override + public Optional<InlineResponse2001> getVnfPackage(final String vnfPkgId) { + try { + final ResponseEntity<VnfPkgInfo> response = httpServiceProvider + .getHttpResponse(etsiCatalogUrlProvider.getVnfPackageUrl(vnfPkgId), VnfPkgInfo.class); + logger.info("getVnfPackage Request for vnfPkgId {} to ETSI Catalog Manager Status Code: {}", vnfPkgId, + response.getStatusCodeValue()); + if (response.getStatusCode() == HttpStatus.OK) { + if (response.hasBody()) { + final VnfPkgInfo vnfPkgInfo = response.getBody(); + if (conversionService.canConvert(vnfPkgInfo.getClass(), InlineResponse2001.class)) { + return Optional.ofNullable(conversionService.convert(vnfPkgInfo, InlineResponse2001.class)); + } + logger.error("Unable to find Converter for response class: {}", vnfPkgInfo.getClass()); + } + logger.error("Received response without body ...."); + } + return Optional.empty(); + } catch (final InvalidRestRequestException invalidRestRequestException) { + logger.error("Caught InvalidRestRequestException", invalidRestRequestException); + throw new VnfPkgBadRequestException("Error: Bad Request Received"); + } catch (final HttpResouceNotFoundException httpResouceNotFoundException) { + logger.error("Caught HttpResouceNotFoundException", httpResouceNotFoundException); + throw new VnfPkgNotFoundException("No Vnf Package found with vnfPkgId: " + vnfPkgId); + } catch (final RestProcessingException restProcessingException) { + logger.error("Caught RestProcessingException with Status Code: {}", restProcessingException.getStatusCode(), + restProcessingException); + throw new EtsiCatalogManagerRequestFailureException("Internal Server Error Occurred."); + } + } + + @Override + public Optional<byte[]> getVnfPackageVnfd(final String vnfPkgId) { + final String vnfRequestUrl = etsiCatalogUrlProvider.getVnfPackageVnfdUrl(vnfPkgId); + final String vnfRequestName = "getVnfPackageVnfd"; + return requestVnfElement(vnfPkgId, vnfRequestUrl, vnfRequestName); + } + + private Optional<byte[]> requestVnfElement(final String vnfPkgId, final String vnfRequestUrl, + final String vnfRequestName) { + try { + final ResponseEntity<byte[]> response = httpServiceProvider.getHttpResponse(vnfRequestUrl, byte[].class); + logger.info("{} Request to ETSI Catalog Manager Status Code: {}", vnfRequestName, + response.getStatusCodeValue()); + if (response.getStatusCode() == HttpStatus.OK) { + return Optional.ofNullable(response.getBody()); + } + } catch (final HttpResouceNotFoundException httpResouceNotFoundException) { + logger.error("Caught HttpResouceNotFoundException", httpResouceNotFoundException); + throw new VnfPkgNotFoundException("No Vnf Package found with vnfPkgId: " + vnfPkgId); + } catch (final RestProcessingException restProcessingException) { + logger.error("Caught RestProcessingException with Status Code: {}", restProcessingException.getStatusCode(), + restProcessingException); + if (restProcessingException.getStatusCode() == HttpStatus.CONFLICT.value()) { + throw new VnfPkgConflictException("A conflict occurred with the state of the resource,\n" + + "due to the attribute: onboardingState not being set to ONBOARDED."); + } + } + throw new EtsiCatalogManagerRequestFailureException("Internal Server Error Occurred."); + } +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/etsicatalog/EtsiCatalogUrlProvider.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/etsicatalog/EtsiCatalogUrlProvider.java new file mode 100644 index 0000000000..8382212d51 --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/etsicatalog/EtsiCatalogUrlProvider.java @@ -0,0 +1,102 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnfmadapter.extclients.etsicatalog; + +import static org.slf4j.LoggerFactory.getLogger; +import org.slf4j.Logger; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +/** + * Provides the URLs for the REST Requests to the ETSI Catalog Manager. + * + * @author gareth.roper@est.tech + */ +@Service +public class EtsiCatalogUrlProvider { + + private static final Logger logger = getLogger(EtsiCatalogUrlProvider.class); + + @Value("${etsi-catalog-manager.vnfpkgm.endpoint}") + private String etsiCatalogManagerEndpoint; + + public EtsiCatalogUrlProvider() {} + + /** + * Get the URL for retrieving the Package Content from the ETSI Catalog.". + * + * @param vnfPkgId The ID of the VNF Package + * @return the URL for the GET operation + */ + public String getVnfPackageContentUrl(final String vnfPkgId) { + final String url = etsiCatalogManagerEndpoint + "/vnf_packages/" + vnfPkgId + "/package_content"; + logger.info("getEtsiCatalogVnfPackageContentUrl: {}", url); + return url; + } + + /** + * Get the URL for retrieving VNF packages information from ETSI Catalog.". + * + * @return the URL for the GET operation + */ + public String getVnfPackagesUrl() { + final String url = etsiCatalogManagerEndpoint + "/vnf_packages"; + logger.info("getEtsiCatalogVnfPackagesEndpoint: {}", url); + return url; + } + + /** + * Get the URL for retrieving specific VNF package information from the ETSI Catalog.". + * + * @param vnfPkgId The ID of the VNF Package + * @return the URL for the GET operation + */ + public String getVnfPackageUrl(final String vnfPkgId) { + final String url = etsiCatalogManagerEndpoint + "/vnf_packages/" + vnfPkgId; + logger.info("getEtsiCatalogVnfPackageEndpoint: {}", url); + return url; + } + + /** + * Get the URL for retrieving VNF Package Artifacts + * + * @param vnfPkgId The ID of the VNF Package + * @param artifactPath The path to the Artifact + * @return the URL for the GET operation + */ + public String getVnfPackageArtifactUrl(final String vnfPkgId, final String artifactPath) { + final String url = etsiCatalogManagerEndpoint + "/vnf_packages/" + vnfPkgId + "/artifacts/" + artifactPath; + logger.info("getVnfPackageArtifactUrl: {}", url); + return url; + } + + /** + * Get the URL for retrieving VNF packages vnfd from ETSI Catalog. + * + * @param vnfPkgId The ID of the VNF Package + * @return the URL for the GET operation + */ + public String getVnfPackageVnfdUrl(final String vnfPkgId) { + final String url = etsiCatalogManagerEndpoint + "/vnf_packages/" + vnfPkgId + "/vnfd"; + logger.info("getEtsiCatalogVnfPackageVnfd: {}", url); + return url; + } +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProviderConfiguration.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProviderConfiguration.java index 93312cfa64..073fc93107 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProviderConfiguration.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProviderConfiguration.java @@ -21,7 +21,6 @@ package org.onap.so.adapters.vnfmadapter.extclients.vnfm; import static org.onap.so.client.RestTemplateConfig.CONFIGURABLE_REST_TEMPLATE; -import com.google.gson.Gson; import java.io.IOException; import java.security.KeyManagementException; import java.security.KeyStore; @@ -29,7 +28,7 @@ import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; -import java.util.Iterator; +import java.util.ListIterator; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -41,8 +40,10 @@ import org.apache.http.impl.client.HttpClients; import org.apache.http.ssl.SSLContextBuilder; import org.onap.aai.domain.yang.EsrSystemInfo; import org.onap.aai.domain.yang.EsrVnfm; -import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.JSON; +import org.onap.logging.filter.spring.SpringClientPayloadFilter; +import org.onap.so.adapters.vnfmadapter.extclients.AbstractServiceProviderConfiguration; import org.onap.so.configuration.rest.BasicHttpHeadersProvider; +import org.onap.so.logging.jaxrs.filter.SOSpringClientFilter; import org.onap.so.rest.service.HttpRestServiceProvider; import org.onap.so.rest.service.HttpRestServiceProviderImpl; import org.slf4j.Logger; @@ -53,10 +54,8 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.Resource; import org.springframework.http.client.BufferingClientHttpRequestFactory; +import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; -import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.http.converter.json.GsonHttpMessageConverter; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.security.oauth2.client.OAuth2RestTemplate; import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails; import org.springframework.web.client.RestTemplate; @@ -65,7 +64,7 @@ import org.springframework.web.client.RestTemplate; * Configures the HttpRestServiceProvider for REST call to a VNFM. */ @Configuration -public class VnfmServiceProviderConfiguration { +public class VnfmServiceProviderConfiguration extends AbstractServiceProviderConfiguration { private static final Logger logger = LoggerFactory.getLogger(VnfmServiceProviderConfiguration.class); private Map<String, HttpRestServiceProvider> mapOfVnfmIdToHttpRestServiceProvider = new ConcurrentHashMap<>(); @@ -131,17 +130,6 @@ public class VnfmServiceProviderConfiguration { return new OAuth2RestTemplate(resourceDetails); } - private void setGsonMessageConverter(final RestTemplate restTemplate) { - final Iterator<HttpMessageConverter<?>> iterator = restTemplate.getMessageConverters().iterator(); - while (iterator.hasNext()) { - if (iterator.next() instanceof MappingJackson2HttpMessageConverter) { - iterator.remove(); - } - } - final Gson gson = new JSON().getGson(); - restTemplate.getMessageConverters().add(new GsonHttpMessageConverter(gson)); - } - private void setTrustStore(final RestTemplate restTemplate) { SSLContext sslContext; try { @@ -167,4 +155,14 @@ public class VnfmServiceProviderConfiguration { } } + private void removeSpringClientFilter(final RestTemplate restTemplate) { + ListIterator<ClientHttpRequestInterceptor> interceptorIterator = restTemplate.getInterceptors().listIterator(); + while (interceptorIterator.hasNext()) { + ClientHttpRequestInterceptor interceptor = interceptorIterator.next(); + if (interceptor instanceof SOSpringClientFilter || interceptor instanceof SpringClientPayloadFilter) { + interceptorIterator.remove(); + } + } + } + } diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProviderImpl.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProviderImpl.java index 948f5fc269..d898de3ad0 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProviderImpl.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProviderImpl.java @@ -26,10 +26,13 @@ import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.CreateVnfRequest; import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse200; import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse2001; import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse201; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse201.InstantiationStateEnum; import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InstantiateVnfRequest; import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.LccnSubscriptionRequest; import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.TerminateVnfRequest; +import org.onap.so.adapters.vnfmadapter.jobmanagement.JobManager; import org.onap.so.adapters.vnfmadapter.rest.exceptions.VnfmRequestFailureException; +import org.onap.so.rest.exceptions.RestProcessingException; import org.onap.so.rest.service.HttpRestServiceProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -115,21 +118,27 @@ public class VnfmServiceProviderImpl implements VnfmServiceProvider { try { response = getHttpServiceProvider(vnfm).postHttpRequest(terminateVnfRequest, vnfSelfLink + "/terminate", Void.class); + } catch (final RestProcessingException restProcessingException) { + if (restProcessingException.getStatusCode() == HttpStatus.CONFLICT.value()) { + InlineResponse201 vnf = getVnf(vnfm, vnfSelfLink).get(); + if (vnf.getInstantiationState().equals(InstantiationStateEnum.NOT_INSTANTIATED)) { + return JobManager.ALREADY_COMPLETED_OPERATION_ID; + } else { + final String errorMessage = + "Terminate request to " + vnfSelfLink + " resulted in exception" + terminateVnfRequest; + logger.error(errorMessage, restProcessingException); + throw new VnfmRequestFailureException(errorMessage, restProcessingException); + } + } } catch (final Exception exception) { final String errorMessage = "Terminate request to " + vnfSelfLink + " resulted in exception" + terminateVnfRequest; logger.error(errorMessage, exception); throw new VnfmRequestFailureException(errorMessage, exception); } - if (response.getStatusCode() != HttpStatus.ACCEPTED) { - final String errorMessage = "Terminate request to " + vnfSelfLink + " returned status code: " - + response.getStatusCode() + ", request: " + terminateVnfRequest; - logger.error(errorMessage); - throw new VnfmRequestFailureException(errorMessage); - } + checkIfResponseIsAcceptable(response, vnfSelfLink, terminateVnfRequest); final String locationHeader = response.getHeaders().get("Location").iterator().next(); return locationHeader.substring(locationHeader.lastIndexOf("/") + 1); - } @Override @@ -162,6 +171,22 @@ public class VnfmServiceProviderImpl implements VnfmServiceProvider { } } + private void checkIfResponseIsAcceptable(ResponseEntity<Void> response, String vnfSelfLink, + TerminateVnfRequest terminateVnfRequest) { + if (response == null) { + final String errorMessage = + "Terminate request to " + vnfSelfLink + ", response is null, " + "request: " + terminateVnfRequest; + logger.error(errorMessage); + throw new VnfmRequestFailureException(errorMessage); + } + if (response.getStatusCode() != HttpStatus.ACCEPTED) { + final String errorMessage = "Terminate request to " + vnfSelfLink + ", returned status code: " + + response.getStatusCode() + ", request: " + terminateVnfRequest; + logger.error(errorMessage); + throw new VnfmRequestFailureException(errorMessage); + } + } + private HttpRestServiceProvider getHttpServiceProvider(final EsrVnfm vnfm) { return vnfmServiceProviderConfiguration.getHttpRestServiceProvider(vnfm); } diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/jobmanagement/JobManager.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/jobmanagement/JobManager.java index 68fdb79444..3de94ebe05 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/jobmanagement/JobManager.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/jobmanagement/JobManager.java @@ -29,6 +29,7 @@ import org.onap.so.adapters.vnfmadapter.extclients.aai.AaiServiceProvider; import org.onap.so.adapters.vnfmadapter.extclients.vnfm.VnfmServiceProvider; import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse200; import org.onap.so.adapters.vnfmadapter.rest.exceptions.JobNotFoundException; +import org.onap.so.rest.exceptions.HttpResouceNotFoundException; import org.onap.vnfmadapter.v1.model.OperationEnum; import org.onap.vnfmadapter.v1.model.OperationStateEnum; import org.onap.vnfmadapter.v1.model.OperationStatusRetrievalStatusEnum; @@ -42,6 +43,7 @@ import org.springframework.stereotype.Component; */ @Component public class JobManager { + public static final String ALREADY_COMPLETED_OPERATION_ID = "alreadyCompleted"; private static final String SEPARATOR = "_"; private static Logger logger = getLogger(JobManager.class); private final Map<String, VnfmOperation> mapOfJobIdToVnfmOperation = Maps.newConcurrentMap(); @@ -87,6 +89,11 @@ public class JobManager { throw new JobNotFoundException("No job found with ID: " + jobId); } + if (vnfmOperation.getOperationId().equals(ALREADY_COMPLETED_OPERATION_ID)) { + response.setOperationStatusRetrievalStatus(OperationStatusRetrievalStatusEnum.STATUS_FOUND); + return response.operationState(OperationStateEnum.COMPLETED); + } + if (vnfmOperation.isVnfDeleted()) { response.setOperationStatusRetrievalStatus(OperationStatusRetrievalStatusEnum.STATUS_FOUND); return response.operationState(getOperationState(vnfmOperation, null)); @@ -116,7 +123,7 @@ public class JobManager { response.setVnfInstanceId(operation.getVnfInstanceId()); return response; - } catch (final Exception exception) { + } catch (final HttpResouceNotFoundException exception) { logger.error("Exception encountered trying to get operation status for operation id " + vnfmOperation.getOperationId(), exception); return response.operationStatusRetrievalStatus(OperationStatusRetrievalStatusEnum.WAITING_FOR_STATUS); diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/lifecycle/LifecycleManager.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/lifecycle/LifecycleManager.java index 0aad91e5be..a885721b76 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/lifecycle/LifecycleManager.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/lifecycle/LifecycleManager.java @@ -24,6 +24,7 @@ import com.google.common.base.Optional; import java.util.Map; import org.onap.aai.domain.yang.EsrVnfm; import org.onap.aai.domain.yang.GenericVnf; +import org.onap.aai.domain.yang.Relationship; import org.onap.so.adapters.vnfmadapter.extclients.SdcPackageProvider; import org.onap.so.adapters.vnfmadapter.extclients.aai.AaiHelper; import org.onap.so.adapters.vnfmadapter.extclients.aai.AaiServiceProvider; @@ -81,21 +82,25 @@ public class LifecycleManager { * @return the response to the request */ public CreateVnfResponse createVnf(final String vnfIdInAai, final CreateVnfRequest request) { - final GenericVnf genericVnf = getGenericVnfFromAai(vnfIdInAai); + GenericVnf genericVnf = getGenericVnfFromAai(vnfIdInAai); EsrVnfm vnfm = aaiHelper.getAssignedVnfm(genericVnf); checkIfVnfAlreadyExistsInVnfm(vnfm, genericVnf); if (vnfm == null) { vnfm = aaiHelper.selectVnfm(genericVnf); - aaiHelper.addRelationshipFromGenericVnfToVnfm(genericVnf, vnfm.getVnfmId()); + aaiServiceProvider.invokePutGenericVnfToVnfmRelationship(genericVnf, vnfm.getVnfmId()); } - aaiHelper.addRelationshipFromGenericVnfToTenant(genericVnf, request.getTenant()); final InlineResponse201 vnfmResponse = sendCreateRequestToVnfm(request, genericVnf, vnfIdInAai, vnfm); logger.info("Create response: {}", vnfmResponse); genericVnf.setSelflink(getSelfLink(vnfmResponse, vnfm)); - aaiServiceProvider.invokePutGenericVnf(genericVnf); + + GenericVnf genericVnfPatch = new GenericVnf(); + genericVnfPatch.setVnfId(genericVnf.getVnfId()); + genericVnfPatch.setSelflink(genericVnf.getSelflink()); + aaiServiceProvider.invokePatchGenericVnf(genericVnfPatch); + final String vnfIdInVnfm = vnfmResponse.getId(); final OamIpAddressSource oamIpAddressSource = extractOamIpAddressSource(request); @@ -203,6 +208,10 @@ public class LifecycleManager { final EsrVnfm vnfm = getAssignedVnfm(genericVnf); final String operationId = sendTerminateRequestToVnfm(vnfm, genericVnf); + + if (operationId.equals(JobManager.ALREADY_COMPLETED_OPERATION_ID)) { + sendDeleteRequestToVnfm(genericVnf); + } final String jobId = jobManager.createJob(vnfm.getVnfmId(), operationId, true); return new DeleteVnfResponse().jobId(jobId); @@ -230,4 +239,27 @@ public class LifecycleManager { } return vnfm; } + + private void sendDeleteRequestToVnfm(final GenericVnf genericVnf) { + + vnfmServiceProvider.deleteVnf(aaiHelper.getAssignedVnfm(genericVnf), genericVnf.getSelflink()); + + final GenericVnf genericVnfPatch = new GenericVnf(); + genericVnfPatch.setVnfId(genericVnf.getVnfId()); + genericVnfPatch.setOrchestrationStatus("Assigned"); + genericVnfPatch.setSelflink(""); + aaiServiceProvider.invokePatchGenericVnf(genericVnfPatch); + + for (final Relationship relationship : genericVnf.getRelationshipList().getRelationship()) { + if (relationship.getRelatedTo().equals("vserver")) { + aaiServiceProvider.invokeDeleteVserver( + aaiHelper.getRelationshipData(relationship, "cloud-region.cloud-owner"), + aaiHelper.getRelationshipData(relationship, "cloud-region.cloud-region-id"), + aaiHelper.getRelationshipData(relationship, "tenant.tenant-id"), + aaiHelper.getRelationshipData(relationship, "vserver.vserver-id")); + } + } + + + } } diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/notificationhandling/NotificationHandler.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/notificationhandling/NotificationHandler.java index eb912c8775..63ec4ccc57 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/notificationhandling/NotificationHandler.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/notificationhandling/NotificationHandler.java @@ -97,10 +97,12 @@ public class NotificationHandler implements Runnable { private void handleVnfInstantiateCompleted() { final GenericVnf genericVnf = aaiServiceProvider .invokeQueryGenericVnf(vnfInstance.getLinks().getSelf().getHref()).getGenericVnf().get(0); - setOamIpAddress(genericVnf, vnfInstance); - genericVnf.setOrchestrationStatus("Created"); - aaiServiceProvider.invokePutGenericVnf(genericVnf); + final GenericVnf genericVnfPatch = new GenericVnf(); + genericVnfPatch.setVnfId(genericVnf.getVnfId()); + setOamIpAddress(genericVnfPatch, vnfInstance); + genericVnfPatch.setOrchestrationStatus("Created"); + aaiServiceProvider.invokePatchGenericVnf(genericVnfPatch); addVservers(vnfLcmOperationOccurrenceNotification, genericVnf.getVnfId(), vnfInstance.getVimConnectionInfo()); @@ -143,28 +145,31 @@ public class NotificationHandler implements Runnable { } private void handleVnfTerminateFailed() { - final GenericVnf genericVnf = aaiServiceProvider - .invokeQueryGenericVnf(vnfInstance.getLinks().getSelf().getHref()).getGenericVnf().get(0); - deleteVservers(vnfLcmOperationOccurrenceNotification, genericVnf); - jobManager.notificationProcessedForOperation(vnfLcmOperationOccurrenceNotification.getVnfLcmOpOccId(), false); + try { + final GenericVnf genericVnf = aaiServiceProvider + .invokeQueryGenericVnf(vnfInstance.getLinks().getSelf().getHref()).getGenericVnf().get(0); + deleteVserversFromAai(vnfLcmOperationOccurrenceNotification, genericVnf); + } finally { + jobManager.notificationProcessedForOperation(vnfLcmOperationOccurrenceNotification.getVnfLcmOpOccId(), + false); + } } private void handleVnfTerminateCompleted() { - final GenericVnf genericVnf = aaiServiceProvider - .invokeQueryGenericVnf(vnfInstance.getLinks().getSelf().getHref()).getGenericVnf().get(0); - deleteVservers(vnfLcmOperationOccurrenceNotification, genericVnf); - - boolean deleteSuccessful = false; + GenericVnf genericVnf = null; + boolean vServersDeletedFromAai = false; + boolean identifierDeletedFromVnfm = false; + boolean genericVnfUpdated = false; try { - vnfmServiceProvider.deleteVnf(aaiHelper.getAssignedVnfm(genericVnf), genericVnf.getSelflink()); - deleteSuccessful = true; + genericVnf = aaiServiceProvider.invokeQueryGenericVnf(vnfInstance.getLinks().getSelf().getHref()) + .getGenericVnf().get(0); + vServersDeletedFromAai = deleteVserversFromAai(vnfLcmOperationOccurrenceNotification, genericVnf); + identifierDeletedFromVnfm = deleteVnfIdentifierOnVnfm(genericVnf); + genericVnfUpdated = patchVnfInAai(genericVnf.getVnfId(), "Assigned", identifierDeletedFromVnfm ? "" : null); } finally { jobManager.notificationProcessedForOperation(vnfLcmOperationOccurrenceNotification.getVnfLcmOpOccId(), - deleteSuccessful); + vServersDeletedFromAai && identifierDeletedFromVnfm && genericVnfUpdated); jobManager.vnfDeleted(vnfLcmOperationOccurrenceNotification.getVnfLcmOpOccId()); - genericVnf.setOrchestrationStatus("Assigned"); - genericVnf.setSelflink(""); - aaiServiceProvider.invokePutGenericVnf(genericVnf); } } @@ -180,27 +185,69 @@ public class NotificationHandler implements Runnable { getVimConnectionInfo(vimConnectionIdToVimConnectionInfo, vnfc); if (ChangeTypeEnum.ADDED.equals(vnfc.getChangeType())) { final Vserver vserver = aaiHelper.createVserver(vnfc); - aaiHelper.addRelationshipFromVserverVnfToGenericVnf(vserver, vnfId); - aaiServiceProvider.invokePutVserver(getCloudOwner(vimConnectionInfo), getCloudRegion(vimConnectionInfo), getTenant(vimConnectionInfo), vserver); + + aaiServiceProvider.invokePutVserverToVnfRelationship(getCloudOwner(vimConnectionInfo), + getCloudRegion(vimConnectionInfo), getTenant(vimConnectionInfo), vserver, vnfId); } } } - private void deleteVservers(final VnfLcmOperationOccurrenceNotification notification, final GenericVnf vnf) { - for (final LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs vnfc : notification.getAffectedVnfcs()) { - if (ChangeTypeEnum.REMOVED.equals(vnfc.getChangeType())) { + private boolean deleteVserversFromAai(final VnfLcmOperationOccurrenceNotification notification, + final GenericVnf vnf) { + try { + for (final LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs vnfc : notification.getAffectedVnfcs()) { + if (ChangeTypeEnum.REMOVED.equals(vnfc.getChangeType())) { - final Relationship relationshipToVserver = aaiHelper.deleteRelationshipWithDataValue(vnf, "vserver", - "vserver.vserver-id", vnfc.getComputeResource().getResourceId()); + final Relationship relationshipToVserver = aaiHelper.deleteRelationshipWithDataValue(vnf, "vserver", + "vserver.vserver-id", vnfc.getComputeResource().getResourceId()); - aaiServiceProvider.invokeDeleteVserver( - aaiHelper.getRelationshipData(relationshipToVserver, "cloud-region.cloud-owner"), - aaiHelper.getRelationshipData(relationshipToVserver, "cloud-region.cloud-region-id"), - aaiHelper.getRelationshipData(relationshipToVserver, "tenant.tenant-id"), - vnfc.getComputeResource().getResourceId()); + aaiServiceProvider.invokeDeleteVserver( + aaiHelper.getRelationshipData(relationshipToVserver, "cloud-region.cloud-owner"), + aaiHelper.getRelationshipData(relationshipToVserver, "cloud-region.cloud-region-id"), + aaiHelper.getRelationshipData(relationshipToVserver, "tenant.tenant-id"), + vnfc.getComputeResource().getResourceId()); + } } + return true; + } catch (final Exception exception) { + logger.error( + "Error encountered deleting vservers based on received notification, AAI may not be updated correctly " + + vnfLcmOperationOccurrenceNotification, + exception); + return false; + } + } + + private boolean deleteVnfIdentifierOnVnfm(GenericVnf genericVnf) { + try { + vnfmServiceProvider.deleteVnf(aaiHelper.getAssignedVnfm(genericVnf), genericVnf.getSelflink()); + return true; + } catch (Exception exception) { + logger.error("Exception deleting the identifier " + genericVnf.getSelflink() + + " from the VNFM. The VNF has been terminated successfully but the identifier will remain on the VNFM.", + exception); + return false; + } + } + + private boolean patchVnfInAai(final String vnfId, final String orchestrationStatus, final String selfLink) { + try { + final GenericVnf genericVnfPatch = new GenericVnf(); + genericVnfPatch.setVnfId(vnfId); + genericVnfPatch.setOrchestrationStatus(orchestrationStatus); + if (selfLink != null) { + genericVnfPatch.setSelflink(selfLink); + } + aaiServiceProvider.invokePatchGenericVnf(genericVnfPatch); + return true; + } catch (final Exception exception) { + logger.error( + "Error encountered setting orchestration status and/or self link based on received notification, AAI may not be updated correctly " + + vnfLcmOperationOccurrenceNotification, + exception); + return false; } } diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/Sol003PackageManagementController.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/Sol003PackageManagementController.java new file mode 100644 index 0000000000..9d8e29b3f9 --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/Sol003PackageManagementController.java @@ -0,0 +1,188 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnfmadapter.rest; + +import static org.onap.so.adapters.vnfmadapter.Constants.APPLICATION_ZIP; +import static org.onap.so.adapters.vnfmadapter.Constants.PACKAGE_MANAGEMENT_BASE_URL; +import static org.slf4j.LoggerFactory.getLogger; +import java.util.Optional; +import javax.ws.rs.core.MediaType; +import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.EtsiCatalogServiceProvider; +import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.model.ProblemDetails; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.InlineResponse2001; +import org.slf4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; + +/** + * Controller for handling the VNF Package Management. For further information please read: + * https://www.etsi.org/deliver/etsi_gs/NFV-SOL/001_099/003/02.05.01_60/gs_nfv-sol003v020501p.pdf Use the section number + * above each endpoint to find the corresponding section in the above document. + * + * @author gareth.roper@est.tech + */ +@Controller +@RequestMapping(value = PACKAGE_MANAGEMENT_BASE_URL, consumes = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) +public class Sol003PackageManagementController { + + private final EtsiCatalogServiceProvider etsiCatalogServiceProvider; + private static final String LOG_REQUEST_RECEIVED = "VNF PackageManagement Controller: {} {} {} {}"; + private static final Logger logger = getLogger(Sol003PackageManagementController.class); + + @Autowired + Sol003PackageManagementController(final EtsiCatalogServiceProvider etsiCatalogServiceProvider) { + this.etsiCatalogServiceProvider = etsiCatalogServiceProvider; + } + + /** + * GET VNF packages information. Will return zero or more VNF package representations that match the attribute + * filter. These representations will be in a list. Section Number: 10.4.2 + * + * @return An Array of all VNF packages. Object: InlineResponse2001[] Response Code: 200 OK + */ + @GetMapping(value = "/vnf_packages", produces = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public ResponseEntity<?> getVnfPackages() { + logger.info(LOG_REQUEST_RECEIVED, "getVnfPackages."); + final Optional<InlineResponse2001[]> response = etsiCatalogServiceProvider.getVnfPackages(); + if (response.isPresent()) { + logger.info(LOG_REQUEST_RECEIVED, "getVnfPackages Response: ", HttpStatus.OK); + return ResponseEntity.ok().body(response.get()); + } + final String errorMessage = "An error occurred, a null response was received by the\n" + + " Sol003PackageManagementController from the EtsiCatalogManager using the GET \"vnf_packages\" \n" + + "endpoint."; + logger.error(errorMessage); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(buildProblemDetails(errorMessage)); + } + + /** + * GET VNF package information. Will return a specific VNF package representation that match the attribute filter. + * Section Number: 10.4.3 + * + * @param vnfPkgId The ID of the VNF Package that you want to query. + * @return A VNF package based on vnfPkgId. Object: VnfPkgInfo Response Code: 200 OK + */ + @GetMapping(value = "/vnf_packages/{vnfPkgId}", produces = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public ResponseEntity<?> getVnfPackage(@PathVariable("vnfPkgId") final String vnfPkgId) { + logger.info(LOG_REQUEST_RECEIVED, "getVnfPackage: ", vnfPkgId); + final Optional<InlineResponse2001> response = etsiCatalogServiceProvider.getVnfPackage(vnfPkgId); + if (response.isPresent()) { + logger.info(LOG_REQUEST_RECEIVED, "getVnfPackage Response: ", HttpStatus.OK); + return ResponseEntity.ok().body(response.get()); + } + final String errorMessage = "An error occurred, a null response was received by the\n" + + " Sol003PackageManagementController from the EtsiCatalogManager using the GET \"vnf_packages\" by vnfPkgId: \"" + + vnfPkgId + "\" \n" + "endpoint."; + logger.error(errorMessage); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(buildProblemDetails(errorMessage)); + } + + /** + * GET VNFD, from VNF package. Will return a copy of the file representing the VNFD or a ZIP file that contains the + * file/multiple files representing the VNFD specified. Section Number: 10.4.4 + * + * @param vnfPkgId The ID of the VNF Package that you want to retrieve the VNFD from. + * @return The VNFD of a VNF Package as a single file or within a ZIP file. Object: byte[] Response Code: 200 OK + */ + @GetMapping(value = "/vnf_packages/{vnfPkgId}/vnfd", + produces = {MediaType.TEXT_PLAIN, APPLICATION_ZIP, MediaType.APPLICATION_JSON}) + public ResponseEntity<byte[]> getVnfPackageVnfd(@PathVariable("vnfPkgId") final String vnfPkgId) { + logger.info(LOG_REQUEST_RECEIVED, "getVnfPackageVnfd Endpoint Invoked with VNF Package ID: ", vnfPkgId); + final Optional<byte[]> response = etsiCatalogServiceProvider.getVnfPackageVnfd(vnfPkgId); + if (response.isPresent()) { + logger.info(LOG_REQUEST_RECEIVED, "getVnfPackageVnfd Response: ", HttpStatus.OK); + return new ResponseEntity(response.get(), HttpStatus.OK); + } + final String errorMessage = "An error occurred, a null response was received by the\n" + + " Sol003PackageManagementController from the EtsiCatalogManager using the GET \"vnfd\" \n" + + "endpoint."; + + logger.error(errorMessage); + return new ResponseEntity(buildProblemDetails(errorMessage), HttpStatus.INTERNAL_SERVER_ERROR); + } + + /** + * GET Package Content, from VNF Package. Will return a copy of the VNF package file that you specified. Section + * Number: 10.4.5 + * + * @param vnfPkgId The ID of the VNF Package that you want to retrieve the "package_content" from. + * @return The Package Content of a VNF Package. Object: byte[] Response Code: 200 OK + */ + @GetMapping(value = "/vnf_packages/{vnfPkgId}/package_content", + produces = {MediaType.APPLICATION_JSON, APPLICATION_ZIP, MediaType.APPLICATION_OCTET_STREAM}) + public ResponseEntity<?> getVnfPackageContent(@PathVariable("vnfPkgId") final String vnfPkgId) { + logger.info(LOG_REQUEST_RECEIVED, "getVnfPackageContent Endpoint Invoked with VNF Package ID: ", vnfPkgId); + final Optional<byte[]> response = etsiCatalogServiceProvider.getVnfPackageContent(vnfPkgId); + if (response.isPresent()) { + logger.info(LOG_REQUEST_RECEIVED, "getVnfPackageContent Response: ", HttpStatus.OK); + return ResponseEntity.ok().body(response.get()); + } + final String errorMessage = "An error occurred, a null response was received by the\n" + + " Sol003PackageManagementController from the EtsiCatalogManager using the GET \"package_content\" \n" + + "endpoint."; + logger.error(errorMessage); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(buildProblemDetails(errorMessage)); + } + + /** + * GET Artifact, from VNF Package Will return a the content of the artifact that you specified. Section Number: + * 10.4.6 + * + * @param vnfPkgId The ID of the VNF Package that you want to retrieve an artifact from. + * @param artifactPath The path of the artifact that you want to retrieve. + * @return An Artifact from a VNF Package. Object: byte[] Response Code: 200 OK + */ + @GetMapping(value = "/vnf_packages/{vnfPkgId}/artifacts/{artifactPath}", + produces = {MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_JSON}) + public ResponseEntity<?> getVnfPackageArtifact(@PathVariable("vnfPkgId") final String vnfPkgId, + @PathVariable("artifactPath") final String artifactPath) { + logger.info(LOG_REQUEST_RECEIVED, "getVnfPackageArtifact: vnfPkgId= ", vnfPkgId, " artifactPath=", + artifactPath); + final Optional<byte[]> response = etsiCatalogServiceProvider.getVnfPackageArtifact(vnfPkgId, artifactPath); + if (response.isPresent()) { + logger.info(LOG_REQUEST_RECEIVED, "getVnfPackageArtifact Response: ", HttpStatus.OK); + return ResponseEntity.ok().body(response.get()); + } + final String errorMessage = "An error occurred, a null response was received by the\n" + + " Sol003PackageManagementController from the EtsiCatalogManager using the\n GET \"vnf_packages\" by vnfPkgId: \"" + + vnfPkgId + "\" for artifactPath: \"" + artifactPath + "\"\n" + "endpoint."; + logger.error(errorMessage); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(buildProblemDetails(errorMessage)); + } + + /** + * Builds the ProblemDetails Object, using the provided error message. + * + * @param detail The error message retrieved from the exception thrown. + * @return ProblemDetails Object, containing error information. + */ + private ProblemDetails buildProblemDetails(final String detail) { + final ProblemDetails problemDetails = new ProblemDetails(); + problemDetails.setDetail(detail); + return problemDetails; + } + +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/Sol003SubscriptionManagementController.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/Sol003SubscriptionManagementController.java new file mode 100644 index 0000000000..16650d4a3d --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/Sol003SubscriptionManagementController.java @@ -0,0 +1,107 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnfmadapter.rest; + +import static org.onap.so.adapters.vnfmadapter.Constants.PACKAGE_MANAGEMENT_BASE_URL; +import static org.slf4j.LoggerFactory.getLogger; +import java.util.List; +import javax.ws.rs.core.MediaType; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.InlineResponse2002; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.PkgmSubscriptionRequest; +import org.slf4j.Logger; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; + +/** + * Controller for handling the Subscription Management. For further information please read: + * https://www.etsi.org/deliver/etsi_gs/NFV-SOL/001_099/003/02.05.01_60/gs_nfv-sol003v020501p.pdf Use the section number + * above each endpoint to find the corresponding section in the above document. + * + * @author gareth.roper@est.tech + */ +@Controller +@RequestMapping(value = PACKAGE_MANAGEMENT_BASE_URL, produces = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}, + consumes = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) +public class Sol003SubscriptionManagementController { + + private static final String LOG_REQUEST_RECEIVED = "Subscription Management Controller: {} {}"; + private static final Logger logger = getLogger(Sol003SubscriptionManagementController.class); + + /** + * POST Subscribe request. Will send request and respond with the subscription that you subscribed to, if + * successful. Section Number: 10.4.7 + * + * @param pkgmSubscriptionRequest This includes the details of the subscription to be created. + * @return The subscription requested, if successful. Object: InlineRespone2002 Response Code: 201 Created Response + * Code: 303 Duplicate Subscription + */ + @PostMapping(value = "/subscriptions") + public ResponseEntity<InlineResponse2002> postSubscriptionRequest( + @RequestBody final PkgmSubscriptionRequest pkgmSubscriptionRequest) { + logger.info(LOG_REQUEST_RECEIVED, " postSubscriptionRequest: ", pkgmSubscriptionRequest); + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + } + + /** + * GET all subscriptions. Will return a list of all subscriptions currently active. Section Number: 10.4.7 + * + * @return All of the current active subscriptions. Object: List<InlineResponse2002> Response Code: 200 OK + */ + @GetMapping(value = "/subscriptions") + public ResponseEntity<List<InlineResponse2002>> getSubscriptions() { + logger.info(LOG_REQUEST_RECEIVED, " getSubscriptions."); + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + } + + /** + * GET a specific subscription, by subscriptionId. Section Number: 10.4.8 + * + * @param subscriptionId The ID of the subscription that you wish to retrieve. + * @return A subscription based on subscriptionId. Object: InlineResponse2002 Response Code: 200 OK + */ + @GetMapping(value = "/subscriptions/{subscriptionId}") + public ResponseEntity<InlineResponse2002> getSubscription( + @PathVariable("subscriptionId") final String subscriptionId) { + logger.info(LOG_REQUEST_RECEIVED, " Getting Subscription: ", subscriptionId); + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + } + + /** + * DELETE a specific subscription, by subscriptionId. Section Number: 10.4.7 + * + * @param subscriptionId The ID of the subscription that you wish to delete. + * @return Empty response if successful. Object: Void Response Code: 204 No Content + */ + @DeleteMapping(value = "/subscriptions/{subscriptionId}") + public ResponseEntity<Void> deleteSubscription(@PathVariable("subscriptionId") final String subscriptionId) { + logger.info(LOG_REQUEST_RECEIVED, " Deleting Subscription: ", subscriptionId); + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + } + + +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/EtsiCatalogManagerRequestFailureException.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/EtsiCatalogManagerRequestFailureException.java new file mode 100644 index 0000000000..dbdc354f4e --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/EtsiCatalogManagerRequestFailureException.java @@ -0,0 +1,43 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.onap.so.adapters.vnfmadapter.rest.exceptions; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +/** + * Exception for an ETSI Catalog Manager Request Failure + * + * @author gareth.roper@est.tech + */ +@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR) +public class EtsiCatalogManagerRequestFailureException extends RuntimeException { + + private static final long serialVersionUID = 66862444537194516L; + + public EtsiCatalogManagerRequestFailureException(final String message) { + super(message); + } + + @Override + public synchronized Throwable fillInStackTrace() { + return this; + } +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/Sol003PackageManagementControllerExceptionHandler.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/Sol003PackageManagementControllerExceptionHandler.java new file mode 100644 index 0000000000..a49063a72f --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/Sol003PackageManagementControllerExceptionHandler.java @@ -0,0 +1,74 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnfmadapter.rest.exceptions; + +import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.model.ProblemDetails; +import org.onap.so.adapters.vnfmadapter.rest.Sol003PackageManagementController; +import org.onap.so.adapters.vnfmadapter.rest.exceptions.EtsiCatalogManagerRequestFailureException; +import org.onap.so.adapters.vnfmadapter.rest.exceptions.VnfPkgBadRequestException; +import org.onap.so.adapters.vnfmadapter.rest.exceptions.VnfPkgConflictException; +import org.onap.so.adapters.vnfmadapter.rest.exceptions.VnfPkgNotFoundException; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +/** + * Exception Handler for the Package Management Controller {@link Sol003PackageManagementController Sol003Controller} + * + * @author gareth.roper@est.tech + */ +@ControllerAdvice(assignableTypes = Sol003PackageManagementController.class) + +public class Sol003PackageManagementControllerExceptionHandler { + + @ExceptionHandler(EtsiCatalogManagerRequestFailureException.class) + public ResponseEntity<ProblemDetails> handleEtsiCatalogManagerRequestFailureException( + final EtsiCatalogManagerRequestFailureException etsiCatalogManagerRequestFailureException) { + final ProblemDetails problemDetails = new ProblemDetails(); + problemDetails.setDetail(etsiCatalogManagerRequestFailureException.getMessage()); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(problemDetails); + } + + @ExceptionHandler(VnfPkgConflictException.class) + public ResponseEntity<ProblemDetails> handleVnfPkgConflictException( + final VnfPkgConflictException vnfPkgConflictException) { + final ProblemDetails problemDetails = new ProblemDetails(); + problemDetails.setDetail(vnfPkgConflictException.getMessage()); + return ResponseEntity.status(HttpStatus.CONFLICT).body(problemDetails); + } + + @ExceptionHandler(VnfPkgNotFoundException.class) + public ResponseEntity<ProblemDetails> handleVnfPkgNotFoundException( + final VnfPkgNotFoundException vnfPkgNotFoundException) { + final ProblemDetails problemDetails = new ProblemDetails(); + problemDetails.setDetail(vnfPkgNotFoundException.getMessage()); + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(problemDetails); + } + + @ExceptionHandler(VnfPkgBadRequestException.class) + public ResponseEntity<ProblemDetails> handleVnfPkgBadRequestException( + final VnfPkgBadRequestException vnfPkgBadRequestException) { + final ProblemDetails problemDetails = new ProblemDetails(); + problemDetails.setDetail(vnfPkgBadRequestException.getMessage()); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(problemDetails); + } +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/VnfPkgBadRequestException.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/VnfPkgBadRequestException.java new file mode 100644 index 0000000000..211131c2a4 --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/VnfPkgBadRequestException.java @@ -0,0 +1,43 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.onap.so.adapters.vnfmadapter.rest.exceptions; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +/** + * Exception for a Vnfpkg Bad Request failure, due to state of resource. + * + * @author andrew.a.lamb@est.tech + */ +@ResponseStatus(code = HttpStatus.BAD_REQUEST) +public class VnfPkgBadRequestException extends RuntimeException { + + private static final long serialVersionUID = 3301317418914258411L; + + public VnfPkgBadRequestException(final String message) { + super(message); + } + + @Override + public synchronized Throwable fillInStackTrace() { + return this; + } +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/VnfPkgConflictException.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/VnfPkgConflictException.java new file mode 100644 index 0000000000..f9aa2a0e21 --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/VnfPkgConflictException.java @@ -0,0 +1,43 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.onap.so.adapters.vnfmadapter.rest.exceptions; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +/** + * Exception for a VnfPkg Conflict failures, due to state of resource. + * + * @author gareth.roper@est.tech + */ +@ResponseStatus(code = HttpStatus.CONFLICT) +public class VnfPkgConflictException extends RuntimeException { + + private static final long serialVersionUID = 26862444537198441L; + + public VnfPkgConflictException(final String message) { + super(message); + } + + @Override + public synchronized Throwable fillInStackTrace() { + return this; + } +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/VnfPkgNotFoundException.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/VnfPkgNotFoundException.java new file mode 100644 index 0000000000..c15e7052ab --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/VnfPkgNotFoundException.java @@ -0,0 +1,43 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.onap.so.adapters.vnfmadapter.rest.exceptions; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +/** + * Exception for VnfPkg Not Found Failures + * + * @author gareth.roper@est.tech + */ +@ResponseStatus(code = HttpStatus.NOT_FOUND) +public class VnfPkgNotFoundException extends RuntimeException { + + private static final long serialVersionUID = 26862444537198441L; + + public VnfPkgNotFoundException(final String message) { + super(message); + } + + @Override + public synchronized Throwable fillInStackTrace() { + return this; + } +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/resources/application-aaf.yaml b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/resources/application-aaf.yaml new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/resources/application-aaf.yaml diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/resources/application-basic.yaml b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/resources/application-basic.yaml new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/resources/application-basic.yaml diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/resources/application.yaml b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/resources/application.yaml index 4434d2edd9..57dc08f3b5 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/resources/application.yaml +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/resources/application.yaml @@ -23,22 +23,13 @@ spring: http: converters: preferred-json-mapper: gson - -http: - client: - ssl: - trust-store: classpath:org.onap.so.trust.jks - trust-store-password: ',sx#.C*W)]wVgJC6ccFHI#:H' - + main: + allow-bean-definition-overriding: true + server: port: 9092 tomcat: max-threads: 50 - ssl: - key-alias: so@so.onap.org - key--store-password: 'ywsqCy:EEo#j}HJHM7z^Rk[L' - key-store: classpath:so-vnfm-adapter.p12 - key-store-type: PKCS12 mso: key: 07a7159d3bf51a0e53be7a8f89699be7 @@ -55,7 +46,7 @@ sdc: endpoint: http://sdc.onap/1234A vnfmadapter: - endpoint: https://so-vnfm-adapter.onap:9092 + endpoint: http://so-vnfm-adapter.onap:9092 #Actuator management: diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/Sol003LcnControllerTest.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/Sol003LcnControllerTest.java index 89a2c102f4..cd92d987d7 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/Sol003LcnControllerTest.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/Sol003LcnControllerTest.java @@ -73,6 +73,7 @@ import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse201L import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse201LinksSelf; import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse201VimConnectionInfo; import org.onap.so.client.aai.AAIResourcesClient; +import org.onap.so.client.aai.AAIVersion; import org.onap.so.client.aai.entities.uri.AAIResourceUri; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -212,12 +213,16 @@ public class Sol003LcnControllerTest { final Vserver vserver = (Vserver) bodyArgument2.getAllValues().get(0); assertEquals("myVnfc1", vserver.getVserverId()); - final Relationship relationship = vserver.getRelationshipList().getRelationship().get(0); - assertEquals("generic-vnf", relationship.getRelatedTo()); - assertEquals("tosca.relationships.HostedOn", relationship.getRelationshipLabel()); - assertEquals("/aai/v15/network/generic-vnfs/generic-vnf/myTestVnfId", relationship.getRelatedLink()); - assertEquals("generic-vnf.vnf-id", relationship.getRelationshipData().get(0).getRelationshipKey()); - assertEquals("myTestVnfId", relationship.getRelationshipData().get(0).getRelationshipValue()); + + final ArgumentCaptor<AAIResourceUri> uriArgument1Connect = ArgumentCaptor.forClass(AAIResourceUri.class); + final ArgumentCaptor<AAIResourceUri> uriArgument2Connect = ArgumentCaptor.forClass(AAIResourceUri.class); + verify(aaiResourcesClient, timeout(1000)).connect(uriArgument1Connect.capture(), uriArgument2Connect.capture()); + assertEquals( + "/cloud-infrastructure/cloud-regions/cloud-region/" + CLOUD_OWNER + "/" + REGION + "/tenants/tenant/" + + TENANT_ID + "/vservers/vserver/myVnfc1", + uriArgument1Connect.getAllValues().get(0).build().toString()); + assertEquals("/network/generic-vnfs/generic-vnf/myTestVnfId", + uriArgument2Connect.getAllValues().get(0).build().toString()); } @Test diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/Sol003PackageManagementControllerTest.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/Sol003PackageManagementControllerTest.java new file mode 100644 index 0000000000..c5194cf27e --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/Sol003PackageManagementControllerTest.java @@ -0,0 +1,655 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnfmadapter.rest; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.onap.so.adapters.vnfmadapter.Constants.PACKAGE_MANAGEMENT_BASE_URL; +import static org.onap.so.client.RestTemplateConfig.CONFIGURABLE_REST_TEMPLATE; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.onap.so.adapters.vnfmadapter.VnfmAdapterApplication; +import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.model.Checksum; +import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.model.ProblemDetails; +import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.model.UriLink; +import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.model.VNFPKGMLinkSerializer; +import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.model.VnfPackageArtifactInfo; +import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.model.VnfPackageSoftwareImageInfo; +import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.model.VnfPkgInfo; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.InlineResponse2001; +import org.onap.so.configuration.rest.BasicHttpHeadersProvider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.client.MockRestServiceServer; +import org.springframework.web.client.RestTemplate; +import com.google.gson.Gson; + +/** + * @author gareth.roper@est.tech + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = VnfmAdapterApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ActiveProfiles("test") +public class Sol003PackageManagementControllerTest { + + @LocalServerPort + private int port; + + @Autowired + @Qualifier(CONFIGURABLE_REST_TEMPLATE) + private RestTemplate testRestTemplate; + + @Autowired + private TestRestTemplate restTemplate; + + private static final String VNF_PACKAGE_ID = "myVnfPackageId"; + private static final String ARTIFACT_PATH = "myArtifactPath"; + private static final String MSB_BASE_URL = "http://msb-iag.onap:80/api/vnfpkgm/v1/vnf_packages"; + private static final String VNFPKGM_BASE_URL = PACKAGE_MANAGEMENT_BASE_URL + "/vnf_packages"; + private static final String localhostUrl = "http://localhost:"; + private static final String GET_VNF_PACKAGES_URL = ""; + private static final String GET_VNF_PACKAGE_BY_ID_URL = "/" + VNF_PACKAGE_ID; + private static final String VNFD_ID = "vnfdId"; + private static final String VNF_PROVIDER = "vnfProvider"; + private static final String VNF_PRODUCT_NAME = "vnfProductName"; + private static final String VNF_SOFTWARE_VERSION = "vnfSoftwareVersion"; + private static final String VNFD_VERSION = "vnfdVersion"; + private static final String ALGORITHM = "algorithm"; + private static final String HASH = "hash"; + private static final String URI_HREF = "uriHref"; + + private MockRestServiceServer mockRestServer; + private BasicHttpHeadersProvider basicHttpHeadersProvider; + private final Gson gson = new Gson(); + + public Sol003PackageManagementControllerTest() {} + + @Before + public void setUp() { + final MockRestServiceServer.MockRestServiceServerBuilder builder = + MockRestServiceServer.bindTo(testRestTemplate); + builder.ignoreExpectOrder(true); + mockRestServer = builder.build(); + basicHttpHeadersProvider = new BasicHttpHeadersProvider(); + } + + @Test + public void testGetPackageContent_ValidArray_Success() { + final byte[] responseArray = buildByteArrayWithRandomData(10); + + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID + "/package_content")) + .andExpect(method(HttpMethod.GET)) + .andRespond(withSuccess(responseArray, MediaType.APPLICATION_OCTET_STREAM)); + + final String testURL = "http://localhost:" + port + PACKAGE_MANAGEMENT_BASE_URL + "/vnf_packages/" + + VNF_PACKAGE_ID + "/package_content"; + final HttpEntity<?> request = new HttpEntity<>(basicHttpHeadersProvider.getHttpHeaders()); + final ResponseEntity<byte[]> responseEntity = + restTemplate.withBasicAuth("test", "test").exchange(testURL, HttpMethod.GET, request, byte[].class); + + assertEquals(byte[].class, responseEntity.getBody().getClass()); + assertArrayEquals(responseEntity.getBody(), responseArray); + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + } + + @Test + public void testOnGetPackageContent_Conflict_Fail() { + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID + "/package_content")) + .andExpect(method(HttpMethod.GET)).andRespond(withStatus(HttpStatus.CONFLICT)); + + final ResponseEntity<ProblemDetails> responseEntity = sendHttpRequest(VNF_PACKAGE_ID + "/package_content"); + + assertTrue(responseEntity.getBody() instanceof ProblemDetails); + assertEquals(HttpStatus.CONFLICT, responseEntity.getStatusCode()); + } + + @Test + public void testOnGetPackageContent_NotFound_Fail() { + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID + "/package_content")) + .andExpect(method(HttpMethod.GET)).andRespond(withStatus(HttpStatus.NOT_FOUND)); + + final ResponseEntity<ProblemDetails> responseEntity = sendHttpRequest(VNF_PACKAGE_ID + "/package_content"); + + assertTrue(responseEntity.getBody() instanceof ProblemDetails); + assertEquals(HttpStatus.NOT_FOUND, responseEntity.getStatusCode()); + } + + @Test + public void testOnGetPackageContent_UnauthorizedClient_Fail() { + final String testURL = "http://localhost:" + port + PACKAGE_MANAGEMENT_BASE_URL + "/vnf_packages/" + + VNF_PACKAGE_ID + "/package_content"; + + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID + "/package_content")) + .andExpect(method(HttpMethod.GET)).andRespond(withStatus(HttpStatus.UNAUTHORIZED)); + + final HttpEntity<?> request = new HttpEntity<>(basicHttpHeadersProvider.getHttpHeaders()); + + + final ResponseEntity<ProblemDetails> responseEntity = + restTemplate.exchange(testURL, HttpMethod.GET, request, ProblemDetails.class); + + assertTrue(responseEntity.getBody() instanceof ProblemDetails); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); + } + + @Test + public void testOnGetPackageContent_InternalServerError_Fail() { + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID + "/package_content")) + .andExpect(method(HttpMethod.GET)).andRespond(withStatus(HttpStatus.INTERNAL_SERVER_ERROR)); + + final ResponseEntity<ProblemDetails> responseEntity = sendHttpRequest(VNF_PACKAGE_ID + "/package_content"); + + assertTrue(responseEntity.getBody() instanceof ProblemDetails); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); + } + + @Test + public void testOnGetPackageContent_BadRequest_Fail() { + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID + "/package_content")) + .andExpect(method(HttpMethod.GET)).andRespond(withStatus(HttpStatus.BAD_REQUEST)); + + final ResponseEntity<ProblemDetails> responseEntity = sendHttpRequest(VNF_PACKAGE_ID + "/package_content"); + + assertTrue(responseEntity.getBody() instanceof ProblemDetails); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); + } + + @Test + public void testOnGetPackageContent_UnauthorizedServer_InternalError_Fail() { + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID + "/package_content")) + .andExpect(method(HttpMethod.GET)).andRespond(withStatus(HttpStatus.UNAUTHORIZED)); + + final ResponseEntity<ProblemDetails> responseEntity = sendHttpRequest(VNF_PACKAGE_ID + "/package_content"); + + assertTrue(responseEntity.getBody() instanceof ProblemDetails); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); + } + + @Test + public void testGetPackageContent_SuccessResponseFromServerWithNullPackage_Fail() { + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID + "/package_content")) + .andExpect(method(HttpMethod.GET)).andRespond(withSuccess()); + + final ResponseEntity<ProblemDetails> responseEntity = sendHttpRequest(VNF_PACKAGE_ID + "/package_content"); + + assertEquals(ProblemDetails.class, responseEntity.getBody().getClass()); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); + } + + @Test + public void testGetPackageArtifact_ValidArray_Success() { + final byte[] responseArray = buildByteArrayWithRandomData(10); + + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID + "/artifacts/" + ARTIFACT_PATH)) + .andExpect(method(HttpMethod.GET)) + .andRespond(withSuccess(responseArray, MediaType.APPLICATION_OCTET_STREAM)); + + final String testURL = "http://localhost:" + port + PACKAGE_MANAGEMENT_BASE_URL + "/vnf_packages/" + + VNF_PACKAGE_ID + "/artifacts/" + ARTIFACT_PATH; + final HttpEntity<?> request = new HttpEntity<>(basicHttpHeadersProvider.getHttpHeaders()); + final ResponseEntity<byte[]> responseEntity = + restTemplate.withBasicAuth("test", "test").exchange(testURL, HttpMethod.GET, request, byte[].class); + + assertEquals(byte[].class, responseEntity.getBody().getClass()); + assertArrayEquals(responseEntity.getBody(), responseArray); + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + } + + @Test + public void testOnGetPackageArtifact_Conflict_Fail() { + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID + "/artifacts/" + ARTIFACT_PATH)) + .andExpect(method(HttpMethod.GET)).andRespond(withStatus(HttpStatus.CONFLICT)); + + final ResponseEntity<ProblemDetails> responseEntity = + sendHttpRequest(VNF_PACKAGE_ID + "/artifacts/" + ARTIFACT_PATH); + + assertNotNull(responseEntity.getBody()); + assertEquals(HttpStatus.CONFLICT, responseEntity.getStatusCode()); + } + + @Test + public void testOnGetPackageArtifact_NotFound_Fail() { + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID + "/artifacts/" + ARTIFACT_PATH)) + .andExpect(method(HttpMethod.GET)).andRespond(withStatus(HttpStatus.NOT_FOUND)); + + final ResponseEntity<ProblemDetails> responseEntity = + sendHttpRequest(VNF_PACKAGE_ID + "/artifacts/" + ARTIFACT_PATH); + + assertNotNull(responseEntity.getBody()); + assertEquals(HttpStatus.NOT_FOUND, responseEntity.getStatusCode()); + } + + @Test + public void testOnGetPackageArtifact_UnauthorizedClient_Fail() { + final String testURL = "http://localhost:" + port + PACKAGE_MANAGEMENT_BASE_URL + "/vnf_packages/" + + VNF_PACKAGE_ID + "/artifacts/" + ARTIFACT_PATH; + + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID + "/artifacts/" + ARTIFACT_PATH)) + .andExpect(method(HttpMethod.GET)).andRespond(withStatus(HttpStatus.UNAUTHORIZED)); + + final HttpEntity<?> request = new HttpEntity<>(basicHttpHeadersProvider.getHttpHeaders()); + final ResponseEntity<ProblemDetails> responseEntity = + restTemplate.exchange(testURL, HttpMethod.GET, request, ProblemDetails.class); + + assertNotNull(responseEntity.getBody()); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); + } + + @Test + public void testOnGetPackageArtifact_InternalServerError_Fail() { + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID + "/artifacts/" + ARTIFACT_PATH)) + .andExpect(method(HttpMethod.GET)).andRespond(withStatus(HttpStatus.INTERNAL_SERVER_ERROR)); + + final ResponseEntity<ProblemDetails> responseEntity = + sendHttpRequest(VNF_PACKAGE_ID + "/artifacts/" + ARTIFACT_PATH); + + assertNotNull(responseEntity.getBody()); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); + } + + @Test + public void testOnGetPackageArtifact_BadRequest_Fail() { + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID + "/artifacts/" + ARTIFACT_PATH)) + .andExpect(method(HttpMethod.GET)).andRespond(withStatus(HttpStatus.BAD_REQUEST)); + + final ResponseEntity<ProblemDetails> responseEntity = + sendHttpRequest(VNF_PACKAGE_ID + "/artifacts/" + ARTIFACT_PATH); + + assertNotNull(responseEntity.getBody()); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); + } + + @Test + public void testOnGetPackageArtifact_UnauthorizedServer_InternalError_Fail() { + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID + "/artifacts/" + ARTIFACT_PATH)) + .andExpect(method(HttpMethod.GET)).andRespond(withStatus(HttpStatus.UNAUTHORIZED)); + + final ResponseEntity<ProblemDetails> responseEntity = + sendHttpRequest(VNF_PACKAGE_ID + "/artifacts/" + ARTIFACT_PATH); + + assertNotNull(responseEntity.getBody()); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); + } + + @Test + public void testGetPackageArtifact_SuccessResponseFromServerWithNullPackage_Fail() { + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID + "/artifacts/" + ARTIFACT_PATH)) + .andExpect(method(HttpMethod.GET)).andRespond(withSuccess()); + + final ResponseEntity<ProblemDetails> responseEntity = + sendHttpRequest(VNF_PACKAGE_ID + "/artifacts/" + ARTIFACT_PATH); + + assertNotNull(responseEntity.getBody()); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); + } + + @Test + public void testVnfPackagesReceivedAsInlineResponse2001ListIfGetVnfPackagesSuccessful() { + final VnfPkgInfo[] responses = createVnfPkgArray(); + + mockRestServer.expect(requestTo(MSB_BASE_URL)).andExpect(method(HttpMethod.GET)) + .andRespond(withSuccess(gson.toJson(responses), MediaType.APPLICATION_JSON)); + + final String testURL = localhostUrl + port + VNFPKGM_BASE_URL; + final HttpEntity<?> request = new HttpEntity<>(basicHttpHeadersProvider.getHttpHeaders()); + + final ResponseEntity<InlineResponse2001[]> responseEntity = restTemplate.withBasicAuth("test", "test") + .exchange(testURL, HttpMethod.GET, request, InlineResponse2001[].class); + + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + assertNotNull(responseEntity.getBody()); + final InlineResponse2001[] inlineResponse2001array = responseEntity.getBody(); + final InlineResponse2001 inlineResponse2001 = inlineResponse2001array[0]; + assertEquals(VNF_PACKAGE_ID, inlineResponse2001.getId()); + assertEquals(VNFD_ID, inlineResponse2001.getVnfdId()); + assertEquals(VNFD_ID, inlineResponse2001.getSoftwareImages().get(0).getId()); + assertEquals(VNF_PRODUCT_NAME, inlineResponse2001.getSoftwareImages().get(0).getName()); + assertEquals(ALGORITHM, inlineResponse2001.getChecksum().getAlgorithm()); + assertEquals(HASH, inlineResponse2001.getChecksum().getHash()); + assertEquals(ARTIFACT_PATH, inlineResponse2001.getAdditionalArtifacts().get(0).getArtifactPath()); + assertEquals(ALGORITHM, inlineResponse2001.getAdditionalArtifacts().get(0).getChecksum().getAlgorithm()); + assertEquals(HASH, inlineResponse2001.getAdditionalArtifacts().get(0).getChecksum().getHash()); + assertEquals(URI_HREF, inlineResponse2001.getLinks().getSelf().getHref()); + } + + @Test + public void test400BadRequestInfoReceivedAsProblemDetailsIfGetVnfPackagesIs400BadRequest() { + mockRestServer.expect(requestTo(MSB_BASE_URL)).andExpect(method(HttpMethod.GET)) + .andRespond(withStatus(HttpStatus.BAD_REQUEST)); + + final ResponseEntity<ProblemDetails> responseEntity = sendHttpRequest(GET_VNF_PACKAGES_URL); + assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); + + assertNotNull(responseEntity.getBody()); + final ProblemDetails problemDetails = responseEntity.getBody(); + assertEquals("Error: Bad Request Received", problemDetails.getDetail()); + } + + @Test + public void test404NotFoundInfoReceivedAsProblemDetailsIfGetVnfPackagesIs404NotFound() { + mockRestServer.expect(requestTo(MSB_BASE_URL)).andExpect(method(HttpMethod.GET)) + .andRespond(withStatus(HttpStatus.NOT_FOUND)); + + final ResponseEntity<ProblemDetails> responseEntity = sendHttpRequest(GET_VNF_PACKAGES_URL); + assertEquals(HttpStatus.NOT_FOUND, responseEntity.getStatusCode()); + + assertNotNull(responseEntity.getBody()); + final ProblemDetails problemDetails = responseEntity.getBody(); + assertEquals("No Vnf Packages found", problemDetails.getDetail()); + } + + @Test + public void test500InternalServerErrorProblemDetailsReceivedIfGetVnfPackagesReturns500InternalServerError() { + mockRestServer.expect(requestTo(MSB_BASE_URL)).andExpect(method(HttpMethod.GET)) + .andRespond(withStatus(HttpStatus.INTERNAL_SERVER_ERROR)); + + final ResponseEntity<ProblemDetails> responseEntity = sendHttpRequest(GET_VNF_PACKAGES_URL); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); + + assertNotNull(responseEntity.getBody()); + final ProblemDetails problemDetails = responseEntity.getBody(); + assertEquals("Internal Server Error Occurred.", problemDetails.getDetail()); + } + + @Test + public void test500InternalServerErrorProblemDetailsReceivedIfGetVnfPackagesReturnsANullPackage() { + mockRestServer.expect(requestTo(MSB_BASE_URL)).andExpect(method(HttpMethod.GET)).andRespond(withSuccess()); + + final ResponseEntity<ProblemDetails> responseEntity = sendHttpRequest(GET_VNF_PACKAGES_URL); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); + + assertNotNull(responseEntity.getBody()); + final ProblemDetails problemDetails = responseEntity.getBody(); + assertEquals("An error occurred, a null response was received by the\n" + + " Sol003PackageManagementController from the EtsiCatalogManager using the GET \"vnf_packages\" \n" + + "endpoint.", problemDetails.getDetail()); + } + + @Test + public void testVnfPackageReceivedAsInlineResponse2001IfGetVnfPackageByIdSuccessful() { + final VnfPkgInfo response = createVnfPkgInfo(VNF_PACKAGE_ID); + + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID)).andExpect(method(HttpMethod.GET)) + .andRespond(withSuccess(gson.toJson(response), MediaType.APPLICATION_JSON)); + + final String testURL = localhostUrl + port + VNFPKGM_BASE_URL + "/" + VNF_PACKAGE_ID; + final HttpEntity<?> request = new HttpEntity<>(basicHttpHeadersProvider.getHttpHeaders()); + final ResponseEntity<InlineResponse2001> responseEntity = restTemplate.withBasicAuth("test", "test") + .exchange(testURL, HttpMethod.GET, request, InlineResponse2001.class); + + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + assertNotNull(responseEntity.getBody()); + final InlineResponse2001 inlineResponse2001 = responseEntity.getBody(); + assertEquals(VNF_PACKAGE_ID, inlineResponse2001.getId()); + assertEquals(VNFD_ID, inlineResponse2001.getVnfdId()); + assertEquals(VNFD_ID, inlineResponse2001.getSoftwareImages().get(0).getId()); + assertEquals(VNF_PRODUCT_NAME, inlineResponse2001.getSoftwareImages().get(0).getName()); + assertEquals(ALGORITHM, inlineResponse2001.getChecksum().getAlgorithm()); + assertEquals(HASH, inlineResponse2001.getChecksum().getHash()); + assertEquals(ARTIFACT_PATH, inlineResponse2001.getAdditionalArtifacts().get(0).getArtifactPath()); + assertEquals(ALGORITHM, inlineResponse2001.getAdditionalArtifacts().get(0).getChecksum().getAlgorithm()); + assertEquals(HASH, inlineResponse2001.getAdditionalArtifacts().get(0).getChecksum().getHash()); + assertEquals(URI_HREF, inlineResponse2001.getLinks().getSelf().getHref()); + } + + @Test + public void test400BadRequestInfoReceivedAsProblemDetailsIfGetVnfPackageByIdIs400BadRequest() { + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID)).andExpect(method(HttpMethod.GET)) + .andRespond(withStatus(HttpStatus.BAD_REQUEST)); + + final ResponseEntity<ProblemDetails> responseEntity = sendHttpRequest(GET_VNF_PACKAGE_BY_ID_URL); + + assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); + assertNotNull(responseEntity.getBody()); + final ProblemDetails problemDetails = responseEntity.getBody(); + assertEquals("Error: Bad Request Received", problemDetails.getDetail()); + } + + @Test + public void test404NotFoundInfoReceivedAsProblemDetailsIfGetVnfPackageByIdIs404NotFound() { + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID)).andExpect(method(HttpMethod.GET)) + .andRespond(withStatus(HttpStatus.NOT_FOUND)); + + final ResponseEntity<ProblemDetails> responseEntity = sendHttpRequest(GET_VNF_PACKAGE_BY_ID_URL); + + assertEquals(HttpStatus.NOT_FOUND, responseEntity.getStatusCode()); + assertNotNull(responseEntity.getBody()); + final ProblemDetails problemDetails = responseEntity.getBody(); + assertEquals("No Vnf Package found with vnfPkgId: " + VNF_PACKAGE_ID, problemDetails.getDetail()); + } + + @Test + public void test500InternalServerErrorProblemDetailsReceivedIfGetVnfPackageByIdReturns500InternalServerError() { + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID)).andExpect(method(HttpMethod.GET)) + .andRespond(withStatus(HttpStatus.INTERNAL_SERVER_ERROR)); + + final ResponseEntity<ProblemDetails> responseEntity = sendHttpRequest(GET_VNF_PACKAGE_BY_ID_URL); + + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); + assertNotNull(responseEntity.getBody()); + final ProblemDetails problemDetails = responseEntity.getBody(); + assertEquals("Internal Server Error Occurred.", problemDetails.getDetail()); + } + + @Test + public void test500InternalServerErrorProblemDetailsReceivedIfGetVnfPackageByIdReturnsANullPackage() { + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID)).andExpect(method(HttpMethod.GET)) + .andRespond(withSuccess()); + + final ResponseEntity<ProblemDetails> responseEntity = sendHttpRequest(GET_VNF_PACKAGE_BY_ID_URL); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); + + assertNotNull(responseEntity.getBody()); + final ProblemDetails problemDetails = responseEntity.getBody(); + assertEquals("An error occurred, a null response was received by the\n" + + " Sol003PackageManagementController from the EtsiCatalogManager using the GET \"vnf_packages\" by vnfPkgId: \"" + + VNF_PACKAGE_ID + "\" \n" + "endpoint.", problemDetails.getDetail()); + } + + // The below test method is here to improve code coverage and provide a foundation for writing future tests + @Test + public void testGetPackageVnfd_ValidArray_Success() { + final byte[] responseArray = buildByteArrayWithRandomData(10); + + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID + "/vnfd")) + .andExpect(method(HttpMethod.GET)) + .andRespond(withSuccess(responseArray, MediaType.APPLICATION_OCTET_STREAM)); + + final String testURL = + "http://localhost:" + port + PACKAGE_MANAGEMENT_BASE_URL + "/vnf_packages/" + VNF_PACKAGE_ID + "/vnfd"; + final HttpEntity<?> request = new HttpEntity<>(basicHttpHeadersProvider.getHttpHeaders()); + final ResponseEntity<byte[]> responseEntity = + restTemplate.withBasicAuth("test", "test").exchange(testURL, HttpMethod.GET, request, byte[].class); + + assertEquals(byte[].class, responseEntity.getBody().getClass()); + assertArrayEquals(responseEntity.getBody(), responseArray); + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + } + + @Test + public void testOnGetPackageVnfd_Conflict_Fail() { + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID + "/vnfd")) + .andExpect(method(HttpMethod.GET)).andRespond(withStatus(HttpStatus.CONFLICT)); + + final ResponseEntity<ProblemDetails> responseEntity = sendHttpRequest(VNF_PACKAGE_ID + "/vnfd"); + + assertTrue(responseEntity.getBody() instanceof ProblemDetails); + assertEquals(HttpStatus.CONFLICT, responseEntity.getStatusCode()); + } + + @Test + public void testOnGetPackageVnfd_NotFound_Fail() { + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID + "/vnfd")) + .andExpect(method(HttpMethod.GET)).andRespond(withStatus(HttpStatus.NOT_FOUND)); + + final ResponseEntity<ProblemDetails> responseEntity = sendHttpRequest(VNF_PACKAGE_ID + "/vnfd"); + + assertTrue(responseEntity.getBody() instanceof ProblemDetails); + assertEquals(HttpStatus.NOT_FOUND, responseEntity.getStatusCode()); + } + + @Test + public void testOnGetPackageVnfd_UnauthorizedClient_Fail() { + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID + "/vnfd")) + .andExpect(method(HttpMethod.GET)).andRespond(withStatus(HttpStatus.UNAUTHORIZED)); + + final ResponseEntity<ProblemDetails> responseEntity = sendHttpRequest(VNF_PACKAGE_ID + "/vnfd"); + + assertTrue(responseEntity.getBody() instanceof ProblemDetails); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); + } + + @Test + public void testOnGetPackageVnfd_InternalServerError_Fail() { + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID + "/vnfd")) + .andExpect(method(HttpMethod.GET)).andRespond(withStatus(HttpStatus.INTERNAL_SERVER_ERROR)); + + final ResponseEntity<ProblemDetails> responseEntity = sendHttpRequest(VNF_PACKAGE_ID + "/vnfd"); + + assertTrue(responseEntity.getBody() instanceof ProblemDetails); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); + } + + @Test + public void testOnGetPackageVnfd_BadRequest_Fail() { + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID + "/vnfd")) + .andExpect(method(HttpMethod.GET)).andRespond(withStatus(HttpStatus.BAD_REQUEST)); + + final ResponseEntity<ProblemDetails> responseEntity = sendHttpRequest(VNF_PACKAGE_ID + "/vnfd"); + + assertTrue(responseEntity.getBody() instanceof ProblemDetails); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); + } + + @Test + public void testOnGetPackageVnfd_UnauthorizedServer_InternalError_Fail() { + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID + "/vnfd")) + .andExpect(method(HttpMethod.GET)).andRespond(withStatus(HttpStatus.UNAUTHORIZED)); + + final ResponseEntity<ProblemDetails> responseEntity = sendHttpRequest(VNF_PACKAGE_ID + "/vnfd"); + + assertTrue(responseEntity.getBody() instanceof ProblemDetails); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); + } + + @Test + public void testGetPackageVnfd_SuccessResponseFromServerWithNullPackage_Fail() { + mockRestServer.expect(requestTo(MSB_BASE_URL + "/" + VNF_PACKAGE_ID + "/vnfd")) + .andExpect(method(HttpMethod.GET)).andRespond(withSuccess()); + + final ResponseEntity<ProblemDetails> responseEntity = sendHttpRequest(VNF_PACKAGE_ID + "/vnfd"); + + assertEquals(ProblemDetails.class, responseEntity.getBody().getClass()); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); + } + + // Simply returns a byte array filled with random data, for use in the tests. + private byte[] buildByteArrayWithRandomData(final int sizeInKb) { + final Random rnd = new Random(); + final byte[] b = new byte[sizeInKb * 1024]; // converting kb to byte + rnd.nextBytes(b); + return b; + } + + private ResponseEntity<ProblemDetails> sendHttpRequest(final String url) { + final String testURL = localhostUrl + port + VNFPKGM_BASE_URL + "/" + url; + final HttpEntity<?> request = new HttpEntity<>(basicHttpHeadersProvider.getHttpHeaders()); + return restTemplate.withBasicAuth("test", "test").exchange(testURL, HttpMethod.GET, request, + ProblemDetails.class); + } + + private VnfPkgInfo[] createVnfPkgArray() { + final VnfPkgInfo[] vnfPkgInfoArray = new VnfPkgInfo[1]; + final VnfPkgInfo vnfPkgInfo = createVnfPkgInfo(VNF_PACKAGE_ID); + vnfPkgInfoArray[0] = vnfPkgInfo; + return vnfPkgInfoArray; + } + + private VnfPkgInfo createVnfPkgInfo(final String vnfPackageId) { + final VnfPkgInfo vnfPkgInfo = new VnfPkgInfo(); + vnfPkgInfo.setId(vnfPackageId); + vnfPkgInfo.setVnfdId(VNFD_ID); + vnfPkgInfo.setVnfProvider(VNF_PROVIDER); + vnfPkgInfo.setVnfProductName(VNF_PRODUCT_NAME); + vnfPkgInfo.setVnfSoftwareVersion(VNF_SOFTWARE_VERSION); + vnfPkgInfo.setVnfdVersion(VNFD_VERSION); + vnfPkgInfo.setChecksum(createVnfPkgChecksum()); + vnfPkgInfo.setSoftwareImages(createSoftwareImages()); + vnfPkgInfo.setAdditionalArtifacts(createAdditionalArtifacts()); + vnfPkgInfo.setLinks(createVNFPKGMLinkSerializerLinks()); + return vnfPkgInfo; + } + + private Checksum createVnfPkgChecksum() { + final Checksum checksum = new Checksum(); + checksum.setAlgorithm(ALGORITHM); + checksum.setHash(HASH); + return checksum; + } + + private List<VnfPackageSoftwareImageInfo> createSoftwareImages() { + final List<VnfPackageSoftwareImageInfo> softwareImages = new ArrayList<>(); + final VnfPackageSoftwareImageInfo vnfPackageSoftwareImageInfo = new VnfPackageSoftwareImageInfo(); + vnfPackageSoftwareImageInfo.setId(VNFD_ID); + vnfPackageSoftwareImageInfo.setName(VNF_PRODUCT_NAME); + vnfPackageSoftwareImageInfo.setProvider(""); + vnfPackageSoftwareImageInfo.setVersion(""); + vnfPackageSoftwareImageInfo.setChecksum(createVnfPkgChecksum()); + vnfPackageSoftwareImageInfo + .setContainerFormat(VnfPackageSoftwareImageInfo.ContainerFormatEnum.fromValue("AKI")); + softwareImages.add(vnfPackageSoftwareImageInfo); + return softwareImages; + } + + private List<VnfPackageArtifactInfo> createAdditionalArtifacts() { + final List<VnfPackageArtifactInfo> vnfPackageArtifactInfos = new ArrayList<>(); + final VnfPackageArtifactInfo vnfPackageArtifactInfo = + new VnfPackageArtifactInfo().artifactPath(ARTIFACT_PATH).checksum(createVnfPkgChecksum()); + vnfPackageArtifactInfos.add(vnfPackageArtifactInfo); + return vnfPackageArtifactInfos; + } + + private VNFPKGMLinkSerializer createVNFPKGMLinkSerializerLinks() { + final UriLink uriLink = new UriLink().href(URI_HREF); + final VNFPKGMLinkSerializer vnfpkgmLinkSerializer = new VNFPKGMLinkSerializer().self(uriLink); + return vnfpkgmLinkSerializer; + } +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/Sol003SubscriptionManagementControllerTest.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/Sol003SubscriptionManagementControllerTest.java new file mode 100644 index 0000000000..ed1880035a --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/Sol003SubscriptionManagementControllerTest.java @@ -0,0 +1,70 @@ +package org.onap.so.adapters.vnfmadapter.rest; + +import static org.junit.Assert.assertEquals; +import static org.onap.so.client.RestTemplateConfig.CONFIGURABLE_REST_TEMPLATE; +import java.net.URISyntaxException; +import java.util.List; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.onap.so.adapters.vnfmadapter.VnfmAdapterApplication; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.InlineResponse2002; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.PkgmSubscriptionRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.client.MockRestServiceServer; +import org.springframework.web.client.RestTemplate; + +/** + * @author gareth.roper@est.tech + */ + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = VnfmAdapterApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ActiveProfiles("test") +public class Sol003SubscriptionManagementControllerTest { + + private static final String subscriptionId = "mySubscriptionId"; + + @Autowired + @Qualifier(CONFIGURABLE_REST_TEMPLATE) + private RestTemplate testRestTemplate; + + @Autowired + private Sol003SubscriptionManagementController controller; + + @Before + public void setUp() throws Exception { + MockRestServiceServer.bindTo(testRestTemplate).build(); + } + + @Test + public void postSubscriptionRequest() throws URISyntaxException, InterruptedException { + final PkgmSubscriptionRequest pkgmSubscriptionRequest = new PkgmSubscriptionRequest(); + final ResponseEntity<InlineResponse2002> response = controller.postSubscriptionRequest(pkgmSubscriptionRequest); + assertEquals(HttpStatus.NOT_IMPLEMENTED, response.getStatusCode()); + } + + @Test + public void getSubscriptions() throws URISyntaxException, InterruptedException { + final ResponseEntity<List<InlineResponse2002>> response = controller.getSubscriptions(); + assertEquals(HttpStatus.NOT_IMPLEMENTED, response.getStatusCode()); + } + + @Test + public void deleteSubscription() throws URISyntaxException, InterruptedException { + final ResponseEntity<Void> response = controller.deleteSubscription(subscriptionId); + assertEquals(HttpStatus.NOT_IMPLEMENTED, response.getStatusCode()); + } + + @Test + public void getSubscription() throws URISyntaxException, InterruptedException { + final ResponseEntity<InlineResponse2002> response = controller.getSubscription(subscriptionId); + assertEquals(HttpStatus.NOT_IMPLEMENTED, response.getStatusCode()); + } +} diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/VnfmAdapterControllerTest.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/VnfmAdapterControllerTest.java index fe55907420..fca50ea6f2 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/VnfmAdapterControllerTest.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/VnfmAdapterControllerTest.java @@ -25,6 +25,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.verify; import static org.onap.so.client.RestTemplateConfig.CONFIGURABLE_REST_TEMPLATE; import static org.springframework.test.web.client.match.MockRestRequestMatchers.content; @@ -38,6 +39,7 @@ import java.util.Optional; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; @@ -56,10 +58,12 @@ import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.JSON; import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse200; import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse2001; import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse201; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse201.InstantiationStateEnum; import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse201Links; import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse201LinksSelf; import org.onap.so.adapters.vnfmadapter.rest.exceptions.VnfmNotFoundException; import org.onap.so.client.aai.AAIResourcesClient; +import org.onap.so.client.aai.AAIVersion; import org.onap.so.client.aai.entities.uri.AAIResourceUri; import org.onap.vnfmadapter.v1.model.CreateVnfRequest; import org.onap.vnfmadapter.v1.model.CreateVnfResponse; @@ -175,20 +179,14 @@ public class VnfmAdapterControllerTest { assertEquals("/network/generic-vnfs/generic-vnf/myTestVnfId", uriArgument.getValue().build().toString()); assertEquals("myTestVnfId", genericVnfArgument.getValue().getVnfId()); - assertEquals(2, genericVnfArgument.getValue().getRelationshipList().getRelationship().size()); - final Relationship vnfmRelationship = - genericVnfArgument.getValue().getRelationshipList().getRelationship().get(0); - assertEquals("esr-vnfm", vnfmRelationship.getRelatedTo()); - assertEquals("tosca.relationships.DependsOn", vnfmRelationship.getRelationshipLabel()); - assertEquals("/aai/v15/external-system/esr-vnfm-list/esr-vnfm/vnfm2", vnfmRelationship.getRelatedLink()); - - final Relationship tenantRelationship = - genericVnfArgument.getValue().getRelationshipList().getRelationship().get(1); - assertEquals("tenant", tenantRelationship.getRelatedTo()); - assertEquals( - "/aai/v15/cloud-infrastructure/cloud-regions/cloud-region/myTestCloudOwner/myTestRegion/tenants/tenant/myTestTenantId", - tenantRelationship.getRelatedLink()); + final ArgumentCaptor<AAIResourceUri> uriArgument1Connect = ArgumentCaptor.forClass(AAIResourceUri.class); + final ArgumentCaptor<AAIResourceUri> uriArgument2Connect = ArgumentCaptor.forClass(AAIResourceUri.class); + verify(aaiResourcesClient, timeout(1000)).connect(uriArgument1Connect.capture(), uriArgument2Connect.capture()); + assertEquals("/external-system/esr-vnfm-list/esr-vnfm/vnfm2", + uriArgument1Connect.getAllValues().get(0).build().toString()); + assertEquals("/network/generic-vnfs/generic-vnf/myTestVnfId", + uriArgument2Connect.getAllValues().get(0).build().toString()); // check the job status @@ -262,6 +260,7 @@ public class VnfmAdapterControllerTest { } @Test + @Ignore public void createVnf_UnauthorizedUser_Returns401() throws Exception { final TestRestTemplate restTemplateWrongPassword = new TestRestTemplate("test", "wrongPassword"); final Tenant tenant = new Tenant().cloudOwner(CLOUD_OWNER).regionName(REGION).tenantId(TENANT_ID); @@ -327,6 +326,40 @@ public class VnfmAdapterControllerTest { } @Test + public void deleteVnf_VnfAlreadyTerminated_Returns202AndJobId() throws Exception { + final TestRestTemplate restTemplate = new TestRestTemplate("test", "test"); + + final GenericVnf genericVnf = setUpGenericVnfInMockAai("vnfmType1"); + addSelfLinkToGenericVnf(genericVnf); + addRelationshipFromGenericVnfToVnfm(genericVnf, "vnfm1"); + setUpVnfmsInMockAai(); + + mockRestServer.expect(requestTo("http://vnfm:8080/vnfs/myTestVnfIdOnVnfm/terminate")) + .andRespond(withStatus(HttpStatus.CONFLICT).contentType(MediaType.APPLICATION_JSON)); + + final InlineResponse201 reponse = new InlineResponse201(); + reponse.setInstantiationState(InstantiationStateEnum.NOT_INSTANTIATED); + mockRestServer.expect(requestTo(new URI("http://vnfm:8080/vnfs/myTestVnfIdOnVnfm"))) + .andRespond(withSuccess(gson.toJson(reponse), MediaType.APPLICATION_JSON)); + + mockRestServer.expect(requestTo("http://vnfm:8080/vnfs/myTestVnfIdOnVnfm")) + .andRespond(withStatus(HttpStatus.NO_CONTENT).contentType(MediaType.APPLICATION_JSON)); + + final RequestEntity<Void> request = RequestEntity + .delete(new URI("http://localhost:" + port + "/so/vnfm-adapter/v1/vnfs/myTestVnfId")) + .accept(MediaType.APPLICATION_JSON).header("X-ONAP-RequestId", "myRequestId") + .header("X-ONAP-InvocationID", "myInvocationId").header("Content-Type", "application/json").build(); + final ResponseEntity<DeleteVnfResponse> deleteVnfResponse = + restTemplate.exchange(request, DeleteVnfResponse.class); + assertEquals(202, deleteVnfResponse.getStatusCode().value()); + assertNotNull(deleteVnfResponse.getBody().getJobId()); + + final ResponseEntity<QueryJobResponse> jobQueryResponse = + controller.jobQuery(deleteVnfResponse.getBody().getJobId(), "", "so", "1213"); + assertEquals(OperationStateEnum.COMPLETED, jobQueryResponse.getBody().getOperationState()); + } + + @Test public void deleteVnf_GenericVnfNotFound_Returns404() throws Exception { final TestRestTemplate restTemplate = new TestRestTemplate("test", "test"); @@ -413,7 +446,8 @@ public class VnfmAdapterControllerTest { private void addRelationshipFromGenericVnfToVnfm(final GenericVnf genericVnf, final String vnfmId) { final Relationship relationshipToVnfm = new Relationship(); - relationshipToVnfm.setRelatedLink("/aai/v15/external-system/esr-vnfm-list/esr-vnfm/" + vnfmId); + relationshipToVnfm + .setRelatedLink("/aai/" + AAIVersion.LATEST + "/external-system/esr-vnfm-list/esr-vnfm/" + vnfmId); relationshipToVnfm.setRelatedTo("esr-vnfm"); final RelationshipData relationshipData = new RelationshipData(); relationshipData.setRelationshipKey("esr-vnfm.vnfm-id"); diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/resources/application.yaml b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/resources/application.yaml index 8cf8b51b9f..ae66464f29 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/resources/application.yaml +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/resources/application.yaml @@ -20,6 +20,8 @@ spring: - username: vnfm password: '$2a$10$Fh9ffgPw2vnmsghsRD3ZauBL1aKXebigbq3BB1RPWtE62UDILsjke' role: BPEL-Client + main: + allow-bean-definition-overriding: true mso: key: 07a7159d3bf51a0e53be7a8f89699be7 @@ -52,3 +54,7 @@ management: prometheus: enabled: true # Whether exporting of metrics to Prometheus is enabled. step: 1m # Step size (i.e. reporting frequency) to use. + +etsi-catalog-manager: + vnfpkgm: + endpoint: http://msb-iag.onap:80/api/vnfpkgm/v1 diff --git a/adapters/pom.xml b/adapters/pom.xml index bd7bebafa0..b96c3744c3 100644 --- a/adapters/pom.xml +++ b/adapters/pom.xml @@ -22,6 +22,8 @@ <module>mso-vfc-adapter</module> <module>mso-openstack-adapters</module> <module>mso-vnfm-adapter</module> + <module>mso-ve-vnfm-adapter</module> + <module>so-appc-orchestrator</module> </modules> <dependencies> diff --git a/adapters/so-appc-orchestrator/pom.xml b/adapters/so-appc-orchestrator/pom.xml new file mode 100644 index 0000000000..717bcee3fc --- /dev/null +++ b/adapters/so-appc-orchestrator/pom.xml @@ -0,0 +1,221 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.onap.so</groupId> + <artifactId>adapters</artifactId> + <version>1.4.0-SNAPSHOT</version> + </parent> + + <groupId>org.onap.so.adapters</groupId> + <artifactId>so-appc-orchestrator</artifactId> + <packaging>jar</packaging> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> + <java.version>1.8</java.version> + <appc.client.version>1.6.0-SNAPSHOT</appc.client.version> + </properties> + <name>so-appc-orchestrator</name> + <description>MSO APPC-C Orchestrator</description> + <build> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + <version>${springboot.version}</version> + <configuration> + <mainClass>org.onap.so.adapters.appc.orchestrator.AppcOrchestratorApplication</mainClass> + </configuration> + <executions> + <execution> + <goals> + <goal>repackage</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <executions> + <execution> + <id>extract-docker-file</id> + </execution> + </executions> + </plugin> + <plugin> + <groupId>io.fabric8</groupId> + <artifactId>fabric8-maven-plugin</artifactId> + <executions> + <execution> + <id>start</id> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.3</version> + <configuration> + <source>1.8</source> + <target>1.8</target> + <fork>true</fork> + <compilerArgs> + <arg>-parameters</arg> + </compilerArgs> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <executions> + <execution> + <id>default-test</id> + <goals> + <goal>test</goal> + </goals> + <configuration> + <includes> + <include>**/AllTestsTestSuite.java</include> + </includes> + <parallel>suites</parallel> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + <pluginManagement> + <plugins> + <!--This plugin's configuration is used to store Eclipse m2e settings + only. It has no influence on the Maven build itself. --> + <plugin> + <groupId>org.eclipse.m2e</groupId> + <artifactId>lifecycle-mapping</artifactId> + <version>1.0.0</version> + <configuration> + <lifecycleMappingMetadata> + <pluginExecutions> + <pluginExecution> + <pluginExecutionFilter> + <groupId> + org.jvnet.jax-ws-commons + </groupId> + <artifactId> + jaxws-maven-plugin + </artifactId> + <versionRange> + [2.3,) + </versionRange> + <goals> + <goal>wsgen</goal> + </goals> + </pluginExecutionFilter> + <action> + <ignore> + </ignore> + </action> + </pluginExecution> + </pluginExecutions> + </lifecycleMappingMetadata> + </configuration> + </plugin> + + <plugin> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + </plugin> + </plugins> + </pluginManagement> + <finalName>${project.artifactId}-${project.version}</finalName> + </build> + <dependencies> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-actuator</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>io.micrometer</groupId> + <artifactId>micrometer-core</artifactId> + </dependency> + <dependency> + <groupId>io.micrometer</groupId> + <artifactId>micrometer-registry-prometheus</artifactId> + </dependency> + <dependency> + <groupId>com.google.guava</groupId> + <artifactId>guava</artifactId> + </dependency> + <dependency> + <groupId>org.onap.so</groupId> + <artifactId>common</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.camunda.bpm</groupId> + <artifactId>camunda-external-task-client</artifactId> + <version>1.1.1</version> + </dependency> + <dependency> + <groupId>org.onap.so</groupId> + <artifactId>MSOCommonBPMN</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.appc.client</groupId> + <artifactId>client-lib</artifactId> + <version>${appc.client.version}</version> + <exclusions> + <exclusion> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + </exclusion> + <exclusion> + <groupId>org.powermock</groupId> + <artifactId>powermock-module-junit4</artifactId> + </exclusion> + <exclusion> + <groupId>org.powermock</groupId> + <artifactId>powermock-api-mockito</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.onap.so.adapters</groupId> + <artifactId>mso-adapter-utils</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.appc.client</groupId> + <artifactId>client-kit</artifactId> + <version>${appc.client.version}</version> + <exclusions> + <exclusion> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + </exclusion> + </exclusions> + </dependency> + <!-- Test Dependencies --> + <dependency> + <groupId>pl.pragmatists</groupId> + <artifactId>JUnitParams</artifactId> + <version>1.0.5</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + </dependencies> +</project> diff --git a/adapters/mso-workflow-message-adapter/src/test/java/org/onap/so/adapters/workflowmessage/WMAdapterRestTest.java b/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/AppcOrchestratorApplication.java index 08728fa339..258c95ac89 100644 --- a/adapters/mso-workflow-message-adapter/src/test/java/org/onap/so/adapters/workflowmessage/WMAdapterRestTest.java +++ b/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/AppcOrchestratorApplication.java @@ -2,14 +2,14 @@ * ============LICENSE_START======================================================= * ONAP - SO * ================================================================================ - * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. * ================================================================================ * 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 - *l + * * 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. @@ -18,28 +18,29 @@ * ============LICENSE_END========================================================= */ -package org.onap.so.adapters.workflowmessage; +package org.onap.so.adapters.appc.orchestrator; -import org.junit.Assert; -import org.junit.Test; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; -public class WMAdapterRestTest { +/** + * @since Version 1.0 + * + */ - @Test(expected = ClassFormatError.class) - public void testHealthCheckException() throws Exception { +@SpringBootApplication(scanBasePackages = {"org.onap"}) +public class AppcOrchestratorApplication { - WMAdapterRest test = new WMAdapterRest(); - test.healthcheck("34388737-cdad-4d96-ae6f-39d08024b495"); - Assert.assertFalse(true); + private static final String LOGS_DIR = "logs_dir"; + private static void setLogsDir() { + if (System.getProperty(LOGS_DIR) == null) { + System.getProperties().setProperty(LOGS_DIR, "./logs/appcorch/"); + } } - @Test(expected = ClassFormatError.class) - public void testReceiveWorkflowMsgException() throws Exception { - WMAdapterRest test = new WMAdapterRest(); - test.receiveWorkflowMessage("contentTypeHeader", "messageType", "correlator", "content"); - Assert.assertFalse(true); - + public static void main(String... args) { + SpringApplication.run(AppcOrchestratorApplication.class, args); + setLogsDir(); } } - diff --git a/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/client/ApplicationControllerCallback.java b/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/client/ApplicationControllerCallback.java new file mode 100644 index 0000000000..1f73000299 --- /dev/null +++ b/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/client/ApplicationControllerCallback.java @@ -0,0 +1,84 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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 org.onap.so.adapters.appc.orchestrator.client; + +import org.camunda.bpm.client.task.ExternalTask; +import org.camunda.bpm.client.task.ExternalTaskService; +import org.onap.appc.client.lcm.api.ResponseHandler; +import org.onap.appc.client.lcm.exceptions.AppcClientException; +import org.onap.appc.client.lcm.model.Status; +import org.onap.so.adapters.appc.orchestrator.client.StatusCategory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ApplicationControllerCallback<T> implements ResponseHandler<T> { + + private static final Logger logger = LoggerFactory.getLogger(ApplicationControllerCallback.class); + + private final ExternalTask externalTask; + private final ExternalTaskService externalTaskService; + private final ApplicationControllerSupport appCSupport; + + public ApplicationControllerCallback(ExternalTask externalTask, ExternalTaskService externalTaskService, + ApplicationControllerSupport appCSupport) { + this.externalTask = externalTask; + this.externalTaskService = externalTaskService; + this.appCSupport = appCSupport; + } + + @Override + public void onResponse(T response) { + logger.info("ON RESPONSE IN CALLBACK"); + + Status status = appCSupport.getStatusFromGenericResponse(response); + + logger.info("Status code is: " + status.getCode()); + logger.info("Status message is: " + status.getMessage()); + + if (appCSupport.getFinalityOf(status)) { + logger.debug("Obtained final status, complete the task"); + completeExternalTask(externalTask, externalTaskService, status); + } else { + logger.debug("Intermediate status, continue the task"); + } + } + + @Override + public void onException(AppcClientException exception) { + + logger.info("ON EXCEPTION IN CALLBACK"); + logger.info("Exception from APPC: " + exception.getMessage()); + Status exceptionStatus = appCSupport.buildStatusFromAppcException(exception); + completeExternalTask(externalTask, externalTaskService, exceptionStatus); + } + + private void completeExternalTask(ExternalTask externalTask, ExternalTaskService externalTaskService, + Status status) { + + if (appCSupport.getCategoryOf(status).equals(StatusCategory.NORMAL)) { + externalTaskService.complete(externalTask); + logger.debug("The External Task Id: {} Successful", externalTask.getId()); + } else { + logger.debug("The External Task Id: {} Failed", externalTask.getId()); + externalTaskService.handleBpmnError(externalTask, "MSOWorkflowException", status.getMessage()); + } + } +} diff --git a/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/client/ApplicationControllerClient.java b/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/client/ApplicationControllerClient.java new file mode 100644 index 0000000000..20093be6a4 --- /dev/null +++ b/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/client/ApplicationControllerClient.java @@ -0,0 +1,244 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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 org.onap.so.adapters.appc.orchestrator.client; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.time.Instant; +import java.util.Optional; +import java.util.Properties; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; +import org.onap.appc.client.lcm.api.AppcClientServiceFactoryProvider; +import org.onap.appc.client.lcm.api.AppcLifeCycleManagerServiceFactory; +import org.onap.appc.client.lcm.api.ApplicationContext; +import org.onap.appc.client.lcm.api.LifeCycleManagerStateful; +import org.onap.appc.client.lcm.exceptions.AppcClientException; +import org.onap.appc.client.lcm.model.Action; +import org.onap.appc.client.lcm.model.ActionIdentifiers; +import org.onap.appc.client.lcm.model.CommonHeader; +import org.onap.appc.client.lcm.model.Flags; +import org.onap.appc.client.lcm.model.Flags.Force; +import org.onap.appc.client.lcm.model.Flags.Mode; +import org.onap.so.adapters.appc.orchestrator.client.ApplicationControllerOrchestratorException; +import org.onap.so.adapters.appc.orchestrator.client.ApplicationControllerSupport; +import org.onap.so.adapters.appc.orchestrator.client.StatusCategory; +import org.onap.appc.client.lcm.model.Payload; +import org.onap.appc.client.lcm.model.Status; +import org.onap.appc.client.lcm.model.ZULU; + +@Component +public class ApplicationControllerClient { + + @Autowired + public Environment env; + + public static final String DEFAULT_CONTROLLER_TYPE = "APPC"; + + private static final String CLIENT_NAME = "MSO"; + + private static final String API_VER = "2.00"; + private static final String ORIGINATOR_ID = "MSO"; + private static final int FLAGS_TTL = 65000; + private static Logger logger = LoggerFactory.getLogger(ApplicationControllerClient.class); + + @Autowired + private ApplicationControllerSupport appCSupport; + + // APPC gave us an API where the controllerType is configured in the + // client object, which is not what we asked for. We asked for an API + // in which the client would have additional methods that could take + // the controllerType as a parameter, so that we would not need to + // maintain multiple client objects. This map should be removed when + // the (hopefully short-term) controllerType becomes obsolete. + + private String controllerType = DEFAULT_CONTROLLER_TYPE; + + private static ConcurrentHashMap<String, LifeCycleManagerStateful> appCClients = new ConcurrentHashMap<>(); + + /** + * Creates an ApplicationControllerClient for the specified controller type. + * + * @param controllerType the controller type: "appc" or "sdnc". + */ + public void setControllerType(String controllerType) { + if (controllerType == null) { + controllerType = DEFAULT_CONTROLLER_TYPE; + } + this.controllerType = controllerType.toUpperCase(); + } + + /** + * Gets the controller type. + * + * @return the controllertype + */ + public String getControllerType() { + return controllerType; + } + + /** + * Returns the AppC client object associated with this ApplicationControllerClient. AppC client objects are shared + * objects. One is created if it does not exist. + * + * @return the client object, or null if creation failed + */ + public LifeCycleManagerStateful getAppCClient() { + return appCClients.computeIfAbsent(controllerType, k -> createAppCClient(k)); + } + + protected LifeCycleManagerStateful createAppCClient(String controllerType) { + + try { + if (controllerType == null) { + controllerType = DEFAULT_CONTROLLER_TYPE; + } + controllerType = controllerType.toUpperCase(); + return AppcClientServiceFactoryProvider.getFactory(AppcLifeCycleManagerServiceFactory.class) + .createLifeCycleManagerStateful(new ApplicationContext(), getLCMProperties(controllerType)); + } catch (AppcClientException e) { + logger.error("Error in getting LifeCycleManagerStateful: {}", e.getMessage(), e); + // This null value will cause NullPointerException when used later. + // Error handling could certainly be improved here. + return null; + } + } + + public Status vnfCommand(Action action, String requestId, String vnfId, Optional<String> vserverId, + Optional<String> request, String controllerType, ApplicationControllerCallback listener) + throws ApplicationControllerOrchestratorException { + this.setControllerType(controllerType); + Status status; + ActionIdentifiers actionIdentifiers = new ActionIdentifiers(); + actionIdentifiers.setVnfId(vnfId); + if (vserverId.isPresent()) { + actionIdentifiers.setVserverId(vserverId.get()); + } + Payload payload = null; + if (request.isPresent()) { + payload = new Payload(request.get()); + + } + status = runCommand(action, actionIdentifiers, payload, requestId, listener); + if (appCSupport.getCategoryOf(status).equals(StatusCategory.ERROR)) { + throw new ApplicationControllerOrchestratorException(status.getMessage(), status.getCode()); + } else { + return status; + } + } + + + public Status runCommand(Action action, org.onap.appc.client.lcm.model.ActionIdentifiers actionIdentifiers, + org.onap.appc.client.lcm.model.Payload payload, String requestID, ApplicationControllerCallback listener) + throws ApplicationControllerOrchestratorException { + Status status; + Object requestObject; + requestObject = createRequest(action, actionIdentifiers, payload, requestID); + appCSupport.logLCMMessage(requestObject); + LifeCycleManagerStateful client = getAppCClient(); + Method lcmMethod = appCSupport.getAPIMethod(action.name(), client, true); + try { + Object response = lcmMethod.invoke(client, requestObject, listener); + if (response != null) { + return appCSupport.getStatusFromGenericResponse(response); + } else { + return new Status(); + } + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + throw new RuntimeException(String.format("%s : %s", "Unable to invoke action", action.toString()), e); + } + } + + protected Properties getLCMProperties() { + return getLCMProperties("appc"); + } + + protected Properties getLCMProperties(String controllerType) { + Properties properties = new Properties(); + + properties.put("topic.read", this.env.getProperty("appc.client.topic.read.name")); + properties.put("topic.write", this.env.getProperty("appc.client.topic.write")); + properties.put("SDNC-topic.read", this.env.getProperty("appc.client.topic.sdnc.read")); + properties.put("SDNC-topic.write", this.env.getProperty("appc.client.topic.sdnc.write")); + properties.put("topic.read.timeout", this.env.getProperty("appc.client.topic.read.timeout")); + properties.put("client.response.timeout", this.env.getProperty("appc.client.response.timeout")); + properties.put("poolMembers", this.env.getProperty("appc.client.poolMembers")); + properties.put("controllerType", controllerType); + properties.put("client.key", this.env.getProperty("appc.client.key")); + properties.put("client.secret", this.env.getProperty("appc.client.secret")); + properties.put("client.name", CLIENT_NAME); + properties.put("service", this.env.getProperty("appc.client.service")); + return properties; + } + + public Object createRequest(Action action, ActionIdentifiers identifier, Payload payload, String requestId) { + Object requestObject = appCSupport.getInput(action.name()); + + + try { + CommonHeader commonHeader = buildCommonHeader(requestId); + requestObject.getClass().getDeclaredMethod("setCommonHeader", CommonHeader.class).invoke(requestObject, + commonHeader); + requestObject.getClass().getDeclaredMethod("setAction", Action.class).invoke(requestObject, action); + requestObject.getClass().getDeclaredMethod("setActionIdentifiers", ActionIdentifiers.class) + .invoke(requestObject, identifier); + if (payload != null) { + logger.info("payload in RunCommand: " + payload.getValue()); + requestObject.getClass().getDeclaredMethod("setPayload", Payload.class).invoke(requestObject, payload); + } + } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { + logger.error("Error building Appc request", e); + } + return requestObject; + } + + private CommonHeader buildCommonHeader(String requestId) { + CommonHeader commonHeader = new CommonHeader(); + commonHeader.setApiVer(API_VER); + commonHeader.setOriginatorId(ORIGINATOR_ID); + commonHeader.setRequestId(requestId == null ? UUID.randomUUID().toString() : requestId); + commonHeader.setSubRequestId(UUID.randomUUID().toString()); + Flags flags = new Flags(); + String flagsMode = "NORMAL"; + Mode mode = Mode.valueOf(flagsMode); + flags.setMode(mode); + String flagsForce = "FALSE"; + Force force = Force.valueOf(flagsForce); + flags.setForce(force); + flags.setTtl(FLAGS_TTL); + commonHeader.setFlags(flags); + Instant timestamp = Instant.now(); + ZULU zulu = new ZULU(timestamp.toString()); + commonHeader.setTimestamp(zulu); + return commonHeader; + } + + public Flags createRequestFlags() { + Flags flags = new Flags(); + flags.setTtl(6000); + return flags; + } +} diff --git a/adapters/mso-workflow-message-adapter/src/test/java/org/onap/so/adapters/workflowmessage/BPRestCallbackTest.java b/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/client/ApplicationControllerOrchestratorException.java index 21917c3d2c..cc980a489d 100644 --- a/adapters/mso-workflow-message-adapter/src/test/java/org/onap/so/adapters/workflowmessage/BPRestCallbackTest.java +++ b/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/client/ApplicationControllerOrchestratorException.java @@ -2,14 +2,14 @@ * ============LICENSE_START======================================================= * ONAP - SO * ================================================================================ - * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. * ================================================================================ * 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. @@ -18,25 +18,20 @@ * ============LICENSE_END========================================================= */ -package org.onap.so.adapters.workflowmessage; +package org.onap.so.adapters.appc.orchestrator.client; -import org.apache.http.entity.ContentType; -import org.junit.Test; -import org.mockito.Mock; -import static junit.framework.Assert.assertFalse; +public class ApplicationControllerOrchestratorException extends Exception { -public class BPRestCallbackTest { + private static final long serialVersionUID = 2594894543585595494L; + private final int appcCode; - @Mock - ContentType contentType; - - @Test - public void testSendExceptionCase() { - - BPRestCallback test = new BPRestCallback(); - test.send("workflowMessageUrl/", "messageType", "correlator", contentType,"message"); - assertFalse(test.send("workflowMessageUrl/", "messageType", "correlator", contentType,"message")); + public ApplicationControllerOrchestratorException(String message, int code) { + super(message); + appcCode = code; + } - } + public int getAppcCode() { + return appcCode; } +} diff --git a/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/client/ApplicationControllerSupport.java b/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/client/ApplicationControllerSupport.java new file mode 100644 index 0000000000..90ab24cb86 --- /dev/null +++ b/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/client/ApplicationControllerSupport.java @@ -0,0 +1,207 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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 org.onap.so.adapters.appc.orchestrator.client; + +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import org.onap.appc.client.lcm.api.LifeCycleManagerStateful; +import org.onap.appc.client.lcm.api.ResponseHandler; +import org.onap.appc.client.lcm.exceptions.AppcClientException; +import org.onap.appc.client.lcm.model.Status; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; + + +@Component +public class ApplicationControllerSupport { + + private static final int ACCEPT_SERIES = 100; + private static final int ERROR_SERIES = 200; + private static final int REJECT_SERIES = 300; + private static final int SUCCESS_SERIES = 400; + private static final int SUCCESS_STATUS = SUCCESS_SERIES; + private static final int PARTIAL_SERIES = 500; + private static final int PARTIAL_SUCCESS_STATUS = PARTIAL_SERIES; + private static final int PARTIAL_FAILURE_STATUS = PARTIAL_SERIES + 1; + + private static Logger logger = LoggerFactory.getLogger(ApplicationControllerSupport.class); + private String lcmModelPackage = "org.onap.appc.client.lcm.model"; + + /** + * @param action + * @return + * @throws ClassNotFoundException + * @throws InstantiationException + * @throws IllegalAccessException + */ + public Object getInput(String action) { + try { + return getInputClass(action).newInstance(); + } catch (IllegalAccessException | InstantiationException e) { + throw new RuntimeException( + String.format("%s : %s", "Unable to instantiate viable LCM Kit input class for action", action), e); + } + } + + /** + * @param action + * @return + * @throws ClassNotFoundException + */ + public Method getAPIMethod(String action, LifeCycleManagerStateful lcmStateful, boolean async) { + Method[] methods = lcmStateful.getClass().getMethods(); + for (Method method : methods) { + if (method.getName().equalsIgnoreCase(action)) { + Class<?>[] methodParameterTypes = method.getParameterTypes(); + if (methodParameterTypes.length > 0) { + if (getInputClass(action).equals(methodParameterTypes[0])) { + if (async) { + if (methodParameterTypes.length == 2 + && ResponseHandler.class.isAssignableFrom(methodParameterTypes[1])) { + return method; + } + } else if (methodParameterTypes.length == 1) { + return method; + } + } + } + } + } + throw new RuntimeException(String.format("%s : %s, async=%b", + "Unable to derive viable LCM Kit API method for action", action, async)); + } + + public Status getStatusFromGenericResponse(Object response) { + Method statusReader = getBeanPropertyMethodFor(response.getClass(), "status", false); + if (statusReader != null) { + try { + return (Status) statusReader.invoke(response); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + logger.error("Unable to obtain status from LCM Kit response", e); + } + } + return new Status(); + } + + public StatusCategory getCategoryOf(Status status) { + int codeSeries = status.getCode() - (status.getCode() % 100); + switch (codeSeries) { + case ACCEPT_SERIES: + return StatusCategory.NORMAL; + case ERROR_SERIES: + case REJECT_SERIES: + return StatusCategory.ERROR; + case SUCCESS_SERIES: + return status.getCode() == SUCCESS_STATUS ? StatusCategory.NORMAL : StatusCategory.ERROR; + case PARTIAL_SERIES: + switch (status.getCode()) { + case PARTIAL_SUCCESS_STATUS: + return StatusCategory.NORMAL; + case PARTIAL_FAILURE_STATUS: + return StatusCategory.ERROR; + default: + return StatusCategory.WARNING; + } + default: + return StatusCategory.WARNING; + } + } + + public boolean getFinalityOf(Status status) { + int codeSeries = status.getCode() - (status.getCode() % 100); + switch (codeSeries) { + case ACCEPT_SERIES: + case PARTIAL_SERIES: + return false; + case ERROR_SERIES: + case REJECT_SERIES: + case SUCCESS_SERIES: + return true; + default: + return true; + } + } + + private Method getBeanPropertyMethodFor(Class<?> clazz, String propertyName, boolean isWriter) { + BeanInfo beanInfo; + try { + beanInfo = Introspector.getBeanInfo(clazz, Object.class); + } catch (IntrospectionException e) { + throw new RuntimeException( + String.format("Unable to produce bean property method for class : %s, property : %s, writer=%b", + clazz.getName(), propertyName, isWriter), + e); + } + PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); + for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { + if (propertyDescriptor.getName().equals(propertyName)) { + return isWriter ? propertyDescriptor.getWriteMethod() : propertyDescriptor.getReadMethod(); + } + } + throw new RuntimeException( + String.format("Unable to produce bean property method for class : %s, property : %s, writer=%b", + clazz.getName(), propertyName, isWriter)); + } + + /** + * @param action + * @return + * @throws ClassNotFoundException + */ + private Class<?> getInputClass(String action) { + try { + return Class.forName(lcmModelPackage + '.' + action + "Input"); + } catch (ClassNotFoundException e) { + throw new RuntimeException(String.format("%s : %s using package : %s", + "Unable to identify viable LCM Kit input class for action", action, lcmModelPackage), e); + } + } + + + public void logLCMMessage(Object message) { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.setSerializationInclusion(Include.NON_NULL); + ObjectWriter writer = objectMapper.writerWithDefaultPrettyPrinter(); + String inputAsJSON; + try { + inputAsJSON = writer.writeValueAsString(message); + logger.info("LCM Kit input message follows: {}", inputAsJSON); + } catch (JsonProcessingException e) { + logger.error("Error in logging LCM Message", e); + } + } + + public Status buildStatusFromAppcException(AppcClientException exception) { + Status exceptionStatus = new Status(); + exceptionStatus.setCode(200); + exceptionStatus.setMessage("Exception on APPC request: " + exception.getMessage()); + return exceptionStatus; + } +} diff --git a/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/client/StatusCategory.java b/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/client/StatusCategory.java new file mode 100644 index 0000000000..27160ef981 --- /dev/null +++ b/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/client/StatusCategory.java @@ -0,0 +1,16 @@ +package org.onap.so.adapters.appc.orchestrator.client; + +public enum StatusCategory { + NORMAL("normal"), WARNING("warning"), ERROR("error"); + + private final String category; + + private StatusCategory(final String category) { + this.category = category; + } + + @Override + public String toString() { + return category; + } +} diff --git a/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/client/beans/ConfigurationParameters.java b/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/client/beans/ConfigurationParameters.java new file mode 100644 index 0000000000..b065e9a0c3 --- /dev/null +++ b/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/client/beans/ConfigurationParameters.java @@ -0,0 +1,53 @@ +package org.onap.so.adapters.appc.orchestrator.client.beans; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ConfigurationParameters { + + @JsonProperty("vnf_name") + private String vnfName; + @JsonProperty("book_name") + private String bookName; + @JsonProperty("node_list") + private String nodeList; + @JsonProperty("file_parameter_content") + private String fileParameterContent; + + + @JsonProperty("vnf_name") + public String getVnfName() { + return vnfName; + } + + @JsonProperty("vnf_name") + public void setVnfName(String vnfName) { + this.vnfName = vnfName; + } + + public String getBookName() { + return bookName; + } + + public void setBookName(String bookName) { + this.bookName = bookName; + } + + public String getNodeList() { + return nodeList; + } + + public void setNodeList(String nodeList) { + this.nodeList = nodeList; + } + + public String getFileParameterContent() { + return fileParameterContent; + } + + public void setFileParameterContent(String fileParameterContent) { + this.fileParameterContent = fileParameterContent; + } + +} diff --git a/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/client/beans/Identity.java b/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/client/beans/Identity.java new file mode 100644 index 0000000000..912441ad9a --- /dev/null +++ b/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/client/beans/Identity.java @@ -0,0 +1,24 @@ +package org.onap.so.adapters.appc.orchestrator.client.beans; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({"identity-url"}) +public class Identity { + + @JsonProperty("identity-url") + private String identityUrl; + + @JsonProperty("identity-url") + public String getIdentityUrl() { + return identityUrl; + } + + @JsonProperty("identity-url") + public void setIdentityUrl(String identityUrl) { + this.identityUrl = identityUrl; + } + +} diff --git a/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/client/beans/Parameters.java b/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/client/beans/Parameters.java new file mode 100644 index 0000000000..9b0385bd7a --- /dev/null +++ b/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/client/beans/Parameters.java @@ -0,0 +1,99 @@ +package org.onap.so.adapters.appc.orchestrator.client.beans; + + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({"vm-id", "identity-url", "old_software_version", "new_software_version", "operations_timeout", + "request-parameters", "configuration-parameters"}) +public class Parameters { + + @JsonProperty("vm-id") + private String vmId; + @JsonProperty("identity-url") + private String identityUrl; + @JsonProperty("operations_timeout") + private String operationsTimeout; + @JsonProperty("existing_software_version") + private String existingSoftwareVersion; + @JsonProperty("new_software_version") + private String newSoftwareVersion; + @JsonProperty("request-parameters") + private RequestParameters requestParameters; + @JsonProperty("configuration-parameters") + private ConfigurationParameters configurationParameters; + + @JsonProperty("request-parameters") + public RequestParameters getRequestParameters() { + return requestParameters; + } + + @JsonProperty("request-parameters") + public void setRequestParameters(RequestParameters requestParameters) { + this.requestParameters = requestParameters; + } + + @JsonProperty("configuration-parameters") + public ConfigurationParameters getConfigurationParameters() { + return configurationParameters; + } + + @JsonProperty("configuration-parameters") + public void setConfigurationParameters(ConfigurationParameters configurationParameters) { + this.configurationParameters = configurationParameters; + } + + @JsonProperty("vm-id") + public String getVmId() { + return vmId; + } + + @JsonProperty("vm-id") + public void setVmId(String vmId) { + this.vmId = vmId; + } + + @JsonProperty("identity-url") + public String getIdentityUrl() { + return identityUrl; + } + + @JsonProperty("identity-url") + public void setIdentityUrl(String identityUrl) { + this.identityUrl = identityUrl; + } + + @JsonProperty("operations_timeout") + public String getOperationsTimeout() { + return operationsTimeout; + } + + @JsonProperty("operations_timeout") + public void setOperationsTimeout(String operationsTimeout) { + this.operationsTimeout = operationsTimeout; + } + + @JsonProperty("existing_software_version") + public String getExistingSoftwareVersion() { + return existingSoftwareVersion; + } + + @JsonProperty("existing_software_version") + public void setExistingSoftwareVersion(String existingSoftwareVersion) { + this.existingSoftwareVersion = existingSoftwareVersion; + } + + @JsonProperty("new_software_version") + public String getNewSoftwareVersion() { + return newSoftwareVersion; + } + + @JsonProperty("new_software_version") + public void setNewSoftwareVersion(String newSoftwareVersion) { + this.newSoftwareVersion = newSoftwareVersion; + } + + +} diff --git a/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/client/beans/RequestParameters.java b/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/client/beans/RequestParameters.java new file mode 100644 index 0000000000..ddc0a0ea3d --- /dev/null +++ b/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/client/beans/RequestParameters.java @@ -0,0 +1,59 @@ +package org.onap.so.adapters.appc.orchestrator.client.beans; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class RequestParameters { + + @JsonProperty("vnf-host-ip-address") + private String vnfHostIpAddress; + @JsonProperty("vf-module-id") + private String vfModuleId; + @JsonProperty("vnf-name") + private String vnfName; + @JsonProperty("host-ip-address") + private String hostIpAddress; + + public String getVnfHostIpAddress() { + return vnfHostIpAddress; + } + + public void setVnfHostIpAddress(String vnfHostIpAddress) { + this.vnfHostIpAddress = vnfHostIpAddress; + } + + public String getVfModuleId() { + return vfModuleId; + } + + public void setVfModuleId(String vfModuleId) { + this.vfModuleId = vfModuleId; + } + + public String getVnfName() { + return vnfName; + } + + public void setVnfName(String vnfName) { + this.vnfName = vnfName; + } + + public String getHostIpAddress() { + return hostIpAddress; + } + + public void setHostIpAddress(String hostIpAddress) { + this.hostIpAddress = hostIpAddress; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("RequestParametersConfigScaleOut{"); + sb.append("vnf-host-ip-address=").append(vnfHostIpAddress); + sb.append(", vf-module-id='").append(vfModuleId); + sb.append('}'); + return sb.toString(); + } + +} diff --git a/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/service/ApplicationControllerTask.java b/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/service/ApplicationControllerTask.java new file mode 100644 index 0000000000..181d114cc0 --- /dev/null +++ b/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/service/ApplicationControllerTask.java @@ -0,0 +1,50 @@ +package org.onap.so.adapters.appc.orchestrator.service; + +import org.camunda.bpm.client.task.ExternalTask; +import org.camunda.bpm.client.task.ExternalTaskService; +import org.onap.so.adapters.appc.orchestrator.client.ApplicationControllerCallback; +import org.onap.so.adapters.appc.orchestrator.client.ApplicationControllerSupport; +import org.onap.so.appc.orchestrator.service.beans.ApplicationControllerTaskRequest; +import org.onap.so.externaltasks.logging.AuditMDCSetup; +import org.onap.so.utils.ExternalTaskUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; +import org.onap.appc.client.lcm.model.Status; + +@Component +public class ApplicationControllerTask extends ExternalTaskUtils { + + private static final Logger logger = LoggerFactory.getLogger(ApplicationControllerTask.class); + + @Autowired + public Environment env; + + @Autowired + public ApplicationControllerTaskImpl applicationControllerTaskImpl; + + @Autowired + public ApplicationControllerSupport applicationControllerSupport; + + @Autowired + private AuditMDCSetup mdcSetup; + + protected void executeExternalTask(ExternalTask externalTask, ExternalTaskService externalTaskService) { + mdcSetup.setupMDC(externalTask); + ApplicationControllerTaskRequest request = externalTask.getVariable("appcOrchestratorRequest"); + String msoRequestId = externalTask.getVariable("mso-request-id"); + logger.debug("Starting External Task for RequestId: {} ", msoRequestId); + Status status = null; + ApplicationControllerCallback listener = + new ApplicationControllerCallback(externalTask, externalTaskService, applicationControllerSupport); + + try { + status = applicationControllerTaskImpl.execute(msoRequestId, request, listener); + } catch (Exception e) { + logger.error("Error while calling appc", e.getMessage()); + } + } + +} diff --git a/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/service/ApplicationControllerTaskImpl.java b/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/service/ApplicationControllerTaskImpl.java new file mode 100644 index 0000000000..a174ccb05a --- /dev/null +++ b/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/service/ApplicationControllerTaskImpl.java @@ -0,0 +1,112 @@ +package org.onap.so.adapters.appc.orchestrator.service; + +import java.util.Optional; +import org.onap.appc.client.lcm.model.Status; +import org.onap.so.adapters.appc.orchestrator.client.ApplicationControllerCallback; +import org.onap.so.adapters.appc.orchestrator.client.ApplicationControllerClient; +import org.onap.so.adapters.appc.orchestrator.client.ApplicationControllerOrchestratorException; +import org.onap.so.adapters.appc.orchestrator.client.beans.ConfigurationParameters; +import org.onap.so.adapters.appc.orchestrator.client.beans.Identity; +import org.onap.so.adapters.appc.orchestrator.client.beans.Parameters; +import org.onap.so.adapters.appc.orchestrator.client.beans.RequestParameters; +import org.onap.so.appc.orchestrator.service.beans.ApplicationControllerTaskRequest; +import org.onap.so.appc.orchestrator.service.beans.ApplicationControllerVm; +import org.onap.so.client.graphinventory.GraphInventoryCommonObjectMapperProvider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import com.fasterxml.jackson.core.JsonProcessingException; + +@Component +public class ApplicationControllerTaskImpl { + + @Autowired + private ApplicationControllerClient appcClient; + + public Status execute(String msoRequestId, ApplicationControllerTaskRequest request, + ApplicationControllerCallback listener) + throws JsonProcessingException, ApplicationControllerOrchestratorException { + Status status = null; + GraphInventoryCommonObjectMapperProvider mapper = new GraphInventoryCommonObjectMapperProvider(); + Optional<String> payload = Optional.empty(); + String vmId = null; + Optional<String> vserverId = Optional.empty(); + Parameters parameters = new Parameters(); + ConfigurationParameters configParams = new ConfigurationParameters(); + + switch (request.getAction()) { + case HealthCheck: + RequestParameters requestParams = new RequestParameters(); + requestParams.setHostIpAddress(request.getApplicationControllerVnf().getVnfHostIpAddress()); + parameters.setRequestParameters(requestParams); + payload = Optional.of((mapper.getMapper().writeValueAsString(parameters))); + break; + case ResumeTraffic: + configParams.setVnfName(request.getApplicationControllerVnf().getVnfName()); + parameters.setConfigurationParameters(configParams); + payload = Optional.of((mapper.getMapper().writeValueAsString(parameters))); + break; + case Start: + case Stop: + Identity identity = new Identity(); + identity.setIdentityUrl(request.getIdentityUrl()); + payload = Optional.of((mapper.getMapper().writeValueAsString(identity))); + break; + case Unlock: + case Lock: + break; + case QuiesceTraffic: + parameters.setOperationsTimeout(request.getOperationsTimeout()); + payload = Optional.of((mapper.getMapper().writeValueAsString(parameters))); + break; + case DistributeTraffic: + configParams.setBookName(request.getBookName()); + configParams.setNodeList(request.getNodeList()); + configParams.setFileParameterContent(request.getFileParameters()); + configParams.setVnfName(request.getApplicationControllerVnf().getVnfName()); + parameters.setConfigurationParameters(configParams); + payload = Optional.of((mapper.getMapper().writeValueAsString(parameters))); + break; + case DistributeTrafficCheck: + configParams.setBookName(request.getBookName()); + configParams.setNodeList(request.getNodeList()); + configParams.setFileParameterContent(request.getFileParameters()); + configParams.setVnfName(request.getApplicationControllerVnf().getVnfName()); + parameters.setConfigurationParameters(configParams); + payload = Optional.of((mapper.getMapper().writeValueAsString(parameters))); + break; + case ConfigModify: + case ConfigScaleOut: + break; + case UpgradePreCheck: + case UpgradePostCheck: + case UpgradeSoftware: + case UpgradeBackup: + parameters.setExistingSoftwareVersion(request.getExistingSoftwareVersion()); + parameters.setNewSoftwareVersion(request.getNewSoftwareVersion()); + payload = Optional.of((mapper.getMapper().writeValueAsString(parameters))); + break; + case ActionStatus: + break; + case Snapshot: + ApplicationControllerVm applicationControllerVm = + request.getApplicationControllerVnf().getApplicationControllerVm(); + if (applicationControllerVm != null) { + vmId = request.getApplicationControllerVnf().getApplicationControllerVm().getVmId(); + parameters.setVmId(vmId); + payload = Optional.of((mapper.getMapper().writeValueAsString(parameters))); + vserverId = Optional + .of(request.getApplicationControllerVnf().getApplicationControllerVm().getVserverId()); + } + default: + // errorMessage = "Unable to idenify Action request for AppCClient"; + break; + } + + status = appcClient.vnfCommand(request.getAction(), msoRequestId, + request.getApplicationControllerVnf().getVnfId(), vserverId, payload, request.getControllerType(), + listener); + + return status; + } + +} diff --git a/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/service/ApplicationControllerTaskService.java b/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/service/ApplicationControllerTaskService.java new file mode 100644 index 0000000000..2a33124eac --- /dev/null +++ b/adapters/so-appc-orchestrator/src/main/java/org/onap/so/adapters/appc/orchestrator/service/ApplicationControllerTaskService.java @@ -0,0 +1,31 @@ +package org.onap.so.adapters.appc.orchestrator.service; + +import javax.annotation.PostConstruct; +import org.onap.so.utils.ExternalTaskServiceUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +@Component +@Profile("!test") +public class ApplicationControllerTaskService { + + @Autowired + public Environment env; + + @Autowired + private ApplicationControllerTask appcOrchestrator; + + @Autowired + private ExternalTaskServiceUtils externalTaskServiceUtils; + + @PostConstruct + public void appcOrchestrator() throws Exception { + for (int i = 0; i < externalTaskServiceUtils.getMaxClients(); i++) { + externalTaskServiceUtils.createExternalTaskClient().subscribe("AppcService").lockDuration(604800000) + .handler(appcOrchestrator::executeExternalTask).open(); + } + } + +} diff --git a/adapters/so-appc-orchestrator/src/main/resources/application.yaml b/adapters/so-appc-orchestrator/src/main/resources/application.yaml new file mode 100644 index 0000000000..c0c5962ea2 --- /dev/null +++ b/adapters/so-appc-orchestrator/src/main/resources/application.yaml @@ -0,0 +1,18 @@ +server: + port: 8080 + tomcat: + max-threads: 50 + +#Actuator +management: + endpoints: + web: + base-path: /manage + exposure: + include: "*" + metrics: + se-global-registry: false + export: + prometheus: + enabled: true # Whether exporting of metrics to Prometheus is enabled. + step: 1m # Step size (i.e. reporting frequency) to use.
\ No newline at end of file diff --git a/adapters/so-appc-orchestrator/src/test/java/org/onap/so/TestApplication.java b/adapters/so-appc-orchestrator/src/test/java/org/onap/so/TestApplication.java new file mode 100644 index 0000000000..fe965b4444 --- /dev/null +++ b/adapters/so-appc-orchestrator/src/test/java/org/onap/so/TestApplication.java @@ -0,0 +1,43 @@ +package org.onap.so; +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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========================================================= + */ + + + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.ComponentScan.Filter; +import org.springframework.context.annotation.FilterType; +import org.springframework.context.annotation.Profile; + +@SpringBootApplication +@Profile("test") +@ComponentScan(basePackages = {"org.onap.so"}, + excludeFilters = {@Filter(type = FilterType.ANNOTATION, classes = SpringBootApplication.class)}) +public class TestApplication { + public static void main(String... args) { + SpringApplication.run(TestApplication.class, args); + System.getProperties().setProperty("mso.db", "MARIADB"); + System.getProperties().setProperty("server.name", "Springboot"); + + + } +} diff --git a/adapters/so-appc-orchestrator/src/test/java/org/onap/so/adapters/appc/orchestrator/client/ApplicationControllerCallbackTest.java b/adapters/so-appc-orchestrator/src/test/java/org/onap/so/adapters/appc/orchestrator/client/ApplicationControllerCallbackTest.java new file mode 100644 index 0000000000..90f5a44752 --- /dev/null +++ b/adapters/so-appc-orchestrator/src/test/java/org/onap/so/adapters/appc/orchestrator/client/ApplicationControllerCallbackTest.java @@ -0,0 +1,113 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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 org.onap.so.adapters.appc.orchestrator.client; + +import static org.hamcrest.CoreMatchers.any; +import static org.mockito.Mockito.doReturn; +import org.camunda.bpm.client.task.ExternalTask; +import org.camunda.bpm.client.task.ExternalTaskService; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.onap.so.adapters.appc.orchestrator.client.ApplicationControllerCallback; +import org.onap.so.adapters.appc.orchestrator.client.ApplicationControllerSupport; +import org.onap.appc.client.lcm.model.Status; +import org.onap.appc.client.lcm.exceptions.AppcClientException; +import org.onap.appc.client.lcm.model.ResumeTrafficOutput; + +public class ApplicationControllerCallbackTest { + + @InjectMocks + ApplicationControllerCallback appcTaskCallback; + + @Mock + ApplicationControllerSupport applicationControllerSupport; + + @Mock + ExternalTask mockExternalTask; + + @Mock + ExternalTaskService mockExternalTaskService; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + appcTaskCallback = new ApplicationControllerCallback(mockExternalTask, mockExternalTaskService, + applicationControllerSupport); + } + + @Test + public void onResponse_appcCallback_success_Test() throws Exception { + Status status = new Status(); + status.setCode(400); + ResumeTrafficOutput response = new ResumeTrafficOutput(); + response.setStatus(status); + doReturn(status).when(applicationControllerSupport).getStatusFromGenericResponse(response); + doReturn(true).when(applicationControllerSupport).getFinalityOf(status); + doReturn(StatusCategory.NORMAL).when(applicationControllerSupport).getCategoryOf(status); + appcTaskCallback.onResponse(response); + Mockito.verify(mockExternalTaskService).complete(mockExternalTask); + } + + @Test + public void onResponse_appcCallback_intermediateResponse_Test() throws Exception { + Status status = new Status(); + status.setCode(100); + ResumeTrafficOutput response = new ResumeTrafficOutput(); + response.setStatus(status); + doReturn(status).when(applicationControllerSupport).getStatusFromGenericResponse(response); + appcTaskCallback.onResponse(response); + Mockito.verifyZeroInteractions(mockExternalTaskService); + } + + @Test + public void onResponse_appcCallback_failure_Test() throws Exception { + String testFailure = "test failure"; + Status status = new Status(); + status.setCode(200); + status.setMessage(testFailure); + ResumeTrafficOutput response = new ResumeTrafficOutput(); + response.setStatus(status); + doReturn(status).when(applicationControllerSupport).getStatusFromGenericResponse(response); + doReturn(true).when(applicationControllerSupport).getFinalityOf(status); + doReturn(StatusCategory.ERROR).when(applicationControllerSupport).getCategoryOf(status); + appcTaskCallback.onResponse(response); + Mockito.verify(mockExternalTaskService).handleBpmnError(mockExternalTask, "MSOWorkflowException", testFailure); + } + + @Test + public void onException_appcCallback_failure_Test() throws Exception { + String testFailure = "test failure"; + AppcClientException appcException = new AppcClientException(testFailure); + Status status = new Status(); + status.setCode(200); + String exceptionMessage = "Exception on APPC request: " + testFailure; + status.setMessage(exceptionMessage); + doReturn(status).when(applicationControllerSupport).buildStatusFromAppcException(appcException); + doReturn(StatusCategory.ERROR).when(applicationControllerSupport).getCategoryOf(status); + appcTaskCallback.onException(appcException); + Mockito.verify(mockExternalTaskService).handleBpmnError(mockExternalTask, "MSOWorkflowException", + exceptionMessage); + } +} diff --git a/adapters/so-appc-orchestrator/src/test/java/org/onap/so/adapters/appc/orchestrator/client/ApplicationControllerSupportTest.java b/adapters/so-appc-orchestrator/src/test/java/org/onap/so/adapters/appc/orchestrator/client/ApplicationControllerSupportTest.java new file mode 100644 index 0000000000..2dd2fd7ac8 --- /dev/null +++ b/adapters/so-appc-orchestrator/src/test/java/org/onap/so/adapters/appc/orchestrator/client/ApplicationControllerSupportTest.java @@ -0,0 +1,79 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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 org.onap.so.adapters.appc.orchestrator.client; + +import static org.assertj.core.api.Assertions.assertThat; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.onap.appc.client.lcm.exceptions.AppcClientException; +import org.onap.appc.client.lcm.model.Status; +import org.onap.so.adapters.appc.orchestrator.client.ApplicationControllerSupport; +import org.onap.so.adapters.appc.orchestrator.client.StatusCategory; +import junitparams.JUnitParamsRunner; +import junitparams.Parameters; + +@RunWith(JUnitParamsRunner.class) +public class ApplicationControllerSupportTest { + private ApplicationControllerSupport applicationControllerSupport = new ApplicationControllerSupport(); + + public static Object[][] statusesAndCategories() { + return new Object[][] {{100, StatusCategory.NORMAL}, {200, StatusCategory.ERROR}, {300, StatusCategory.ERROR}, + {400, StatusCategory.NORMAL}, {401, StatusCategory.ERROR}, {500, StatusCategory.NORMAL}, + {501, StatusCategory.ERROR}, {502, StatusCategory.WARNING}, {800, StatusCategory.WARNING},}; + } + + public static Object[][] statusesAndFinalities() { + return new Object[][] {{100, false}, {200, true}, {300, true}, {400, true}, {500, false}, {800, true},}; + } + + @Test + @Parameters(method = "statusesAndCategories") + public void shouldReturnCategoryForCode(int code, StatusCategory category) throws Exception { + // when + StatusCategory detectedCategory = applicationControllerSupport.getCategoryOf(createStatus(code)); + // then + assertThat(detectedCategory).isEqualTo(category); + } + + @Test + @Parameters(method = "statusesAndFinalities") + public void shouldReturnFinalityForCode(int code, boolean expectedFinality) throws Exception { + // when + boolean finality = applicationControllerSupport.getFinalityOf(createStatus(code)); + // then + assertThat(finality).isEqualTo(expectedFinality); + } + + @Test + public void buildStatusFromAppcException_Test() { + String errorMessage = "errormessage"; + AppcClientException exception = new AppcClientException(errorMessage); + Status status = applicationControllerSupport.buildStatusFromAppcException(exception); + assertThat(status.getCode() == 200); + assertThat((status.getMessage()).equals(("Exception on APPC request: " + errorMessage))); + } + + private Status createStatus(int code) { + Status status = new Status(); + status.setCode(code); + return status; + } +} diff --git a/adapters/so-appc-orchestrator/src/test/java/org/onap/so/adapters/appc/orchestrator/client/beans/BeansTest.java b/adapters/so-appc-orchestrator/src/test/java/org/onap/so/adapters/appc/orchestrator/client/beans/BeansTest.java new file mode 100644 index 0000000000..76b5efacb3 --- /dev/null +++ b/adapters/so-appc-orchestrator/src/test/java/org/onap/so/adapters/appc/orchestrator/client/beans/BeansTest.java @@ -0,0 +1,20 @@ +package org.onap.so.adapters.appc.orchestrator.client.beans; + +import org.junit.Test; +import com.openpojo.reflection.filters.FilterPackageInfo; +import com.openpojo.validation.Validator; +import com.openpojo.validation.ValidatorBuilder; +import com.openpojo.validation.rule.impl.GetterMustExistRule; +import com.openpojo.validation.rule.impl.SetterMustExistRule; +import com.openpojo.validation.test.impl.GetterTester; +import com.openpojo.validation.test.impl.SetterTester; + +public class BeansTest { + + @Test + public void validateGettersAndSetters() { + Validator validator = ValidatorBuilder.create().with(new SetterMustExistRule(), new GetterMustExistRule()) + .with(new SetterTester(), new GetterTester()).build(); + validator.validate("org.onap.so.adapters.appc.orchestrator.client.beans", new FilterPackageInfo()); + } +} diff --git a/adapters/so-appc-orchestrator/src/test/java/org/onap/so/adapters/appc/orchestrator/service/ApplicationControllerTaskImplITTest.java b/adapters/so-appc-orchestrator/src/test/java/org/onap/so/adapters/appc/orchestrator/service/ApplicationControllerTaskImplITTest.java new file mode 100644 index 0000000000..3eac851f13 --- /dev/null +++ b/adapters/so-appc-orchestrator/src/test/java/org/onap/so/adapters/appc/orchestrator/service/ApplicationControllerTaskImplITTest.java @@ -0,0 +1,88 @@ +package org.onap.so.adapters.appc.orchestrator.service; + +import java.util.List; +import java.util.Optional; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnitRunner; +import org.onap.appc.client.lcm.model.Status; +import org.onap.so.TestApplication; +import org.onap.so.adapters.appc.orchestrator.client.ApplicationControllerCallback; +import org.onap.so.adapters.appc.orchestrator.client.ApplicationControllerClient; +import org.onap.so.adapters.appc.orchestrator.client.ApplicationControllerOrchestratorException; +import org.onap.so.adapters.appc.orchestrator.client.ApplicationControllerSupport; +import org.onap.so.adapters.appc.orchestrator.client.beans.ConfigurationParameters; +import org.onap.so.adapters.appc.orchestrator.client.beans.Identity; +import org.onap.so.adapters.appc.orchestrator.client.beans.Parameters; +import org.onap.so.adapters.appc.orchestrator.client.beans.RequestParameters; +import org.onap.so.adapters.appc.orchestrator.service.ApplicationControllerTaskImpl; +import org.onap.so.appc.orchestrator.service.beans.ApplicationControllerTaskRequest; +import org.onap.so.appc.orchestrator.service.beans.ApplicationControllerVnf; +import org.onap.so.client.graphinventory.GraphInventoryCommonObjectMapperProvider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; +import org.camunda.bpm.client.task.ExternalTask; +import org.camunda.bpm.client.task.ExternalTaskService; +import com.fasterxml.jackson.core.JsonProcessingException; +import org.onap.appc.client.lcm.model.Action; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = TestApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ActiveProfiles("test") +@ContextConfiguration +@AutoConfigureWireMock(port = 0) +public class ApplicationControllerTaskImplITTest { + + @Autowired + private ApplicationControllerTaskImpl applicationControllerTaskImpl; + + @Mock + ExternalTask externalTask; + + @Mock + ExternalTaskService externalTaskService; + + @Mock + ApplicationControllerSupport appCSupport; + + ApplicationControllerTaskRequest request; + + ApplicationControllerCallback listener; + + GraphInventoryCommonObjectMapperProvider mapper = new GraphInventoryCommonObjectMapperProvider(); + + @Before + public void setup() { + request = new ApplicationControllerTaskRequest(); + request.setBookName("testBookName"); + request.setControllerType("testControllerType"); + request.setFileParameters("testFileParams"); + request.setIdentityUrl("testIdentityUrl"); + request.setNewSoftwareVersion("2.0"); + request.setExistingSoftwareVersion("1.0"); + request.setOperationsTimeout("30"); + ApplicationControllerVnf applicationControllerVnf = new ApplicationControllerVnf(); + applicationControllerVnf.setVnfHostIpAddress("100.100"); + applicationControllerVnf.setVnfId("testVnfId"); + applicationControllerVnf.setVnfName("testVnfName"); + request.setApplicationControllerVnf(applicationControllerVnf); + listener = new ApplicationControllerCallback(null, externalTaskService, appCSupport); + } + + + @Test + public void testListener() throws Exception { + request.setAction(Action.QuiesceTraffic); + Status status = applicationControllerTaskImpl.execute("testRequestId", request, listener); + } + +} diff --git a/adapters/so-appc-orchestrator/src/test/java/org/onap/so/adapters/appc/orchestrator/service/ApplicationControllerTaskImplTest.java b/adapters/so-appc-orchestrator/src/test/java/org/onap/so/adapters/appc/orchestrator/service/ApplicationControllerTaskImplTest.java new file mode 100644 index 0000000000..640e2dbd6e --- /dev/null +++ b/adapters/so-appc-orchestrator/src/test/java/org/onap/so/adapters/appc/orchestrator/service/ApplicationControllerTaskImplTest.java @@ -0,0 +1,236 @@ +package org.onap.so.adapters.appc.orchestrator.service; + +import java.util.Optional; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnitRunner; +import org.onap.appc.client.lcm.model.Status; +import org.onap.so.adapters.appc.orchestrator.client.ApplicationControllerCallback; +import org.onap.so.adapters.appc.orchestrator.client.ApplicationControllerClient; +import org.onap.so.adapters.appc.orchestrator.client.ApplicationControllerOrchestratorException; +import org.onap.so.adapters.appc.orchestrator.client.beans.ConfigurationParameters; +import org.onap.so.adapters.appc.orchestrator.client.beans.Identity; +import org.onap.so.adapters.appc.orchestrator.client.beans.Parameters; +import org.onap.so.adapters.appc.orchestrator.client.beans.RequestParameters; +import org.onap.so.adapters.appc.orchestrator.service.ApplicationControllerTaskImpl; +import org.onap.so.appc.orchestrator.service.beans.ApplicationControllerTaskRequest; +import org.onap.so.appc.orchestrator.service.beans.ApplicationControllerVnf; +import org.onap.so.client.graphinventory.GraphInventoryCommonObjectMapperProvider; +import com.fasterxml.jackson.core.JsonProcessingException; +import org.onap.appc.client.lcm.model.Action; + +@RunWith(MockitoJUnitRunner.class) +public class ApplicationControllerTaskImplTest { + + @Mock + ApplicationControllerClient applicationControllerClient; + + @InjectMocks + @Spy + ApplicationControllerTaskImpl applicationControllerTaskImpl; + + ApplicationControllerTaskRequest request; + + ApplicationControllerCallback listener; + + GraphInventoryCommonObjectMapperProvider mapper = new GraphInventoryCommonObjectMapperProvider(); + + @Before + public void setup() { + request = new ApplicationControllerTaskRequest(); + request.setBookName("testBookName"); + request.setControllerType("testControllerType"); + request.setFileParameters("testFileParams"); + request.setIdentityUrl("testIdentityUrl"); + request.setNewSoftwareVersion("2.0"); + request.setExistingSoftwareVersion("1.0"); + request.setOperationsTimeout("30"); + ApplicationControllerVnf applicationControllerVnf = new ApplicationControllerVnf(); + applicationControllerVnf.setVnfHostIpAddress("100.100"); + applicationControllerVnf.setVnfId("testVnfId"); + applicationControllerVnf.setVnfName("testVnfName"); + request.setApplicationControllerVnf(applicationControllerVnf); + listener = new ApplicationControllerCallback(null, null, null); + + } + + @Test + public void testExcute_healthCheck() throws JsonProcessingException, ApplicationControllerOrchestratorException { + request.setAction(Action.HealthCheck); + + Parameters parameters = new Parameters(); + RequestParameters requestParams = new RequestParameters(); + requestParams.setHostIpAddress(request.getApplicationControllerVnf().getVnfHostIpAddress()); + parameters.setRequestParameters(requestParams); + Optional<String> payload = Optional.of((mapper.getMapper().writeValueAsString(parameters))); + + Mockito.when(applicationControllerClient.vnfCommand(Action.HealthCheck, "testRequestId", + request.getApplicationControllerVnf().getVnfId(), Optional.empty(), payload, "testControllerType", + listener)).thenReturn(new Status()); + + Status status = applicationControllerTaskImpl.execute("testRequestId", request, listener); + + Mockito.verify(applicationControllerClient).vnfCommand(Action.HealthCheck, "testRequestId", + request.getApplicationControllerVnf().getVnfId(), Optional.empty(), payload, "testControllerType", + listener); + + } + + @Test + public void testExcute_resumeTraffic() throws JsonProcessingException, ApplicationControllerOrchestratorException { + request.setAction(Action.ResumeTraffic); + + Parameters parameters = new Parameters(); + ConfigurationParameters configParams = new ConfigurationParameters(); + configParams.setVnfName(request.getApplicationControllerVnf().getVnfName()); + parameters.setConfigurationParameters(configParams); + Optional<String> payload = Optional.of((mapper.getMapper().writeValueAsString(parameters))); + + Mockito.when(applicationControllerClient.vnfCommand(request.getAction(), "testRequestId", + request.getApplicationControllerVnf().getVnfId(), Optional.empty(), payload, "testControllerType", + listener)).thenReturn(new Status()); + + Status status = applicationControllerTaskImpl.execute("testRequestId", request, listener); + + Mockito.verify(applicationControllerClient).vnfCommand(request.getAction(), "testRequestId", + request.getApplicationControllerVnf().getVnfId(), Optional.empty(), payload, "testControllerType", + listener); + } + + @Test + public void testExcute_stop() throws JsonProcessingException, ApplicationControllerOrchestratorException { + request.setAction(Action.Stop); + + Identity identity = new Identity(); + identity.setIdentityUrl(request.getIdentityUrl()); + Optional<String> payload = Optional.of((mapper.getMapper().writeValueAsString(identity))); + + Mockito.when(applicationControllerClient.vnfCommand(request.getAction(), "testRequestId", + request.getApplicationControllerVnf().getVnfId(), Optional.empty(), payload, "testControllerType", + listener)).thenReturn(new Status()); + + Status status = applicationControllerTaskImpl.execute("testRequestId", request, listener); + + Mockito.verify(applicationControllerClient).vnfCommand(request.getAction(), "testRequestId", + request.getApplicationControllerVnf().getVnfId(), Optional.empty(), payload, "testControllerType", + listener); + } + + @Test + public void testExcute_lock() throws JsonProcessingException, ApplicationControllerOrchestratorException { + request.setAction(Action.Lock); + + Mockito.when(applicationControllerClient.vnfCommand(request.getAction(), "testRequestId", + request.getApplicationControllerVnf().getVnfId(), Optional.empty(), Optional.empty(), + "testControllerType", listener)).thenReturn(new Status()); + + Status status = applicationControllerTaskImpl.execute("testRequestId", request, listener); + + Mockito.verify(applicationControllerClient).vnfCommand(request.getAction(), "testRequestId", + request.getApplicationControllerVnf().getVnfId(), Optional.empty(), Optional.empty(), + "testControllerType", listener); + } + + @Test + public void testExcute_quiesceTraffic() throws JsonProcessingException, ApplicationControllerOrchestratorException { + request.setAction(Action.QuiesceTraffic); + + + Parameters parameters = new Parameters(); + parameters.setOperationsTimeout(request.getOperationsTimeout()); + Optional<String> payload = Optional.of((mapper.getMapper().writeValueAsString(parameters))); + System.out.println("PAYLOAD is: " + payload.get()); + + Mockito.when(applicationControllerClient.vnfCommand(request.getAction(), "testRequestId", + request.getApplicationControllerVnf().getVnfId(), Optional.empty(), payload, "testControllerType", + listener)).thenReturn(new Status()); + + Status status = applicationControllerTaskImpl.execute("testRequestId", request, listener); + + Mockito.verify(applicationControllerClient).vnfCommand(request.getAction(), "testRequestId", + request.getApplicationControllerVnf().getVnfId(), Optional.empty(), payload, "testControllerType", + listener); + } + + @Test + public void testExcute_distributeTraffic() + throws JsonProcessingException, ApplicationControllerOrchestratorException { + request.setAction(Action.DistributeTraffic); + + Parameters parameters = new Parameters(); + ConfigurationParameters configParams = new ConfigurationParameters(); + configParams.setBookName(request.getBookName()); + configParams.setNodeList(request.getNodeList()); + configParams.setFileParameterContent(request.getFileParameters()); + configParams.setVnfName(request.getApplicationControllerVnf().getVnfName()); + parameters.setConfigurationParameters(configParams); + Optional<String> payload = Optional.of((mapper.getMapper().writeValueAsString(parameters))); + + Mockito.when(applicationControllerClient.vnfCommand(request.getAction(), "testRequestId", + request.getApplicationControllerVnf().getVnfId(), Optional.empty(), payload, "testControllerType", + listener)).thenReturn(new Status()); + + Status status = applicationControllerTaskImpl.execute("testRequestId", request, listener); + + Mockito.verify(applicationControllerClient).vnfCommand(request.getAction(), "testRequestId", + request.getApplicationControllerVnf().getVnfId(), Optional.empty(), payload, "testControllerType", + listener); + } + + @Test + public void testExcute_distributeTrafficCheck() + throws JsonProcessingException, ApplicationControllerOrchestratorException { + request.setAction(Action.DistributeTrafficCheck); + + Parameters parameters = new Parameters(); + ConfigurationParameters configParams = new ConfigurationParameters(); + configParams.setBookName(request.getBookName()); + configParams.setNodeList(request.getNodeList()); + configParams.setFileParameterContent(request.getFileParameters()); + configParams.setVnfName(request.getApplicationControllerVnf().getVnfName()); + parameters.setConfigurationParameters(configParams); + Optional<String> payload = Optional.of((mapper.getMapper().writeValueAsString(parameters))); + + Mockito.when(applicationControllerClient.vnfCommand(request.getAction(), "testRequestId", + request.getApplicationControllerVnf().getVnfId(), Optional.empty(), payload, "testControllerType", + listener)).thenReturn(new Status()); + + Status status = applicationControllerTaskImpl.execute("testRequestId", request, listener); + + Mockito.verify(applicationControllerClient).vnfCommand(request.getAction(), "testRequestId", + request.getApplicationControllerVnf().getVnfId(), Optional.empty(), payload, "testControllerType", + listener); + } + + @Test + public void testExcute_upgradeBackup() throws JsonProcessingException, ApplicationControllerOrchestratorException { + request.setAction(Action.UpgradeBackup); + + Parameters parameters = new Parameters(); + parameters.setExistingSoftwareVersion(request.getExistingSoftwareVersion()); + parameters.setNewSoftwareVersion(request.getNewSoftwareVersion()); + Optional<String> payload = Optional.of((mapper.getMapper().writeValueAsString(parameters))); + + Mockito.when(applicationControllerClient.vnfCommand(request.getAction(), "testRequestId", + request.getApplicationControllerVnf().getVnfId(), Optional.empty(), payload, "testControllerType", + listener)).thenReturn(new Status()); + + Status status = applicationControllerTaskImpl.execute("testRequestId", request, listener); + + Mockito.verify(applicationControllerClient).vnfCommand(request.getAction(), "testRequestId", + request.getApplicationControllerVnf().getVnfId(), Optional.empty(), payload, "testControllerType", + listener); + } + + @Test + public void testListener() throws Exception { + request.setAction(Action.QuiesceTraffic); + Status status = applicationControllerTaskImpl.execute("testRequestId", request, listener); + } + +} diff --git a/adapters/so-appc-orchestrator/src/test/java/org/onap/so/adapters/appc/orchestrator/service/ApplicationControllerTaskTest.java b/adapters/so-appc-orchestrator/src/test/java/org/onap/so/adapters/appc/orchestrator/service/ApplicationControllerTaskTest.java new file mode 100644 index 0000000000..228ee90107 --- /dev/null +++ b/adapters/so-appc-orchestrator/src/test/java/org/onap/so/adapters/appc/orchestrator/service/ApplicationControllerTaskTest.java @@ -0,0 +1,76 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * 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 org.onap.so.adapters.appc.orchestrator.service; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import org.camunda.bpm.client.task.ExternalTask; +import org.camunda.bpm.client.task.ExternalTaskService; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.onap.so.externaltasks.logging.AuditMDCSetup; +import org.onap.so.adapters.appc.orchestrator.client.ApplicationControllerCallback; +import org.onap.so.appc.orchestrator.service.beans.ApplicationControllerTaskRequest; +import org.onap.appc.client.lcm.model.Status; + +public class ApplicationControllerTaskTest extends ApplicationControllerTask { + + @InjectMocks + ApplicationControllerTask appcTaskService = new ApplicationControllerTask(); + + @Mock + ApplicationControllerTaskImpl applicationControllerTaskImpl; + + @Mock + ExternalTask mockExternalTask; + + @Mock + ExternalTaskService mockExternalTaskService; + + @Mock + private AuditMDCSetup mdcSetup; + + private ApplicationControllerTaskRequest request = new ApplicationControllerTaskRequest(); + private String msoRequestId = "testRequestId"; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + doNothing().when(mdcSetup).setupMDC(mockExternalTask); + doReturn(request).when(mockExternalTask).getVariable("appcOrchestratorRequest"); + doReturn(msoRequestId).when(mockExternalTask).getVariable("mso-request-id"); + } + + @Test + public void executeExternalTask_appc_success_Test() throws Exception { + Status status = new Status(); + doReturn(status).when(applicationControllerTaskImpl).execute(any(String.class), + any(ApplicationControllerTaskRequest.class), any(ApplicationControllerCallback.class)); + appcTaskService.executeExternalTask(mockExternalTask, mockExternalTaskService); + Mockito.verify(applicationControllerTaskImpl).execute(any(String.class), + any(ApplicationControllerTaskRequest.class), any(ApplicationControllerCallback.class)); + } +} diff --git a/adapters/so-appc-orchestrator/src/test/resources/application-test.yaml b/adapters/so-appc-orchestrator/src/test/resources/application-test.yaml new file mode 100644 index 0000000000..eb693a263e --- /dev/null +++ b/adapters/so-appc-orchestrator/src/test/resources/application-test.yaml @@ -0,0 +1,17 @@ + +appc: + client: + key: LSl8QKolmKcC0yJR + response: + timeout: '60000' + secret: lgjXraD1HutKxv8jEN6tVouu + poolMembers: localhost:3904,localhost:3904 + service: ueb + topic: + read: + name: APPC-1902-SHDEV-WRITE + timeout: '120000' + write: APPC-1902-SHDEV-READ + sdnc: + read: SDNC-LCM-READ + write: SDNC-LCM-WRITE
\ No newline at end of file diff --git a/adapters/so-appc-orchestrator/src/test/resources/logback-test.xml b/adapters/so-appc-orchestrator/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..8a9e705ca6 --- /dev/null +++ b/adapters/so-appc-orchestrator/src/test/resources/logback-test.xml @@ -0,0 +1,31 @@ +<configuration> + + + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{1024} - %msg%n</pattern> + </encoder> + </appender> + + + <logger name="com.att.ecomp.audit" level="info" additivity="false"> + <appender-ref ref="STDOUT" /> + </logger> + + <logger name="com.att.eelf.metrics" level="info" additivity="false"> + <appender-ref ref="STDOUT" /> + </logger> + + <logger name="com.att.eelf.error" level="trace" additivity="false"> + <appender-ref ref="STDOUT" /> + </logger> + + <logger name="org.onap" level="${so.log.level:-WARN}" additivity="false"> + <appender-ref ref="STDOUT" /> + </logger> + + <root level="WARN"> + <appender-ref ref="STDOUT" /> + </root> + +</configuration>
\ No newline at end of file |