/*- * ============LICENSE_START======================================================= * ONAP - SO * ================================================================================ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. * Copyright (C) 2017 Huawei Technologies Co., Ltd. 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.openecomp.mso.adapters.network; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.POST; 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.core.GenericEntity; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.xml.ws.Holder; import org.apache.http.HttpStatus; import org.openecomp.mso.adapters.network.exceptions.NetworkException; import org.openecomp.mso.adapters.nwrest.ContrailNetwork; import org.openecomp.mso.adapters.nwrest.CreateNetworkError; import org.openecomp.mso.adapters.nwrest.CreateNetworkRequest; import org.openecomp.mso.adapters.nwrest.CreateNetworkResponse; import org.openecomp.mso.adapters.nwrest.DeleteNetworkError; import org.openecomp.mso.adapters.nwrest.DeleteNetworkRequest; import org.openecomp.mso.adapters.nwrest.DeleteNetworkResponse; import org.openecomp.mso.adapters.nwrest.ProviderVlanNetwork; import org.openecomp.mso.adapters.nwrest.QueryNetworkError; import org.openecomp.mso.adapters.nwrest.QueryNetworkResponse; import org.openecomp.mso.adapters.nwrest.RollbackNetworkError; import org.openecomp.mso.adapters.nwrest.RollbackNetworkRequest; import org.openecomp.mso.adapters.nwrest.RollbackNetworkResponse; import org.openecomp.mso.adapters.nwrest.UpdateNetworkError; import org.openecomp.mso.adapters.nwrest.UpdateNetworkRequest; import org.openecomp.mso.adapters.nwrest.UpdateNetworkResponse; import org.openecomp.mso.cloud.CloudConfigFactory; import org.openecomp.mso.entity.MsoRequest; import org.openecomp.mso.logger.MessageEnum; import org.openecomp.mso.logger.MsoLogger; import org.openecomp.mso.openstack.beans.NetworkRollback; import org.openecomp.mso.openstack.beans.NetworkStatus; import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory; import org.openecomp.mso.properties.MsoPropertiesFactory; @Path("/v1/networks") public class NetworkAdapterRest { private static final MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA); private static final String TESTING_KEYWORD = "___TESTING___"; private final CloudConfigFactory cloudConfigFactory = new CloudConfigFactory(); private final MsoPropertiesFactory msoPropertiesFactory = new MsoPropertiesFactory(); private final MsoNetworkAdapterImpl adapter = new MsoNetworkAdapterImpl(msoPropertiesFactory, cloudConfigFactory); @POST @Path("") @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public Response createNetwork(CreateNetworkRequest req) { LOGGER.debug("createNetwork enter: " + req.toJsonString()); CreateNetworkTask task = new CreateNetworkTask(req); if (req.isSynchronous()) { // This is a synchronous request task.run(); return Response .status(task.getStatusCode()) .entity(task.getGenericEntityResponse()) .build(); } else { // This is an asynchronous request try { Thread t1 = new Thread(task); t1.start(); } catch (Exception e) { // problem handling create, send generic failure as sync resp to caller LOGGER.error (MessageEnum.RA_CREATE_NETWORK_EXC, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception while create network", e); return Response.serverError().build(); } // send sync response (ACK) to caller LOGGER.debug ("createNetwork exit"); return Response.status(HttpStatus.SC_ACCEPTED).build(); } } public class CreateNetworkTask implements Runnable { private final CreateNetworkRequest req; private CreateNetworkResponse response = null; private CreateNetworkError eresp = null; private boolean sendxml; public CreateNetworkTask(CreateNetworkRequest req) { this.req = req; this.sendxml = true; // can be set with a field or header later } public int getStatusCode() { return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; } public Object getGenericEntityResponse() { return (response != null) ? new GenericEntity(response) {} : new GenericEntity(eresp) {}; } private String getResponse() { if (response != null) { return sendxml ? response.toXmlString() : response.toJsonString(); } else { return sendxml ? eresp.toXmlString() : eresp.toJsonString(); } } @Override public void run() { LOGGER.debug ("CreateNetworkTask start"); try { // Synchronous Web Service Outputs Holder networkId = new Holder<>(); Holder neutronNetworkId = new Holder<>(); Holder networkFqdn = new Holder<>(); Holder> subnetIdMap = new Holder<>(); Holder rollback = new Holder<>(); String cloudsite = req.getCloudSiteId(); if (cloudsite != null && cloudsite.equals(TESTING_KEYWORD)) { String tenant = req.getTenantId(); if (tenant != null && tenant.equals(TESTING_KEYWORD)) { throw new NetworkException("testing."); } networkId.value = "479D3D8B-6360-47BC-AB75-21CC91981484"; neutronNetworkId.value = "55e55884-28fa-11e6-8971-0017f20fe1b8"; networkFqdn.value = "086f70b6-28fb-11e6-8260-0017f20fe1b8"; subnetIdMap.value = testMap(); rollback.value = new NetworkRollback(); } else if (req.isContrailRequest()) { ContrailNetwork ctn = req.getContrailNetwork(); if (ctn == null) { ctn = new ContrailNetwork(); req.setContrailNetwork(ctn); } adapter.createNetworkContrail( req.getCloudSiteId(), req.getTenantId(), req.getNetworkType(), req.getModelCustomizationUuid(), req.getNetworkName(), req.getContrailNetwork().getRouteTargets(), req.getContrailNetwork().getShared(), req.getContrailNetwork().getExternal(), req.getFailIfExists(), req.getBackout(), req.getSubnets(), req.getContrailNetwork().getPolicyFqdns(), req.getContrailNetwork().getRouteTableFqdns(), req.getMsoRequest(), networkId, neutronNetworkId, networkFqdn, subnetIdMap, rollback); } else { ProviderVlanNetwork pvn = req.getProviderVlanNetwork(); if (pvn == null) { pvn = new ProviderVlanNetwork(); req.setProviderVlanNetwork(pvn); } adapter.createNetwork( req.getCloudSiteId(), req.getTenantId(), req.getNetworkType(), req.getModelCustomizationUuid(), req.getNetworkName(), req.getProviderVlanNetwork().getPhysicalNetworkName(), req.getProviderVlanNetwork().getVlans(), req.getFailIfExists(), req.getBackout(), req.getSubnets(), req.getMsoRequest(), networkId, neutronNetworkId, subnetIdMap, rollback); } response = new CreateNetworkResponse( req.getNetworkId(), neutronNetworkId.value, rollback.value.getNetworkStackId(), networkFqdn.value, rollback.value.getNetworkCreated(), subnetIdMap.value, rollback.value, req.getMessageId()); } catch (NetworkException e) { LOGGER.debug ("Exception:", e); eresp = new CreateNetworkError( e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId()); } if (!req.isSynchronous()) { // This is asynch, so POST response back to caller BpelRestClient bpelClient = new BpelRestClient(); bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); } LOGGER.debug ("CreateNetworkTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); } } @DELETE @Path("{aaiNetworkId}") @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public Response deleteNetwork( @PathParam("aaiNetworkId") String aaiNetworkId, DeleteNetworkRequest req) { LOGGER.debug("deleteNetwork enter: " + req.toJsonString()); if (aaiNetworkId == null || !aaiNetworkId.equals(req.getNetworkId())) { return Response .status(HttpStatus.SC_BAD_REQUEST) .type(MediaType.TEXT_PLAIN) .entity("A&AI NetworkId in URL ("+aaiNetworkId+") does not match content ("+req.getNetworkId()+")") .build(); } DeleteNetworkTask task = new DeleteNetworkTask(req); if (req.isSynchronous()) { // This is a synchronous request task.run(); return Response .status(task.getStatusCode()) .entity(task.getGenericEntityResponse()) .build(); } else { // This is an asynchronous request try { Thread t1 = new Thread(task); t1.start(); } catch (Exception e) { // problem handling create, send generic failure as sync resp to caller LOGGER.error (MessageEnum.RA_DELETE_NETWORK_EXC, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception while delete network", e); return Response.serverError().build(); } // send sync response (ACK) to caller LOGGER.debug ("deleteNetwork exit"); return Response.status(HttpStatus.SC_ACCEPTED).build(); } } public class DeleteNetworkTask implements Runnable { private final DeleteNetworkRequest req; private DeleteNetworkResponse response = null; private DeleteNetworkError eresp = null; private boolean sendxml; public DeleteNetworkTask(DeleteNetworkRequest req) { this.req = req; this.sendxml = true; // can be set with a field or header later } public int getStatusCode() { return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; } public Object getGenericEntityResponse() { return (response != null) ? new GenericEntity(response) {} : new GenericEntity(eresp) {}; } private String getResponse() { if (response != null) { return sendxml ? response.toXmlString() : response.toJsonString(); } else { return sendxml ? eresp.toXmlString() : eresp.toJsonString(); } } @Override public void run() { LOGGER.debug("DeleteNetworkTask start"); try { Holder networkDeleted = new Holder<>(); if (req.getCloudSiteId().equals(TESTING_KEYWORD)) { networkDeleted.value = true; } else { adapter.deleteNetwork( req.getCloudSiteId(), req.getTenantId(), req.getNetworkType(), req.getModelCustomizationUuid(), req.getNetworkStackId(), req.getMsoRequest(), networkDeleted); } response = new DeleteNetworkResponse(req.getNetworkId(), networkDeleted.value, req.getMessageId()); } catch (NetworkException e) { LOGGER.debug ("Exception:", e); eresp = new DeleteNetworkError(e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId()); } if (!req.isSynchronous()) { // This is asynch, so POST response back to caller BpelRestClient bpelClient = new BpelRestClient(); bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); } LOGGER.debug("DeleteNetworkTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); } } @GET @Path("{aaiNetworkId}") @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public Response queryNetwork( @QueryParam("cloudSiteId") String cloudSiteId, @QueryParam("tenantId") String tenantId, @QueryParam("networkStackId") String networkStackId, @QueryParam("skipAAI") String skipAAI, @QueryParam("msoRequest.requestId") String requestId, @QueryParam("msoRequest.serviceInstanceId") String serviceInstanceId, @PathParam("aaiNetworkId") String aaiNetworkId) { //This request responds synchronously only LOGGER.debug ("Query network enter:" + aaiNetworkId); MsoRequest msoRequest = new MsoRequest(requestId, serviceInstanceId); try { int respStatus = HttpStatus.SC_OK; QueryNetworkResponse resp = new QueryNetworkResponse(networkStackId, null, networkStackId, null, null); Holder networkExists = new Holder<>(); Holder networkId = new Holder<>(); Holder neutronNetworkId = new Holder<>(); Holder status = new Holder<>(); Holder> routeTargets = new Holder<>(); Holder> subnetIdMap = new Holder<>(); adapter.queryNetworkContrail(cloudSiteId, tenantId, aaiNetworkId, msoRequest, networkExists, networkId, neutronNetworkId, status, routeTargets, subnetIdMap); if (!networkExists.value) { LOGGER.debug ("network not found"); respStatus = HttpStatus.SC_NOT_FOUND; } else { LOGGER.debug ("network found" + networkId.value + ", status=" + status.value); resp.setNetworkExists(networkExists.value); resp.setNetworkId(networkId.value); resp.setNeutronNetworkId(neutronNetworkId.value); resp.setNetworkStatus(status.value); resp.setRouteTargets(routeTargets.value); resp.setSubnetIdMap(subnetIdMap.value); } LOGGER.debug ("Query network exit"); return Response .status(respStatus) .entity(new GenericEntity(resp) {}) .build(); } catch (NetworkException e) { LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, aaiNetworkId, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception when query VNF", e); QueryNetworkError err = new QueryNetworkError(); err.setMessage(e.getMessage()); err.setCategory(MsoExceptionCategory.INTERNAL); return Response .status(HttpStatus.SC_INTERNAL_SERVER_ERROR) .entity(new GenericEntity(err) {}) .build(); } } @DELETE @Path("{aaiNetworkId}/rollback") @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public Response rollbackNetwork( RollbackNetworkRequest req) { LOGGER.debug("rollbackNetwork enter: " + req.toJsonString()); RollbackNetworkTask task = new RollbackNetworkTask(req); if (req.isSynchronous()) { // This is a synchronous request task.run(); return Response .status(task.getStatusCode()) .entity(task.getGenericEntityResponse()) .build(); } else { // This is an asynchronous request try { Thread t1 = new Thread(task); t1.start(); } catch (Exception e) { // problem handling create, send generic failure as sync resp to caller LOGGER.error (MessageEnum.RA_ROLLBACK_NULL, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception in rollbackNetwork", e); return Response.serverError().build(); } // send sync response (ACK) to caller LOGGER.debug("rollbackNetwork exit"); return Response.status(HttpStatus.SC_ACCEPTED).build(); } } public class RollbackNetworkTask implements Runnable { private final RollbackNetworkRequest req; private RollbackNetworkResponse response = null; private RollbackNetworkError eresp = null; private boolean sendxml; public RollbackNetworkTask(RollbackNetworkRequest req) { this.req = req; this.sendxml = true; // can be set with a field or header later } public int getStatusCode() { return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; } public Object getGenericEntityResponse() { return (response != null) ? new GenericEntity(response) {} : new GenericEntity(eresp) {}; } private String getResponse() { if (response != null) { return sendxml ? response.toXmlString() : response.toJsonString(); } else { return sendxml ? eresp.toXmlString() : eresp.toJsonString(); } } @Override public void run() { LOGGER.debug("RollbackNetworkTask start"); try { NetworkRollback nwr = req.getNetworkRollback(); adapter.rollbackNetwork(nwr); response = new RollbackNetworkResponse(true, req.getMessageId()); } catch (NetworkException e) { LOGGER.debug ("Exception:", e); eresp = new RollbackNetworkError(e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId()); } if (!req.isSynchronous()) { // This is asynch, so POST response back to caller BpelRestClient bpelClient = new BpelRestClient(); bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); } LOGGER.debug("RollbackNetworkTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); } } @PUT @Path("{aaiNetworkId}") @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) public Response updateNetwork( @PathParam("aaiNetworkId") String aaiNetworkId, UpdateNetworkRequest req) { LOGGER.debug("updateNetwork enter: " + req.toJsonString()); if (aaiNetworkId == null || !aaiNetworkId.equals(req.getNetworkId())) { return Response .status(HttpStatus.SC_BAD_REQUEST) .type(MediaType.TEXT_PLAIN) .entity("A&AI NetworkId in URL ("+aaiNetworkId+") does not match content ("+req.getNetworkId()+")") .build(); } UpdateNetworkTask task = new UpdateNetworkTask(req); if (req.isSynchronous()) { // This is a synchronous request task.run(); return Response .status(task.getStatusCode()) .entity(task.getGenericEntityResponse()) .build(); } else { // This is an asynchronous request try { Thread t1 = new Thread(task); t1.start(); } catch (Exception e) { // problem handling create, send generic failure as sync resp to caller LOGGER.error (MessageEnum.RA_UPDATE_NETWORK_ERR, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception in updateNetwork", e); return Response.serverError().build(); } // send sync response (ACK) to caller LOGGER.debug ("updateNetwork exit"); return Response.status(HttpStatus.SC_ACCEPTED).build(); } } public class UpdateNetworkTask implements Runnable { private final UpdateNetworkRequest req; private UpdateNetworkResponse response = null; private UpdateNetworkError eresp = null; private boolean sendxml; public UpdateNetworkTask(UpdateNetworkRequest req) { this.req = req; this.sendxml = true; // can be set with a field or header later } public int getStatusCode() { return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST; } public Object getGenericEntityResponse() { return (response != null) ? new GenericEntity(response) {} : new GenericEntity(eresp) {}; } private String getResponse() { if (response != null) { return sendxml ? response.toXmlString() : response.toJsonString(); } else { return sendxml ? eresp.toXmlString() : eresp.toJsonString(); } } @Override public void run() { LOGGER.debug("UpdateNetworkTask start"); try { Holder> subnetIdMap = new Holder<>(); Holder rollback = new Holder<> (); if (req.getCloudSiteId().equals(TESTING_KEYWORD)) { subnetIdMap.value = testMap(); NetworkRollback rb = new NetworkRollback (); rb.setCloudId(req.getCloudSiteId()); rb.setTenantId(req.getTenantId()); rb.setMsoRequest(req.getMsoRequest()); rollback.value = rb; } else if (req.isContrailRequest()) { ContrailNetwork ctn = req.getContrailNetwork(); if (ctn == null) { ctn = new ContrailNetwork(); req.setContrailNetwork(ctn); } adapter.updateNetworkContrail( req.getCloudSiteId(), req.getTenantId(), req.getNetworkType(), req.getModelCustomizationUuid(), req.getNetworkStackId(), req.getNetworkName(), req.getContrailNetwork().getRouteTargets(), req.getContrailNetwork().getShared(), req.getContrailNetwork().getExternal(), req.getSubnets(), req.getContrailNetwork().getPolicyFqdns(), req.getContrailNetwork().getRouteTableFqdns(), req.getMsoRequest(), subnetIdMap, rollback); } else { ProviderVlanNetwork pvn = req.getProviderVlanNetwork(); if (pvn == null) { pvn = new ProviderVlanNetwork(); req.setProviderVlanNetwork(pvn); } adapter.updateNetwork( req.getCloudSiteId(), req.getTenantId(), req.getNetworkType(), req.getModelCustomizationUuid(), req.getNetworkStackId(), req.getNetworkName(), req.getProviderVlanNetwork().getPhysicalNetworkName(), req.getProviderVlanNetwork().getVlans(), req.getSubnets(), req.getMsoRequest(), subnetIdMap, rollback); } response = new UpdateNetworkResponse( req.getNetworkId(), null, // NeutronNetworkId is not available from an update subnetIdMap.value, req.getMessageId()); } catch (NetworkException e) { LOGGER.debug ("Exception:", e); eresp = new UpdateNetworkError(e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId()); } if (!req.isSynchronous()) { // This is asynch, so POST response back to caller BpelRestClient bpelClient = new BpelRestClient(); bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml); } LOGGER.debug("UpdateNetworkTask exit: code=" + getStatusCode() + ", resp="+ getResponse()); } } public static Map testMap() { Map m = new HashMap<>(); m.put("mickey", "7"); m.put("clyde", "10"); m.put("wayne", "99"); return m; } }