aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichaelMorris <michael.morris@est.tech>2019-04-02 17:14:42 +0000
committerMichaelMorris <michael.morris@est.tech>2019-04-02 17:14:42 +0000
commit173664d486788099829e40c1c741445100354db3 (patch)
tree20bbee5d7c47198cb6aa9587292ae944b2b7dea0
parent4a74d94ea4604504325b320d499e2f3708ef1514 (diff)
Add job handling
Issue-ID: SO-1624 Change-Id: I84c089d7b0ad610f0fe38be220a81a1f0762f394 Signed-off-by: MichaelMorris <michael.morris@est.tech>
-rw-r--r--adapters/mso-vnfm-adapter/mso-vnfm-adapter-api/src/main/resources/vnfmadapter.yaml2
-rw-r--r--adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProvider.java10
-rw-r--r--adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProviderConfiguration.java15
-rw-r--r--adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProviderImpl.java11
-rw-r--r--adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmUrlProvider.java73
-rw-r--r--adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/jobmanagement/JobManager.java119
-rw-r--r--adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/jobmanagement/VnfmOperation.java85
-rw-r--r--adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/lifecycle/LifecycleManager.java36
-rw-r--r--adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/VnfmAdapterController.java38
-rw-r--r--adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/VnfmAdapterControllerTest.java112
10 files changed, 485 insertions, 16 deletions
diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-adapter-api/src/main/resources/vnfmadapter.yaml b/adapters/mso-vnfm-adapter/mso-vnfm-adapter-api/src/main/resources/vnfmadapter.yaml
index dc5f85e5fe..9d0a5283af 100644
--- a/adapters/mso-vnfm-adapter/mso-vnfm-adapter-api/src/main/resources/vnfmadapter.yaml
+++ b/adapters/mso-vnfm-adapter/mso-vnfm-adapter-api/src/main/resources/vnfmadapter.yaml
@@ -241,7 +241,7 @@ definitions:
required:
- operationStatusRetrievalStatus
OperationStatusRetrievalStatusEnum:
- description: The status of the attempt to retrrieve the operation from the VNFM
+ description: The status of the attempt to retrieve the operation from the VNFM
type: string
enum:
- STATUS_FOUND
diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProvider.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProvider.java
index 0b5b65e7c3..f0646f3cf2 100644
--- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProvider.java
+++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProvider.java
@@ -21,6 +21,7 @@
package org.onap.so.adapters.vnfmadapter.extclients.vnfm;
import com.google.common.base.Optional;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse200;
import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse201;
/**
@@ -36,4 +37,13 @@ public interface VnfmServiceProvider {
*/
Optional<InlineResponse201> getVnf(final String vnfSelfLink);
+ /**
+ * Invoke a get request for a VNFM operation.
+ *
+ * @param vnfmId the id of the VNFM in AAI
+ * @param operationId the id of the operation on the VNFM
+ * @return the operation from the VNFM
+ */
+ Optional<InlineResponse200> getOperation(final String vnfmId, final String operationId);
+
}
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 28b0b14e4c..88008c6a3f 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,6 +21,7 @@
package org.onap.so.adapters.vnfmadapter.extclients.vnfm;
import static org.onap.so.client.RestTemplateConfig.CONFIGURABLE_REST_TEMPLATE;
+import java.util.Iterator;
import org.onap.so.configuration.rest.BasicHttpHeadersProvider;
import org.onap.so.configuration.rest.HttpHeadersProvider;
import org.onap.so.rest.service.HttpRestServiceProvider;
@@ -29,6 +30,9 @@ 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.http.converter.HttpMessageConverter;
+import org.springframework.http.converter.json.GsonHttpMessageConverter;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.RestTemplate;
/**
@@ -45,7 +49,18 @@ public class VnfmServiceProviderConfiguration {
private HttpRestServiceProvider getHttpRestServiceProvider(final RestTemplate restTemplate,
final HttpHeadersProvider httpHeadersProvider) {
+ setGsonMessageConverter(restTemplate);
return new HttpRestServiceProviderImpl(restTemplate, httpHeadersProvider);
}
+ private void setGsonMessageConverter(final RestTemplate restTemplate) {
+ final Iterator<HttpMessageConverter<?>> iterator = restTemplate.getMessageConverters().iterator();
+ while (iterator.hasNext()) {
+ if (iterator.next() instanceof MappingJackson2HttpMessageConverter) {
+ iterator.remove();
+ }
+ }
+ restTemplate.getMessageConverters().add(new GsonHttpMessageConverter());
+ }
+
}
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 4a141ede4c..43d4f1e0dd 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
@@ -21,6 +21,7 @@
package org.onap.so.adapters.vnfmadapter.extclients.vnfm;
import com.google.common.base.Optional;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse200;
import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse201;
import org.onap.so.rest.service.HttpRestServiceProvider;
import org.springframework.beans.factory.annotation.Autowired;
@@ -31,11 +32,13 @@ import org.springframework.stereotype.Service;
public class VnfmServiceProviderImpl implements VnfmServiceProvider {
private final HttpRestServiceProvider httpServiceProvider;
+ private final VnfmUrlProvider urlProvider;
@Autowired
- public VnfmServiceProviderImpl(
+ public VnfmServiceProviderImpl(final VnfmUrlProvider urlProvider,
@Qualifier("vnfmServiceProvider") final HttpRestServiceProvider httpServiceProvider) {
this.httpServiceProvider = httpServiceProvider;
+ this.urlProvider = urlProvider;
}
@Override
@@ -43,5 +46,9 @@ public class VnfmServiceProviderImpl implements VnfmServiceProvider {
return httpServiceProvider.get(vnfSelfLink, InlineResponse201.class);
}
-
+ @Override
+ public Optional<InlineResponse200> getOperation(final String vnfmId, final String operationId) {
+ final String url = urlProvider.getOperationUrl(vnfmId, operationId);
+ return httpServiceProvider.get(url, InlineResponse200.class);
+ }
}
diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmUrlProvider.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmUrlProvider.java
new file mode 100644
index 0000000000..f5a99b1d95
--- /dev/null
+++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmUrlProvider.java
@@ -0,0 +1,73 @@
+/*-
+ * ============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.vnfm;
+
+import static org.slf4j.LoggerFactory.getLogger;
+import java.net.URI;
+import org.onap.aai.domain.yang.EsrSystemInfo;
+import org.onap.aai.domain.yang.EsrSystemInfoList;
+import org.onap.so.adapters.vnfmadapter.extclients.aai.AaiServiceProvider;
+import org.onap.so.adapters.vnfmadapter.rest.exceptions.VnfmNotFoundException;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.web.util.UriComponentsBuilder;
+
+/**
+ * Provides URLs for REST calls to a VNFM.
+ */
+@Service
+public class VnfmUrlProvider {
+
+ private static Logger logger = getLogger(VnfmUrlProvider.class);
+ private final AaiServiceProvider aaiServiceProvider;
+
+ @Autowired
+ public VnfmUrlProvider(final AaiServiceProvider aaiServiceProvider) {
+ this.aaiServiceProvider = aaiServiceProvider;
+ }
+
+ /**
+ * Get the URL for a generic VNF in AAI.
+ *
+ * @param vnfId The identifier of the VNF
+ * @return the URL of the VNF
+ */
+ public String getOperationUrl(final String vnfmId, final String operationId) {
+ final String url = UriComponentsBuilder.fromUri(getBaseUri(vnfmId)).pathSegment("/vnf_lcm_op_occs/")
+ .pathSegment(operationId).build().toString();
+ logger.debug("getOperationUrl:" + url);
+
+ return url;
+ }
+
+ private URI getBaseUri(final String vnfmId) {
+ final EsrSystemInfoList vnfmEsrSystemInfoList = aaiServiceProvider.invokeGetVnfmEsrSystemInfoList(vnfmId);
+
+ if (vnfmEsrSystemInfoList != null) {
+ for (final EsrSystemInfo esrSystemInfo : vnfmEsrSystemInfoList.getEsrSystemInfo()) {
+ return UriComponentsBuilder.fromHttpUrl(esrSystemInfo.getServiceUrl()).build().toUri();
+ }
+ }
+
+ throw new VnfmNotFoundException("VNFM, or Service URL for VNFM, not found for VNFM " + vnfmId);
+ }
+}
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
new file mode 100644
index 0000000000..ac11bcee4b
--- /dev/null
+++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/jobmanagement/JobManager.java
@@ -0,0 +1,119 @@
+/*-
+ * ============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.jobmanagement;
+
+import static org.slf4j.LoggerFactory.getLogger;
+import com.google.common.base.Optional;
+import com.google.common.collect.Maps;
+import java.util.Map;
+import java.util.UUID;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.VnfmServiceProvider;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse200;
+import org.onap.vnfmadapter.v1.model.OperationEnum;
+import org.onap.vnfmadapter.v1.model.OperationStateEnum;
+import org.onap.vnfmadapter.v1.model.OperationStatusRetrievalStatusEnum;
+import org.onap.vnfmadapter.v1.model.QueryJobResponse;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * Manages jobs enabling the status of jobs to be queried. A job is associated with an operation on
+ * a VNFM.
+ */
+@Component
+public class JobManager {
+ private static final String SEPARATOR = "_";
+ private static Logger logger = getLogger(JobManager.class);
+ private final Map<String, VnfmOperation> mapOfJobIdToVnfmOperation = Maps.newConcurrentMap();
+ private final VnfmServiceProvider vnfmServiceProvider;
+
+ @Autowired
+ JobManager(final VnfmServiceProvider vnfmServiceProvider) {
+ this.vnfmServiceProvider = vnfmServiceProvider;
+ }
+
+ /**
+ * Create a job associated with an operation on a VNFM.
+ *
+ * @param vnfmId the VNFM the operation relates to
+ * @param operationId the ID of the associated VNFM operation
+ * @param waitForNotificationForSuccess if set to <code>true</code> the
+ * {@link QueryJobResponse#getOperationState()} shall not return
+ * {@link org.onap.vnfmadapter.v1.model.OperationStateEnum#COMPLETED} unless a required
+ * notification has been processed
+ * @return the ID of the job. Can be used to query the job using {@link #getVnfmOperation(String)}
+ */
+ public String createJob(final String vnfmId, final String operationId,
+ final boolean waitForNotificationForSuccess) {
+ final String jobId = vnfmId + SEPARATOR + UUID.randomUUID().toString();
+ final VnfmOperation vnfmOperation = new VnfmOperation(vnfmId, operationId, waitForNotificationForSuccess);
+ mapOfJobIdToVnfmOperation.put(jobId, vnfmOperation);
+ return jobId;
+ }
+
+ /**
+ * Get the operation, associated with the given job ID, from the VNFM.
+ *
+ * @param jobId the job ID
+ * @return the associated operation from the VNFM, or <code>null</code> of no operation is
+ * associated with the given job ID
+ */
+ public QueryJobResponse getVnfmOperation(final String jobId) {
+ final VnfmOperation vnfmOperation = mapOfJobIdToVnfmOperation.get(jobId);
+ final QueryJobResponse response = new QueryJobResponse();
+
+ if (vnfmOperation == null) {
+ return null;
+ }
+
+ final Optional<InlineResponse200> operationOptional =
+ vnfmServiceProvider.getOperation(vnfmOperation.getVnfmId(), vnfmOperation.getOperationId());
+ if (!operationOptional.isPresent()) {
+ return response.operationStatusRetrievalStatus(OperationStatusRetrievalStatusEnum.OPERATION_NOT_FOUND);
+ }
+ final InlineResponse200 operation = operationOptional.get();
+
+ logger.debug("Job Id: " + jobId + ", operationId: " + operation.getId() + ", operation details: " + operation);
+
+ response.setOperationStatusRetrievalStatus(OperationStatusRetrievalStatusEnum.STATUS_FOUND);
+ response.setId(operation.getId());
+ response.setOperation(OperationEnum.fromValue(operation.getOperation().getValue()));
+ response.setOperationState(getOperationState(vnfmOperation, operation));
+ response.setStartTime(operation.getStartTime());
+ response.setStateEnteredTime(operation.getStateEnteredTime());
+ response.setVnfInstanceId(operation.getVnfInstanceId());
+
+ return response;
+ }
+
+ private OperationStateEnum getOperationState(final VnfmOperation vnfmOperation,
+ final InlineResponse200 operationResponse) {
+ final OperationStateEnum operationState =
+ OperationStateEnum.fromValue(operationResponse.getOperationState().getValue());
+ if (operationState == OperationStateEnum.COMPLETED && vnfmOperation.isWaitForNotificationForSuccess()
+ && !vnfmOperation.isNotificationProcessed()) {
+ return org.onap.vnfmadapter.v1.model.OperationStateEnum.PROCESSING;
+ }
+ return operationState;
+ }
+
+}
diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/jobmanagement/VnfmOperation.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/jobmanagement/VnfmOperation.java
new file mode 100644
index 0000000000..916c9e4011
--- /dev/null
+++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/jobmanagement/VnfmOperation.java
@@ -0,0 +1,85 @@
+/*-
+ * ============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.jobmanagement;
+
+/**
+ * Represents an operation on a VNFM.
+ */
+public class VnfmOperation {
+
+ private final String vnfmId;
+ private final String operationId;
+ private boolean waitForNotificationForSuccess = false;
+ private boolean isNotificationProcessed = false;
+
+ public VnfmOperation(final String vnfmId, final String operationId, final boolean waitForNotificationForSuccess) {
+ this.vnfmId = vnfmId;
+ this.operationId = operationId;
+ this.waitForNotificationForSuccess = waitForNotificationForSuccess;
+ }
+
+ /**
+ * Get the ID of the operation on the VNFM.
+ *
+ * @return the ID of the operation on the VNFM
+ */
+ public String getOperationId() {
+ return operationId;
+ }
+
+ /**
+ * Get the ID of the VNFM the operation is carried out by.
+ *
+ * @return the ID of the VNFM
+ */
+ public String getVnfmId() {
+ return vnfmId;
+ }
+
+ /**
+ * Check if a notification should be processed before the operation is considered successfully
+ * completed.
+ *
+ * @return <code>true></code> if a notification must be processed before the operation is considered
+ * successfully completed, <code>false</code> otherwise
+ */
+ public boolean isWaitForNotificationForSuccess() {
+ return waitForNotificationForSuccess;
+ }
+
+ /**
+ * Set the required notification has been processed for the operation.
+ */
+ public void setNotificationProcessed() {
+ this.isNotificationProcessed = true;
+ }
+
+ /**
+ * Check if the required notification has been processed.
+ *
+ * @return <code>true</code> of the required notification has been processed, <code>false</code>
+ * otherwise
+ */
+ public boolean isNotificationProcessed() {
+ return isNotificationProcessed;
+ }
+
+}
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 4c54ded4ae..5c944ca38b 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
@@ -28,31 +28,45 @@ import org.onap.so.adapters.vnfmadapter.extclients.aai.AaiClientProvider;
import org.onap.so.adapters.vnfmadapter.extclients.aai.AaiHelper;
import org.onap.so.adapters.vnfmadapter.extclients.vnfm.VnfmServiceProvider;
import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse201;
+import org.onap.so.adapters.vnfmadapter.jobmanagement.JobManager;
import org.onap.so.client.aai.AAIObjectType;
import org.onap.so.client.aai.entities.uri.AAIUriFactory;
import org.onap.so.client.graphinventory.entities.uri.Depth;
import org.onap.vnfmadapter.v1.model.CreateVnfRequest;
import org.onap.vnfmadapter.v1.model.CreateVnfResponse;
+import org.onap.vnfmadapter.v1.model.DeleteVnfResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
+/**
+ * Manages lifecycle operations towards the VNFMs.
+ */
@Component
public class LifecycleManager {
private static final Logger logger = LoggerFactory.getLogger(LifecycleManager.class);
private final AaiClientProvider aaiClientProvider;
private final VnfmServiceProvider vnfmServiceProvider;
private final AaiHelper aaiHelper;
+ private final JobManager jobManager;
@Autowired
LifecycleManager(final AaiClientProvider aaiClientProvider, final AaiHelper aaiHelper,
- final VnfmServiceProvider vnfmServiceProvider) {
+ final VnfmServiceProvider vnfmServiceProvider, final JobManager jobManager) {
this.aaiClientProvider = aaiClientProvider;
this.vnfmServiceProvider = vnfmServiceProvider;
this.aaiHelper = aaiHelper;
+ this.jobManager = jobManager;
}
+ /**
+ * Create a VNF on a VNFM.
+ *
+ * @param vnfIdInAai the ID of the VNF in AAI
+ * @param request the create request
+ * @return the response to the request
+ */
public CreateVnfResponse createVnf(final String vnfIdInAai, final CreateVnfRequest request) {
final GenericVnf genericVnf = getGenericVnfFromAai(vnfIdInAai);
checkIfVnfAlreadyExistsInVnfm(genericVnf);
@@ -63,8 +77,11 @@ public class LifecycleManager {
aaiHelper.addRelationshipFromGenericVnfToVnfm(genericVnf, vnfm.getVnfmId());
}
+ // operation ID set to random value for now, will be set correctly once we implement instantiate
+ // call towards the VNFM
+ final String jobId = jobManager.createJob(vnfm.getVnfmId(), UUID.randomUUID().toString(), false);
final CreateVnfResponse response = new CreateVnfResponse();
- response.setJobId(UUID.randomUUID().toString());
+ response.setJobId(jobId);
return response;
}
@@ -94,4 +111,19 @@ public class LifecycleManager {
}
}
}
+
+ /**
+ * Delete a VNF on a VNFM.
+ *
+ * @param vnfIdInAai the ID of the VNF in AAI
+ * @return the response to the request
+ */
+ public DeleteVnfResponse deleteVnf(final String vnfIdInAai) {
+ // vnfm ID and operation ID set to random value for now, will be set correctly once we implement
+ // terminate call towards the VNFM
+ final String jobId = jobManager.createJob(UUID.randomUUID().toString(), UUID.randomUUID().toString(), true);
+ final DeleteVnfResponse response = new DeleteVnfResponse();
+ response.setJobId(jobId);
+ return response;
+ }
}
diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/VnfmAdapterController.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/VnfmAdapterController.java
index 65d5478a57..055b8e0450 100644
--- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/VnfmAdapterController.java
+++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/VnfmAdapterController.java
@@ -21,14 +21,15 @@
package org.onap.so.adapters.vnfmadapter.rest;
import static org.onap.so.adapters.vnfmadapter.Constants.BASE_URL;
-import java.util.UUID;
import javax.validation.Valid;
import javax.ws.rs.core.MediaType;
import org.onap.logging.ref.slf4j.ONAPLogConstants;
+import org.onap.so.adapters.vnfmadapter.jobmanagement.JobManager;
import org.onap.so.adapters.vnfmadapter.lifecycle.LifecycleManager;
import org.onap.vnfmadapter.v1.model.CreateVnfRequest;
import org.onap.vnfmadapter.v1.model.CreateVnfResponse;
import org.onap.vnfmadapter.v1.model.DeleteVnfResponse;
+import org.onap.vnfmadapter.v1.model.QueryJobResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
@@ -37,6 +38,7 @@ 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;
@@ -54,10 +56,12 @@ public class VnfmAdapterController {
private static final Logger logger = LoggerFactory.getLogger(VnfmAdapterController.class);
private final LifecycleManager lifecycleManager;
+ private final JobManager jobManager;
@Autowired
- VnfmAdapterController(final LifecycleManager lifecycleManager) {
+ VnfmAdapterController(final LifecycleManager lifecycleManager, final JobManager jobManager) {
this.lifecycleManager = lifecycleManager;
+ this.jobManager = jobManager;
}
@PostMapping(value = "/vnfs/{vnfId}")
@@ -109,12 +113,38 @@ public class VnfmAdapterController {
logger.info("REST request vnfDelete for VNF: {}", vnfId);
- final DeleteVnfResponse response = new DeleteVnfResponse();
- response.setJobId(UUID.randomUUID().toString());
+ final DeleteVnfResponse response = lifecycleManager.deleteVnf(vnfId);
clearLoggingMDCs();
return new ResponseEntity<>(response, HttpStatus.ACCEPTED);
}
+ @GetMapping(value = "/jobs/{jobId}")
+ public ResponseEntity<QueryJobResponse> jobQuery(
+ @ApiParam(value = "The identifier of the Job.", required = true) @PathVariable("jobId") final String jobId,
+ @ApiParam(
+ value = "Used to track REST requests for logging purposes. Identifies a single top level invocation of ONAP",
+ required = false) @RequestHeader(value = ONAPLogConstants.Headers.REQUEST_ID,
+ required = false) final String requestId,
+ @ApiParam(
+ value = "Used to track REST requests for logging purposes. Identifies the client application user agent or user invoking the API",
+ required = false) @RequestHeader(value = ONAPLogConstants.Headers.PARTNER_NAME,
+ required = false) final String partnerName,
+ @ApiParam(
+ value = "Used to track REST requests for logging purposes. Identifies a single invocation of a single component",
+ required = false) @RequestHeader(value = ONAPLogConstants.Headers.INVOCATION_ID,
+ required = false) final String invocationId) {
+
+ setLoggingMDCs(requestId, partnerName, invocationId);
+
+ final QueryJobResponse response = jobManager.getVnfmOperation(jobId);
+ if (response == null) {
+ return new ResponseEntity<>(HttpStatus.NOT_FOUND);
+ }
+ return new ResponseEntity<>(response, HttpStatus.OK);
+
+ }
+
+
private void setLoggingMDCs(final String requestId, final String partnerName, final String invocationId) {
MDC.put(ONAPLogConstants.MDCs.REQUEST_ID, requestId);
MDC.put(ONAPLogConstants.MDCs.PARTNER_NAME, partnerName);
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 e307a253f8..29bab9dc6a 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
@@ -33,6 +33,7 @@ import java.net.URI;
import java.util.Optional;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
+import org.hamcrest.core.StringStartsWith;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -47,6 +48,7 @@ import org.onap.aai.domain.yang.Relationship;
import org.onap.aai.domain.yang.RelationshipData;
import org.onap.aai.domain.yang.RelationshipList;
import org.onap.so.adapters.vnfmadapter.VnfmAdapterApplication;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse200;
import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse201;
import org.onap.so.adapters.vnfmadapter.rest.exceptions.VnfmNotFoundException;
import org.onap.so.client.aai.AAIResourcesClient;
@@ -54,6 +56,9 @@ import org.onap.so.client.aai.entities.uri.AAIResourceUri;
import org.onap.vnfmadapter.v1.model.CreateVnfRequest;
import org.onap.vnfmadapter.v1.model.CreateVnfResponse;
import org.onap.vnfmadapter.v1.model.DeleteVnfResponse;
+import org.onap.vnfmadapter.v1.model.OperationEnum;
+import org.onap.vnfmadapter.v1.model.OperationStateEnum;
+import org.onap.vnfmadapter.v1.model.QueryJobResponse;
import org.onap.vnfmadapter.v1.model.Tenant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
@@ -70,6 +75,9 @@ 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 org.threeten.bp.LocalDateTime;
+import org.threeten.bp.OffsetDateTime;
+import org.threeten.bp.ZoneOffset;
@RunWith(SpringRunner.class)
@@ -78,6 +86,11 @@ import org.springframework.web.client.RestTemplate;
public class VnfmAdapterControllerTest {
+ private static final OffsetDateTime JAN_1_2019_12_00 =
+ OffsetDateTime.of(LocalDateTime.of(2019, 1, 1, 12, 0), ZoneOffset.UTC);
+ private static final OffsetDateTime JAN_1_2019_1_00 =
+ OffsetDateTime.of(LocalDateTime.of(2019, 1, 1, 1, 0), ZoneOffset.UTC);
+
@LocalServerPort
private int port;
@Autowired
@@ -144,16 +157,28 @@ public class VnfmAdapterControllerTest {
doReturn(Optional.of(esrSystemInfoList1)).when(aaiResourcesClient).get(eq(EsrSystemInfoList.class),
MockitoHamcrest.argThat(new AaiResourceUriMatcher(
"/external-system/esr-vnfm-list/esr-vnfm/vnfm1/esr-system-info-list")));
-
doReturn(Optional.of(esrSystemInfoList2)).when(aaiResourcesClient).get(eq(EsrSystemInfoList.class),
MockitoHamcrest.argThat(new AaiResourceUriMatcher(
"/external-system/esr-vnfm-list/esr-vnfm/vnfm2/esr-system-info-list")));
+ final InlineResponse200 firstOperationQueryResponse = createOperationQueryResponse(
+ org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse200.OperationEnum.INSTANTIATE,
+ org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse200.OperationStateEnum.PROCESSING);
+ mockRestServer.expect(requestTo(new StringStartsWith("http://vnfm2:8080/vnf_lcm_op_occs")))
+ .andRespond(withSuccess(gson.toJson(firstOperationQueryResponse), MediaType.APPLICATION_JSON));
- final ResponseEntity<CreateVnfResponse> response =
+ final InlineResponse200 secondOperationQueryReponse = createOperationQueryResponse(
+ org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse200.OperationEnum.INSTANTIATE,
+ org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse200.OperationStateEnum.COMPLETED);
+ mockRestServer.expect(requestTo(new StringStartsWith("http://vnfm2:8080/vnf_lcm_op_occs")))
+ .andRespond(withSuccess(gson.toJson(secondOperationQueryReponse), MediaType.APPLICATION_JSON));
+
+ // Invoke the create request
+
+ final ResponseEntity<CreateVnfResponse> createVnfResponse =
controller.vnfCreate("myTestVnfId", createVnfRequest, "asadas", "so", "1213");
- assertEquals(HttpStatus.ACCEPTED, response.getStatusCode());
- assertNotNull(response.getBody().getJobId());
+ assertEquals(HttpStatus.ACCEPTED, createVnfResponse.getStatusCode());
+ assertNotNull(createVnfResponse.getBody().getJobId());
final ArgumentCaptor<GenericVnf> genericVnfArgument = ArgumentCaptor.forClass(GenericVnf.class);
final ArgumentCaptor<AAIResourceUri> uriArgument = ArgumentCaptor.forClass(AAIResourceUri.class);
@@ -169,6 +194,22 @@ public class VnfmAdapterControllerTest {
assertEquals("esr-vnfm", createdRelationship.getRelatedTo());
assertEquals("tosca.relationships.DependsOn", createdRelationship.getRelationshipLabel());
assertEquals("/aai/v15/external-system/esr-vnfm-list/esr-vnfm/vnfm2", createdRelationship.getRelatedLink());
+
+ // check the job status
+
+ final ResponseEntity<QueryJobResponse> firstJobQueryResponse =
+ controller.jobQuery(createVnfResponse.getBody().getJobId(), "", "so", "1213");
+ assertEquals(OperationEnum.INSTANTIATE, firstJobQueryResponse.getBody().getOperation());
+ assertEquals(OperationStateEnum.PROCESSING, firstJobQueryResponse.getBody().getOperationState());
+ assertEquals(JAN_1_2019_12_00, firstJobQueryResponse.getBody().getStartTime());
+ assertEquals(JAN_1_2019_1_00, firstJobQueryResponse.getBody().getStateEnteredTime());
+
+ final ResponseEntity<QueryJobResponse> secondJobQueryResponse =
+ controller.jobQuery(createVnfResponse.getBody().getJobId(), "", "so", "1213");
+ assertEquals(OperationEnum.INSTANTIATE, secondJobQueryResponse.getBody().getOperation());
+ assertEquals(OperationStateEnum.COMPLETED, secondJobQueryResponse.getBody().getOperationState());
+ assertEquals(JAN_1_2019_12_00, secondJobQueryResponse.getBody().getStartTime());
+ assertEquals(JAN_1_2019_1_00, secondJobQueryResponse.getBody().getStateEnteredTime());
}
@Test(expected = IllegalArgumentException.class)
@@ -336,9 +377,62 @@ public class VnfmAdapterControllerTest {
.delete(new URI("http://localhost:" + port + "/so/vnfm-adapter/v1/vnfs/myVnfId"))
.accept(MediaType.APPLICATION_JSON).header("X-ONAP-RequestId", "myRequestId")
.header("X-ONAP-InvocationID", "myInvocationId").header("Content-Type", "application/json").build();
- final ResponseEntity<DeleteVnfResponse> response = restTemplate.exchange(request, DeleteVnfResponse.class);
- assertEquals(202, response.getStatusCode().value());
- assertNotNull(response.getBody().getJobId());
+ final ResponseEntity<DeleteVnfResponse> deleteVnfResponse =
+ restTemplate.exchange(request, DeleteVnfResponse.class);
+ assertEquals(202, deleteVnfResponse.getStatusCode().value());
+ assertNotNull(deleteVnfResponse.getBody().getJobId());
+
+
+ final EsrSystemInfo esrSystemInfo = new EsrSystemInfo();
+ esrSystemInfo.setServiceUrl("http://vnfm:8080");
+ esrSystemInfo.setType("vnfmType");
+ esrSystemInfo.setSystemType("VNFM");
+ final EsrSystemInfoList esrSystemInfoList = new EsrSystemInfoList();
+ esrSystemInfoList.getEsrSystemInfo().add(esrSystemInfo);
+
+ doReturn(Optional.of(esrSystemInfoList)).when(aaiResourcesClient).get(eq(EsrSystemInfoList.class),
+ MockitoHamcrest.argThat(new AaiResourceUriMatcher("/external-system/esr-vnfm-list/esr-vnfm/...")));
+
+ final InlineResponse200 firstOperationQueryResponse = createOperationQueryResponse(
+ org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse200.OperationEnum.TERMINATE,
+ org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse200.OperationStateEnum.PROCESSING);
+ mockRestServer.expect(requestTo(new StringStartsWith("http://vnfm:8080/vnf_lcm_op_occs")))
+ .andRespond(withSuccess(gson.toJson(firstOperationQueryResponse), MediaType.APPLICATION_JSON));
+
+
+ final InlineResponse200 secondOperationQueryReponse = createOperationQueryResponse(
+ org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse200.OperationEnum.TERMINATE,
+ org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse200.OperationStateEnum.COMPLETED);
+ mockRestServer.expect(requestTo(new StringStartsWith("http://vnfm:8080/vnf_lcm_op_occs")))
+ .andRespond(withSuccess(gson.toJson(secondOperationQueryReponse), MediaType.APPLICATION_JSON));
+
+
+ final ResponseEntity<QueryJobResponse> firstJobQueryResponse =
+ controller.jobQuery(deleteVnfResponse.getBody().getJobId(), "", "so", "1213");
+ assertEquals(OperationEnum.TERMINATE, firstJobQueryResponse.getBody().getOperation());
+ assertEquals(OperationStateEnum.PROCESSING, firstJobQueryResponse.getBody().getOperationState());
+ assertEquals(JAN_1_2019_12_00, firstJobQueryResponse.getBody().getStartTime());
+ assertEquals(JAN_1_2019_1_00, firstJobQueryResponse.getBody().getStateEnteredTime());
+
+ final ResponseEntity<QueryJobResponse> secondJobQueryResponse =
+ controller.jobQuery(deleteVnfResponse.getBody().getJobId(), "", "so", "1213");
+ assertEquals(OperationEnum.TERMINATE, secondJobQueryResponse.getBody().getOperation());
+ assertEquals(OperationStateEnum.PROCESSING, secondJobQueryResponse.getBody().getOperationState());
+ assertEquals(JAN_1_2019_12_00, secondJobQueryResponse.getBody().getStartTime());
+ assertEquals(JAN_1_2019_1_00, secondJobQueryResponse.getBody().getStateEnteredTime());
+ }
+
+ private InlineResponse200 createOperationQueryResponse(
+ final org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse200.OperationEnum operation,
+ final org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse200.OperationStateEnum operationState) {
+ final InlineResponse200 response = new InlineResponse200();
+ response.setId("9876");
+ response.setOperation(operation);
+ response.setOperationState(operationState);
+ response.setStartTime(JAN_1_2019_12_00);
+ response.setStateEnteredTime(JAN_1_2019_1_00);
+ response.setVnfInstanceId("myVnfInstanceId");
+ return response;
}
private class AaiResourceUriMatcher extends BaseMatcher<AAIResourceUri> {
@@ -352,6 +446,10 @@ public class VnfmAdapterControllerTest {
@Override
public boolean matches(final Object item) {
if (item instanceof AAIResourceUri) {
+ if (uriAsString.endsWith("...")) {
+ return ((AAIResourceUri) item).build().toString()
+ .startsWith(uriAsString.substring(0, uriAsString.indexOf("...")));
+ }
return ((AAIResourceUri) item).build().toString().equals(uriAsString);
}
return false;