Adding Junit
[so.git] / adapters / mso-network-adapter / src / main / java / org / openecomp / mso / adapters / network / MsoNetworkAdapterImpl.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * Copyright (C) 2017 Huawei Technologies Co., Ltd. All rights reserved.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.openecomp.mso.adapters.network;
23
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28
29 import java.util.Optional;
30 import javax.jws.WebService;
31 import javax.xml.ws.Holder;
32
33 import org.codehaus.jackson.JsonNode;
34 import org.codehaus.jackson.map.ObjectMapper;
35
36 import org.openecomp.mso.adapters.network.exceptions.NetworkException;
37 import org.openecomp.mso.cloud.CloudConfig;
38 import org.openecomp.mso.cloud.CloudConfigFactory;
39 import org.openecomp.mso.cloud.CloudSite;
40 import org.openecomp.mso.db.catalog.CatalogDatabase;
41 import org.openecomp.mso.db.catalog.beans.HeatTemplate;
42 import org.openecomp.mso.db.catalog.beans.NetworkResource;
43 import org.openecomp.mso.db.catalog.utils.MavenLikeVersioning;
44 import org.openecomp.mso.entity.MsoRequest;
45 import org.openecomp.mso.logger.MessageEnum;
46 import org.openecomp.mso.logger.MsoAlarmLogger;
47 import org.openecomp.mso.logger.MsoLogger;
48 import org.openecomp.mso.openstack.beans.HeatStatus;
49 import org.openecomp.mso.openstack.beans.NetworkInfo;
50 import org.openecomp.mso.openstack.beans.NetworkRollback;
51 import org.openecomp.mso.openstack.beans.NetworkStatus;
52 import org.openecomp.mso.openstack.beans.Pool;
53 import org.openecomp.mso.openstack.beans.StackInfo;
54 import org.openecomp.mso.openstack.beans.Subnet;
55 import org.openecomp.mso.openstack.exceptions.MsoAdapterException;
56 import org.openecomp.mso.openstack.exceptions.MsoException;
57 import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory;
58 import org.openecomp.mso.openstack.utils.MsoHeatUtils;
59 import org.openecomp.mso.openstack.utils.MsoHeatUtilsWithUpdate;
60 import org.openecomp.mso.openstack.utils.MsoNeutronUtils;
61 import org.openecomp.mso.openstack.utils.MsoNeutronUtils.NetworkType;
62 import org.openecomp.mso.properties.MsoPropertiesException;
63 import org.openecomp.mso.properties.MsoPropertiesFactory;
64
65 import static org.openecomp.mso.openstack.utils.MsoCommonUtils.isNullOrEmpty;
66
67 @WebService(serviceName = "NetworkAdapter", endpointInterface = "org.openecomp.mso.adapters.network.MsoNetworkAdapter", targetNamespace = "http://org.openecomp.mso/network")
68 public class MsoNetworkAdapterImpl implements MsoNetworkAdapter {
69
70         MsoPropertiesFactory msoPropertiesFactory=new MsoPropertiesFactory();
71
72         CloudConfigFactory cloudConfigFactory=new CloudConfigFactory();
73
74         private static final String AIC3_NW_PROPERTY= "org.openecomp.mso.adapters.network.aic3nw";
75         private static final String AIC3_NW="OS::ContrailV2::VirtualNetwork";
76         public static final String MSO_PROP_NETWORK_ADAPTER="MSO_PROP_NETWORK_ADAPTER";
77     private static final String VLANS = "vlans";
78     private static final String PHYSICAL_NETWORK = "physical_network";
79     private static final String UPDATE_NETWORK_CONTEXT = "UpdateNetwork";
80     private static final String NETWORK_ID = "network_id";
81     private static final String NETWORK_FQDN = "network_fqdn";
82     private static final String CREATE_NETWORK_CONTEXT = "CreateNetwork";
83     private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError";
84     private static final String NEUTRON_MODE = "NEUTRON";
85     private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA);
86     private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger ();
87     protected CloudConfig cloudConfig;
88
89     /**
90      * Health Check web method. Does nothing but return to show the adapter is deployed.
91      */
92     @Override
93     public void healthCheck () {
94         LOGGER.debug ("Health check call in Network Adapter");
95     }
96
97     /**
98      * Do not use this constructor or the msoPropertiesFactory will be NULL.
99      *
100          * @see MsoNetworkAdapterImpl#MsoNetworkAdapterImpl(MsoPropertiesFactory)
101      */
102     public MsoNetworkAdapterImpl() {
103     }
104
105     /**
106      * This constructor MUST be used if this class if called with the new operator.
107      * @param msoPropFactory
108
109      */
110     public MsoNetworkAdapterImpl(MsoPropertiesFactory msoPropFactory,CloudConfigFactory cloudConfigFact) {
111         this.msoPropertiesFactory = msoPropFactory;
112         this.cloudConfigFactory=cloudConfigFact;
113         cloudConfig = cloudConfigFactory.getCloudConfig ();
114     }
115
116     @Override
117     public void createNetwork (String cloudSiteId,
118                                String tenantId,
119                                String networkType,
120                                String modelCustomizationUuid,
121                                String networkName,
122                                String physicalNetworkName,
123                                List <Integer> vlans,
124                                Boolean failIfExists,
125                                Boolean backout,
126                                List <Subnet> subnets,
127                                MsoRequest msoRequest,
128                                Holder <String> networkId,
129                                Holder <String> neutronNetworkId,
130                                Holder <Map <String, String>> subnetIdMap,
131                                Holder <NetworkRollback> rollback) throws NetworkException {
132         Holder <String> networkFqdn = new Holder <> ();
133         createNetwork (cloudSiteId,
134                        tenantId,
135                        networkType,
136                        modelCustomizationUuid,
137                        networkName,
138                        physicalNetworkName,
139                        vlans,
140                        null,
141                        null,
142                        null,
143                        failIfExists,
144                        backout,
145                        subnets,
146                        null,
147                        null,
148                        msoRequest,
149                        networkId,
150                        neutronNetworkId,
151                        networkFqdn,
152                        subnetIdMap,
153                        rollback);
154     }
155
156     @Override
157     public void createNetworkContrail (String cloudSiteId,
158                                        String tenantId,
159                                        String networkType,
160                                        String modelCustomizationUuid,
161                                        String networkName,
162                                        List <String> routeTargets,
163                                        String shared,
164                                        String external,
165                                        Boolean failIfExists,
166                                        Boolean backout,
167                                        List <Subnet> subnets,
168                                        List <String> policyFqdns,
169                                        List<String> routeTableFqdns,
170                                        MsoRequest msoRequest,
171                                        Holder <String> networkId,
172                                        Holder <String> neutronNetworkId,
173                                        Holder <String> networkFqdn,
174                                        Holder <Map <String, String>> subnetIdMap,
175                                        Holder <NetworkRollback> rollback) throws NetworkException {
176         createNetwork (cloudSiteId,
177                        tenantId,
178                        networkType,
179                        modelCustomizationUuid,
180                        networkName,
181                        null,
182                        null,
183                        routeTargets,
184                        shared,
185                        external,
186                        failIfExists,
187                        backout,
188                        subnets,
189                        policyFqdns,
190                        routeTableFqdns,
191                        msoRequest,
192                        networkId,
193                        neutronNetworkId,
194                        networkFqdn,
195                        subnetIdMap,
196                        rollback);
197     }
198
199     /**
200      * This is the "Create Network" web service implementation.
201      * It will create a new Network of the requested type in the specified cloud
202      * and tenant. The tenant must exist at the time this service is called.
203      *
204      * If a network with the same name already exists, this can be considered a
205      * success or failure, depending on the value of the 'failIfExists' parameter.
206      *
207      * There will be a pre-defined set of network types defined in the MSO Catalog.
208      * All such networks will have a similar configuration, based on the allowable
209      * Openstack networking definitions. This includes basic networks, provider
210      * networks (with a single VLAN), and multi-provider networks (one or more VLANs)
211      *
212      * Initially, all provider networks must be "vlan" type, and multiple segments in
213      * a multi-provider network must be multiple VLANs on the same physical network.
214      *
215      * This service supports two modes of Network creation/update:
216      * - via Heat Templates
217      * - via Neutron API
218      * The network orchestration mode for each network type is declared in its
219      * catalog definition. All Heat-based templates must support some subset of
220      * the same input parameters: network_name, physical_network, vlan(s).
221      *
222      * The method returns the network ID and a NetworkRollback object. This latter
223      * object can be passed as-is to the rollbackNetwork operation to undo everything
224      * that was created. This is useful if a network is successfully created but
225      * the orchestration fails on a subsequent operation.
226      */
227
228     private void createNetwork (String cloudSiteId,
229                                String tenantId,
230                                String networkType,
231                                String modelCustomizationUuid,
232                                String networkName,
233                                String physicalNetworkName,
234                                List <Integer> vlans,
235                                List <String> routeTargets,
236                                String shared,
237                                String external,
238                                Boolean failIfExists,
239                                Boolean backout,
240                                List <Subnet> subnets,
241                                List <String> policyFqdns,
242                                List <String> routeTableFqdns,
243                                MsoRequest msoRequest,
244                                Holder <String> networkId,
245                                Holder <String> neutronNetworkId,
246                                Holder <String> networkFqdn,
247                                Holder <Map <String, String>> subnetIdMap,
248                                Holder <NetworkRollback> rollback) throws NetworkException {
249         MsoLogger.setLogContext (msoRequest);
250         MsoLogger.setServiceName ("CreateNetwork");
251
252         LOGGER.debug ("*** CREATE Network: " + networkName
253                       + " of type "
254                       + networkType
255                       + " in "
256                       + cloudSiteId
257                       + "/"
258                       + tenantId);
259
260         // Will capture execution time for metrics
261         long startTime = System.currentTimeMillis ();
262
263         // Build a default rollback object (no actions performed)
264         NetworkRollback networkRollback = new NetworkRollback ();
265         networkRollback.setCloudId (cloudSiteId);
266         networkRollback.setTenantId (tenantId);
267         networkRollback.setMsoRequest (msoRequest);
268         networkRollback.setModelCustomizationUuid(modelCustomizationUuid);
269
270         // tenant query is not required here.
271         // If the tenant doesn’t exist, the Heat calls will fail anyway (when the HeatUtils try to obtain a token).
272         // So this is just catching that error in a bit more obvious way up front.
273
274         cloudConfig = cloudConfigFactory.getCloudConfig ();
275         Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite(cloudSiteId);
276         if (!cloudSiteOpt.isPresent())
277         {
278                 String error = "Configuration Error. Stack " + networkName + " in "
279                                 + cloudSiteId
280                                 + "/"
281                                 + tenantId
282                                 + ": "
283                                 + " CloudSite does not exist in MSO Configuration";
284                 LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "", "", MsoLogger.ErrorCode.DataError, "Configuration Error");
285             LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
286                 // Set the detailed error as the Exception 'message'
287                 throw new NetworkException (error, MsoExceptionCategory.USERDATA);
288         }
289
290         // Get a handle to the Catalog Database
291
292         // Make sure DB connection is always closed
293         try (CatalogDatabase db = getCatalogDB()) {
294             NetworkResource networkResource = networkCheck(db,
295                 startTime,
296                 networkType,
297                 modelCustomizationUuid,
298                 networkName,
299                 physicalNetworkName,
300                 vlans,
301                 routeTargets,
302                 cloudSiteOpt.get());
303             String mode = networkResource.getOrchestrationMode();
304             NetworkType neutronNetworkType = NetworkType.valueOf(networkResource.getNeutronNetworkType());
305
306             if (NEUTRON_MODE.equals(mode)) {
307
308                 // Use an MsoNeutronUtils for all neutron commands
309                 MsoNeutronUtils neutron = new MsoNeutronUtils(MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory);
310
311                 // See if the Network already exists (by name)
312                 NetworkInfo netInfo = null;
313                 long queryNetworkStarttime = System.currentTimeMillis();
314                 try {
315                     netInfo = neutron.queryNetwork(networkName, tenantId, cloudSiteId);
316                     LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
317                         MsoLogger.ResponseCode.Suc, "Response successfully received from OpenStack", "OpenStack",
318                         "QueryNetwork", null);
319                 } catch (MsoException me) {
320                     LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.ERROR,
321                         MsoLogger.ResponseCode.CommunicationError, "Exception while querying network from OpenStack",
322                         "OpenStack", "QueryNetwork", null);
323                     LOGGER.error(MessageEnum.RA_QUERY_NETWORK_EXC, networkName, cloudSiteId, tenantId, "OpenStack", "",
324                         MsoLogger.ErrorCode.BusinessProcesssError, "Exception while querying network from OpenStack",
325                         me);
326                     me.addContext(CREATE_NETWORK_CONTEXT);
327                     LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
328                         MsoLogger.ResponseCode.CommunicationError, "Exception while querying network from OpenStack");
329                     throw new NetworkException(me);
330                 }
331
332                 if (netInfo != null) {
333                     // Exists. If that's OK, return success with the network ID.
334                     // Otherwise, return an exception.
335                     if (failIfExists != null && failIfExists) {
336                         String error = "Create Nework: Network " + networkName
337                             + " already exists in "
338                             + cloudSiteId
339                             + "/"
340                             + tenantId
341                             + " with ID " + netInfo.getId();
342                         LOGGER.error(MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId,
343                             "OpenStack", "", MsoLogger.ErrorCode.DataError, "Network already exists");
344                         LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict,
345                             error);
346                         throw new NetworkException(error, MsoExceptionCategory.USERDATA);
347                     } else {
348                         // Populate the outputs from the existing network.
349                         networkId.value = netInfo.getId();
350                         neutronNetworkId.value = netInfo.getId();
351                         rollback.value = networkRollback; // Default rollback - no updates performed
352                         String msg = "Found Existing network, status=" + netInfo.getStatus() + " for Neutron mode";
353                         LOGGER.warn(MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId, "", "",
354                             MsoLogger.ErrorCode.DataError, "Found Existing network, status=" + netInfo.getStatus());
355                         LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc,
356                             msg);
357                     }
358                     return;
359                 }
360
361                 long createNetworkStarttime = System.currentTimeMillis();
362                 try {
363                     netInfo = neutron.createNetwork(cloudSiteId,
364                         tenantId,
365                         neutronNetworkType,
366                         networkName,
367                         physicalNetworkName,
368                         vlans);
369                     LOGGER.recordMetricEvent(createNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
370                         MsoLogger.ResponseCode.Suc, "Response successfully received from OpenStack", "OpenStack",
371                         "CreateNetwork", null);
372                 } catch (MsoException me) {
373                     me.addContext(CREATE_NETWORK_CONTEXT);
374                     LOGGER.recordMetricEvent(createNetworkStarttime, MsoLogger.StatusCode.ERROR,
375                         MsoLogger.ResponseCode.CommunicationError, "Exception while communicate with OpenStack",
376                         "OpenStack", "CreateNetwork", null);
377                     String error = "Create Network: type " + neutronNetworkType
378                         + " in "
379                         + cloudSiteId
380                         + "/"
381                         + tenantId
382                         + ": "
383                         + me;
384                     LOGGER.error(MessageEnum.RA_CREATE_NETWORK_EXC, networkName, cloudSiteId, tenantId, "OpenStack", "",
385                         MsoLogger.ErrorCode.DataError, "Exception while communicate with OpenStack", me);
386                     LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
387                         MsoLogger.ResponseCode.CommunicationError, error);
388
389                     throw new NetworkException(me);
390                 }
391
392                 // Note: ignoring MsoNetworkAlreadyExists because we already checked.
393
394                 // If reach this point, network creation is successful.
395                 // Since directly created via Neutron, networkId tracked by MSO is the same
396                 // as the neutron network ID.
397                 networkId.value = netInfo.getId();
398                 neutronNetworkId.value = netInfo.getId();
399
400                 networkRollback.setNetworkCreated(true);
401                 networkRollback.setNetworkId(netInfo.getId());
402                 networkRollback.setNeutronNetworkId(netInfo.getId());
403                 networkRollback.setNetworkType(networkType);
404
405                 LOGGER.debug("Network " + networkName + " created, id = " + netInfo.getId());
406             } else if ("HEAT".equals(mode)) {
407
408                 // Use an MsoHeatUtils for all Heat commands
409                 MsoHeatUtils heat = new MsoHeatUtils(MSO_PROP_NETWORK_ADAPTER, msoPropertiesFactory,
410                     cloudConfigFactory);
411
412                 //HeatTemplate heatTemplate = db.getHeatTemplate (networkResource.getTemplateId ());
413                 HeatTemplate heatTemplate = db
414                     .getHeatTemplateByArtifactUuidRegularQuery(networkResource.getHeatTemplateArtifactUUID());
415                 if (heatTemplate == null) {
416                     String error = "Network error - undefined Heat Template. Network Type = " + networkType;
417                     LOGGER.error(MessageEnum.RA_PARAM_NOT_FOUND, "Heat Template", "Network Type", networkType,
418                         "Openstack", "", MsoLogger.ErrorCode.DataError,
419                         "Network error - undefined Heat Template. Network Type = " + networkType);
420                     alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); // Alarm on this
421                     // error,
422                     // configuration
423                     // must be fixed
424                     LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound,
425                         error);
426                     throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
427                 }
428
429                 LOGGER.debug("Got HEAT Template from DB: " + heatTemplate.toString());
430
431                 // "Fix" the template if it has CR/LF (getting this from Oracle)
432                 String template = heatTemplate.getHeatTemplate();
433                 template = template.replaceAll("\r\n", "\n");
434
435                 boolean aic3template = false;
436                 String aic3nw = AIC3_NW;
437                 try {
438                     aic3nw = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_NETWORK_ADAPTER)
439                         .getProperty(AIC3_NW_PROPERTY, AIC3_NW);
440                 } catch (MsoPropertiesException e) {
441                     String error = "Unable to get properties:" + MSO_PROP_NETWORK_ADAPTER;
442                     LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "", "", MsoLogger.ErrorCode.DataError,
443                         "Exception - Unable to get properties", e);
444                 }
445
446                 if (template.contains(aic3nw))
447                     aic3template = true;
448
449                 // First, look up to see if the Network already exists (by name).
450                 // For HEAT orchestration of networks, the stack name will always match the network name
451                 StackInfo heatStack = null;
452                 long queryNetworkStarttime = System.currentTimeMillis();
453                 try {
454                     heatStack = heat.queryStack(cloudSiteId, tenantId, networkName);
455                     LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
456                         MsoLogger.ResponseCode.Suc, "Response successfully received from OpenStack", "OpenStack",
457                         "QueryNetwork", null);
458                 } catch (MsoException me) {
459                     me.addContext(CREATE_NETWORK_CONTEXT);
460                     LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.ERROR,
461                         MsoLogger.ResponseCode.CommunicationError, "Exception while querying stack from OpenStack",
462                         "OpenStack", "QueryNetwork", null);
463                     String error = "Create Network (heat): query network " + networkName
464                         + " in "
465                         + cloudSiteId
466                         + "/"
467                         + tenantId
468                         + ": "
469                         + me;
470                     LOGGER.error(MessageEnum.RA_QUERY_NETWORK_EXC, networkName, cloudSiteId, tenantId, "OpenStack", "",
471                         MsoLogger.ErrorCode.DataError, "Exception while querying stack from OpenStack", me);
472                     LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
473                         MsoLogger.ResponseCode.CommunicationError, error);
474                     throw new NetworkException(me);
475                 }
476
477                 if (heatStack != null && (heatStack.getStatus() != HeatStatus.NOTFOUND)) {
478                     // Stack exists. Return success or error depending on input directive
479                     if (failIfExists != null && failIfExists) {
480                         String error = "CreateNetwork: Stack " + networkName
481                             + " already exists in "
482                             + cloudSiteId
483                             + "/"
484                             + tenantId
485                             + " as " + heatStack.getCanonicalName();
486                         LOGGER.error(MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId, "", "",
487                             MsoLogger.ErrorCode.DataError, "Network already exists");
488                         LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict,
489                             error);
490                         throw new NetworkException(error, MsoExceptionCategory.USERDATA);
491                     } else {
492                         // Populate the outputs from the existing stack.
493                         networkId.value = heatStack.getCanonicalName();
494                         neutronNetworkId.value = (String) heatStack.getOutputs().get(NETWORK_ID);
495                         rollback.value = networkRollback; // Default rollback - no updates performed
496                         if (aic3template) {
497                             networkFqdn.value = (String) heatStack.getOutputs().get(NETWORK_FQDN);
498                         }
499                         Map<String, Object> outputs = heatStack.getOutputs();
500                         Map<String, String> sMap = new HashMap<>();
501                         if (outputs != null) {
502                             for (String key : outputs.keySet()) {
503                                 if (key != null && key.startsWith("subnet")) {
504                                     if (aic3template) //one subnet_id output
505                                     {
506                                         Map<String, String> map = getSubnetUUId(key, outputs, subnets);
507                                         sMap.putAll(map);
508                                     } else //multiples subnet_%aaid% outputs
509                                     {
510                                         String subnetUUId = (String) outputs.get(key);
511                                         sMap.put(key.substring("subnet_id_".length()), subnetUUId);
512                                     }
513                                 }
514                             }
515                         }
516                         subnetIdMap.value = sMap;
517                         LOGGER.warn(MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId, "", "",
518                             MsoLogger.ErrorCode.DataError,
519                             "Found Existing network stack, status=" + heatStack.getStatus());
520                         LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Suc,
521                             "Found Existing network stack");
522                     }
523                     return;
524                 }
525
526                 // Ready to deploy the new Network
527                 // Build the common set of HEAT template parameters
528                 Map<String, Object> stackParams = populateNetworkParams(neutronNetworkType,
529                     networkName,
530                     physicalNetworkName,
531                     vlans,
532                     routeTargets,
533                     shared,
534                     external,
535                     aic3template);
536
537                 // Validate (and update) the input parameters against the DB definition
538                 // Shouldn't happen unless DB config is wrong, since all networks use same inputs
539                 // and inputs were already validated.
540                 try {
541                     stackParams = heat.validateStackParams(stackParams, heatTemplate);
542                 } catch (IllegalArgumentException e) {
543                     String error = "Create Network: Configuration Error: " + e.getMessage();
544                     LOGGER.error(MessageEnum.RA_CONFIG_EXC, e.getMessage(), "Openstack", "",
545                         MsoLogger.ErrorCode.DataError, "Exception - Create Network, Configuration Error", e);
546                     alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); // Alarm on this
547                     // error,
548                     // configuration
549                     // must be fixed
550                     LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError,
551                         error);
552                     // Input parameters were not valid
553                     throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
554                 }
555
556                 if (subnets != null) {
557                     try {
558                         if (aic3template) {
559                             template = mergeSubnetsAIC3(template, subnets, stackParams);
560                         } else {
561                             template = mergeSubnets(template, subnets);
562                         }
563                     } catch (MsoException me) {
564                         me.addContext(CREATE_NETWORK_CONTEXT);
565                         String error = "Create Network (heat): type " + neutronNetworkType
566                             + " in "
567                             + cloudSiteId
568                             + "/"
569                             + tenantId
570                             + ": "
571                             + me;
572                         LOGGER.error(MessageEnum.RA_CREATE_NETWORK_EXC, neutronNetworkType.toString(), cloudSiteId,
573                             tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError,
574                             "Exception Create Network, merging subnets", me);
575                         LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
576                             MsoLogger.ResponseCode.InternalError, error);
577                         throw new NetworkException(me);
578                     }
579                 }
580
581                 if (policyFqdns != null && !policyFqdns.isEmpty() && aic3template) {
582                     try {
583                         mergePolicyRefs(policyFqdns, stackParams);
584                     } catch (MsoException me) {
585                         me.addContext(CREATE_NETWORK_CONTEXT);
586                         String error = "Create Network (heat) mergePolicyRefs type " + neutronNetworkType
587                             + " in "
588                             + cloudSiteId
589                             + "/"
590                             + tenantId
591                             + ": "
592                             + me;
593                         LOGGER.error(MessageEnum.RA_CREATE_NETWORK_EXC, neutronNetworkType.toString(), cloudSiteId,
594                             tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError,
595                             "Exception Create Network, merging policyRefs", me);
596                         LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
597                             MsoLogger.ResponseCode.InternalError, error);
598                         throw new NetworkException(me);
599                     }
600                 }
601
602                 if (routeTableFqdns != null && !routeTableFqdns.isEmpty() && aic3template) {
603                     try {
604                         mergeRouteTableRefs(routeTableFqdns, stackParams);
605                     } catch (MsoException me) {
606                         me.addContext(CREATE_NETWORK_CONTEXT);
607                         String error = "Create Network (heat) mergeRouteTableRefs type " + neutronNetworkType
608                             + " in "
609                             + cloudSiteId
610                             + "/"
611                             + tenantId
612                             + ": "
613                             + me;
614                         LOGGER.error(MessageEnum.RA_CREATE_NETWORK_EXC, neutronNetworkType.toString(), cloudSiteId,
615                             tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError,
616                             "Exception Create Network, merging routeTableRefs", me);
617                         LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
618                             MsoLogger.ResponseCode.InternalError, error);
619                         throw new NetworkException(me);
620                     }
621                 }
622
623                 // Deploy the network stack
624                 // Ignore MsoStackAlreadyExists exception because we already checked.
625                 try {
626                     if (backout == null)
627                         backout = true;
628                     heatStack = heat.createStack(cloudSiteId,
629                         tenantId,
630                         networkName,
631                         template,
632                         stackParams,
633                         true,
634                         heatTemplate.getTimeoutMinutes(),
635                         null,
636                         null,
637                         null,
638                         backout.booleanValue());
639                 } catch (MsoException me) {
640                     me.addContext(CREATE_NETWORK_CONTEXT);
641                     String error = "Create Network (heat): type " + neutronNetworkType
642                         + " in "
643                         + cloudSiteId
644                         + "/"
645                         + tenantId
646                         + ": "
647                         + me;
648                     LOGGER.error(MessageEnum.RA_CREATE_NETWORK_EXC, networkName, cloudSiteId, tenantId, "Openstack", "",
649                         MsoLogger.ErrorCode.DataError, "Exception creating network", me);
650                     LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
651                         MsoLogger.ResponseCode.CommunicationError, error);
652                     throw new NetworkException(me);
653                 }
654
655                 // Reach this point if createStack is successful.
656
657                 // For Heat-based orchestration, the MSO-tracked network ID is the heat stack,
658                 // and the neutronNetworkId is the network UUID returned in stack outputs.
659                 networkId.value = heatStack.getCanonicalName();
660                 neutronNetworkId.value = (String) heatStack.getOutputs().get(NETWORK_ID);
661                 if (aic3template) {
662                     networkFqdn.value = (String) heatStack.getOutputs().get(NETWORK_FQDN);
663                 }
664                 Map<String, Object> outputs = heatStack.getOutputs();
665                 Map<String, String> sMap = new HashMap<>();
666                 if (outputs != null) {
667                     for (String key : outputs.keySet()) {
668                         if (key != null && key.startsWith("subnet")) {
669                             if (aic3template) //one subnet output expected
670                             {
671                                 Map<String, String> map = getSubnetUUId(key, outputs, subnets);
672                                 sMap.putAll(map);
673                             } else //multiples subnet_%aaid% outputs allowed
674                             {
675                                 String subnetUUId = (String) outputs.get(key);
676                                 sMap.put(key.substring("subnet_id_".length()), subnetUUId);
677                             }
678                         }
679                     }
680                 }
681                 subnetIdMap.value = sMap;
682
683                 rollback.value = networkRollback;
684                 // Populate remaining rollback info and response parameters.
685                 networkRollback.setNetworkStackId(heatStack.getCanonicalName());
686                 networkRollback.setNeutronNetworkId((String) heatStack.getOutputs().get(NETWORK_ID));
687                 networkRollback.setNetworkCreated(true);
688                 networkRollback.setNetworkType(networkType);
689
690                 LOGGER.debug("Network " + networkName + " successfully created via HEAT");
691             }
692         }
693         LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Suc, "Successfully created network");
694         return;
695     }
696
697     @Override
698     public void updateNetwork (String cloudSiteId,
699                                String tenantId,
700                                String networkType,
701                                String modelCustomizationUuid,
702                                String networkId,
703                                String networkName,
704                                String physicalNetworkName,
705                                List <Integer> vlans,
706                                List <Subnet> subnets,
707                                MsoRequest msoRequest,
708                                Holder <Map <String, String>> subnetIdMap,
709                                Holder <NetworkRollback> rollback) throws NetworkException {
710         updateNetwork (cloudSiteId,
711                        tenantId,
712                        networkType,
713                        modelCustomizationUuid,
714                        networkId,
715                        networkName,
716                        physicalNetworkName,
717                        vlans,
718                        null,
719                        null,
720                        null,
721                        subnets,
722                        null,
723                        null,
724                        msoRequest,
725                        subnetIdMap,
726                        rollback);
727
728     }
729
730     @Override
731     public void updateNetworkContrail (String cloudSiteId,
732                                        String tenantId,
733                                        String networkType,
734                                        String modelCustomizationUuid,
735                                        String networkId,
736                                        String networkName,
737                                        List <String> routeTargets,
738                                        String shared,
739                                        String external,
740                                        List <Subnet> subnets,
741                                        List <String> policyFqdns,
742                                        List<String> routeTableFqdns,
743                                        MsoRequest msoRequest,
744                                        Holder <Map <String, String>> subnetIdMap,
745                                        Holder <NetworkRollback> rollback) throws NetworkException {
746         updateNetwork (cloudSiteId,
747                        tenantId,
748                        networkType,
749                        modelCustomizationUuid,
750                        networkId,
751                        networkName,
752                        null,
753                        null,
754                        routeTargets,
755                        shared,
756                        external,
757                        subnets,
758                        policyFqdns,
759                        routeTableFqdns,
760                        msoRequest,
761                        subnetIdMap,
762                        rollback);
763     }
764
765     /**
766      * This is the "Update Network" web service implementation.
767      * It will update an existing Network of the requested type in the specified cloud
768      * and tenant. The typical use will be to replace the VLANs with the supplied
769      * list (to add or remove a VLAN), but other properties may be updated as well.
770      *
771      * There will be a pre-defined set of network types defined in the MSO Catalog.
772      * All such networks will have a similar configuration, based on the allowable
773      * Openstack networking definitions. This includes basic networks, provider
774      * networks (with a single VLAN), and multi-provider networks (one or more VLANs).
775      *
776      * Initially, all provider networks must currently be "vlan" type, and multi-provider
777      * networks must be multiple VLANs on the same physical network.
778      *
779      * This service supports two modes of Network update:
780      * - via Heat Templates
781      * - via Neutron API
782      * The network orchestration mode for each network type is declared in its
783      * catalog definition. All Heat-based templates must support some subset of
784      * the same input parameters: network_name, physical_network, vlan, segments.
785      *
786      * The method returns a NetworkRollback object. This object can be passed
787      * as-is to the rollbackNetwork operation to undo everything that was updated.
788      * This is useful if a network is successfully updated but orchestration
789      * fails on a subsequent operation.
790      */
791     private void updateNetwork (String cloudSiteId,
792                                String tenantId,
793                                String networkType,
794                                String modelCustomizationUuid,
795                                String networkId,
796                                String networkName,
797                                String physicalNetworkName,
798                                List <Integer> vlans,
799                                List <String> routeTargets,
800                                String shared,
801                                String external,
802                                List <Subnet> subnets,
803                                List <String> policyFqdns,
804                                List<String> routeTableFqdns,
805                                MsoRequest msoRequest,
806                                Holder <Map <String, String>> subnetIdMap,
807                                Holder <NetworkRollback> rollback) throws NetworkException {
808         MsoLogger.setLogContext (msoRequest);
809         MsoLogger.setServiceName ("UpdateNetwork");
810         LOGGER.debug ("***UPDATE Network adapter with Network: " + networkName
811                 + " of type "
812                 + networkType
813                 + " in "
814                 + cloudSiteId
815                 + "/"
816                 + tenantId);
817
818
819         // Will capture execution time for metrics
820         long startTime = System.currentTimeMillis ();
821
822         // Build a default rollback object (no actions performed)
823         NetworkRollback networkRollback = new NetworkRollback ();
824         networkRollback.setCloudId (cloudSiteId);
825         networkRollback.setTenantId (tenantId);
826         networkRollback.setMsoRequest (msoRequest);
827
828         cloudConfig = cloudConfigFactory.getCloudConfig ();
829         Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite (cloudSiteId);
830         if (!cloudSiteOpt.isPresent()) {
831                    String error = "UpdateNetwork: Configuration Error. Stack " + networkName + " in "
832                        + cloudSiteId
833                        + "/"
834                        + tenantId
835                        + ": "
836                        + " CloudSite does not exist in MSO Configuration";
837                    LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "Openstack", "", MsoLogger.ErrorCode.DataError, "CloudSite does not exist in MSO Configuration");
838                LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
839                    // Set the detailed error as the Exception 'message'
840                    throw new NetworkException (error, MsoExceptionCategory.USERDATA);
841         }
842
843         // Get a handle to the Catalog Database
844
845         // Make sure DB connection is always closed
846         try (CatalogDatabase db = getCatalogDB()) {
847             NetworkResource networkResource = networkCheck(db,
848                 startTime,
849                 networkType,
850                 modelCustomizationUuid,
851                 networkName,
852                 physicalNetworkName,
853                 vlans,
854                 routeTargets,
855                 cloudSiteOpt.get());
856             String mode = networkResource.getOrchestrationMode();
857             NetworkType neutronNetworkType = NetworkType.valueOf(networkResource.getNeutronNetworkType());
858
859             // Use an MsoNeutronUtils for all Neutron commands
860             MsoNeutronUtils neutron = new MsoNeutronUtils(MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory);
861
862             if (NEUTRON_MODE.equals(mode)) {
863
864                 // Verify that the Network exists
865                 // For Neutron-based orchestration, the networkId is the Neutron Network UUID.
866                 NetworkInfo netInfo = null;
867                 long queryNetworkStarttime = System.currentTimeMillis();
868                 try {
869                     netInfo = neutron.queryNetwork(networkId, tenantId, cloudSiteId);
870                     LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
871                         MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
872                         "QueryNetwork", null);
873                 } catch (MsoException me) {
874                     me.addContext(UPDATE_NETWORK_CONTEXT);
875                     String error = "Update Network (neutron): query " + networkId
876                         + " in "
877                         + cloudSiteId
878                         + "/"
879                         + tenantId
880                         + ": "
881                         + me;
882                     LOGGER.recordMetricEvent(queryNetworkStarttime, MsoLogger.StatusCode.ERROR,
883                         MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryNetwork", null);
884                     LOGGER.error(MessageEnum.RA_QUERY_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack",
885                         "QueryNetwork", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - queryNetwork", me);
886                     LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
887                         MsoLogger.ResponseCode.CommunicationError, error);
888                     throw new NetworkException(me);
889                 }
890
891                 if (netInfo == null) {
892                     String error = "Update Nework: Network " + networkId
893                         + " does not exist in "
894                         + cloudSiteId
895                         + "/"
896                         + tenantId;
897                     LOGGER.error(MessageEnum.RA_NETWORK_NOT_FOUND, networkId, cloudSiteId, tenantId, "OpenStack", "",
898                         MsoLogger.ErrorCode.BusinessProcesssError, "Network not found");
899                     LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest,
900                         error);
901                     // Does not exist. Throw an exception (can't update a non-existent network)
902                     throw new NetworkException(error, MsoExceptionCategory.USERDATA);
903                 }
904                 long updateNetworkStarttime = System.currentTimeMillis();
905                 try {
906                     netInfo = neutron.updateNetwork(cloudSiteId,
907                         tenantId,
908                         networkId,
909                         neutronNetworkType,
910                         physicalNetworkName,
911                         vlans);
912                     LOGGER.recordMetricEvent(updateNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
913                         MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
914                         "UpdateNetwork", null);
915                 } catch (MsoException me) {
916                     me.addContext(UPDATE_NETWORK_CONTEXT);
917                     String error = "Update Network (neutron): " + networkId
918                         + " in "
919                         + cloudSiteId
920                         + "/"
921                         + tenantId
922                         + ": "
923                         + me;
924                     LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, networkId, cloudSiteId, tenantId, "Openstack",
925                         "updateNetwork", MsoLogger.ErrorCode.DataError, "Exception - updateNetwork", me);
926                     LOGGER.recordMetricEvent(updateNetworkStarttime, MsoLogger.StatusCode.ERROR,
927                         MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateNetwork", null);
928                     LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
929                         MsoLogger.ResponseCode.CommunicationError, error);
930                     throw new NetworkException(me);
931                 }
932
933                 // Add the network ID and previously queried vlans to the rollback object
934                 networkRollback.setNetworkId(netInfo.getId());
935                 networkRollback.setNeutronNetworkId(netInfo.getId());
936                 networkRollback.setNetworkType(networkType);
937                 // Save previous parameters
938                 networkRollback.setNetworkName(netInfo.getName());
939                 networkRollback.setPhysicalNetwork(netInfo.getProvider());
940                 networkRollback.setVlans(netInfo.getVlans());
941
942                 LOGGER.debug("Network " + networkId + " updated, id = " + netInfo.getId());
943             } else if ("HEAT".equals(mode)) {
944
945                 // Use an MsoHeatUtils for all Heat commands
946                 MsoHeatUtilsWithUpdate heat = new MsoHeatUtilsWithUpdate(MSO_PROP_NETWORK_ADAPTER, msoPropertiesFactory,
947                     cloudConfigFactory);
948
949                 // First, look up to see that the Network already exists.
950                 // For Heat-based orchestration, the networkId is the network Stack ID.
951                 StackInfo heatStack = null;
952                 long queryStackStarttime = System.currentTimeMillis();
953                 try {
954                     heatStack = heat.queryStack(cloudSiteId, tenantId, networkName);
955                     LOGGER.recordMetricEvent(queryStackStarttime, MsoLogger.StatusCode.COMPLETE,
956                         MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
957                         "QueryStack", null);
958                 } catch (MsoException me) {
959                     me.addContext(UPDATE_NETWORK_CONTEXT);
960                     String error = "UpdateNetwork (heat): query " + networkName
961                         + " in "
962                         + cloudSiteId
963                         + "/"
964                         + tenantId
965                         + ": "
966                         + me;
967                     LOGGER.recordMetricEvent(queryStackStarttime, MsoLogger.StatusCode.ERROR,
968                         MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
969                     LOGGER.error(MessageEnum.RA_QUERY_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack",
970                         "queryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
971                     LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
972                         MsoLogger.ResponseCode.CommunicationError, error);
973                     throw new NetworkException(me);
974                 }
975
976                 if (heatStack == null || (heatStack.getStatus() == HeatStatus.NOTFOUND)) {
977                     String error = "UpdateNetwork: Stack " + networkName
978                         + " does not exist in "
979                         + cloudSiteId
980                         + "/"
981                         + tenantId;
982                     LOGGER.error(MessageEnum.RA_NETWORK_NOT_FOUND, networkId, cloudSiteId, tenantId, "OpenStack",
983                         "queryStack", MsoLogger.ErrorCode.DataError, "Network not found");
984                     LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest,
985                         error);
986                     // Network stack does not exist. Return an error
987                     throw new NetworkException(error, MsoExceptionCategory.USERDATA);
988                 }
989
990                 // Get the previous parameters for rollback
991                 Map<String, Object> heatParams = heatStack.getParameters();
992
993                 String previousNetworkName = (String) heatParams.get("network_name");
994                 String previousPhysicalNetwork = (String) heatParams.get(PHYSICAL_NETWORK);
995
996                 List<Integer> previousVlans = new ArrayList<>();
997                 String vlansParam = (String) heatParams.get(VLANS);
998                 if (vlansParam != null) {
999                     for (String vlan : vlansParam.split(",")) {
1000                         try {
1001                             previousVlans.add(Integer.parseInt(vlan));
1002                         } catch (NumberFormatException e) {
1003                             LOGGER.warn(MessageEnum.RA_VLAN_PARSE, networkId, vlansParam, "", "",
1004                                 MsoLogger.ErrorCode.DataError, "Exception - VLAN parse", e);
1005                         }
1006                     }
1007                 }
1008                 LOGGER.debug("Update Stack:  Previous VLANS: " + previousVlans);
1009
1010                 // Ready to deploy the updated Network via Heat
1011
1012                 //HeatTemplate heatTemplate = db.getHeatTemplate (networkResource.getTemplateId ());
1013                 HeatTemplate heatTemplate = db
1014                     .getHeatTemplateByArtifactUuidRegularQuery(networkResource.getHeatTemplateArtifactUUID());
1015                 if (heatTemplate == null) {
1016                     String error = "Network error - undefined Heat Template. Network Type=" + networkType;
1017                     LOGGER.error(MessageEnum.RA_PARAM_NOT_FOUND, "Heat Template", "Network Type", networkType,
1018                         "OpenStack", "getHeatTemplate", MsoLogger.ErrorCode.DataError,
1019                         "Network error - undefined Heat Template. Network Type=" + networkType);
1020                     alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1021                     LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest,
1022                         error);
1023                     throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
1024                 }
1025
1026                 LOGGER.debug("Got HEAT Template from DB: " + heatTemplate.toString());
1027
1028                 // "Fix" the template if it has CR/LF (getting this from Oracle)
1029                 String template = heatTemplate.getHeatTemplate();
1030                 template = template.replaceAll("\r\n", "\n");
1031
1032                 boolean aic3template = false;
1033                 String aic3nw = AIC3_NW;
1034                 try {
1035                     aic3nw = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_NETWORK_ADAPTER)
1036                         .getProperty(AIC3_NW_PROPERTY, AIC3_NW);
1037                 } catch (MsoPropertiesException e) {
1038                     String error = "Unable to get properties:" + MSO_PROP_NETWORK_ADAPTER;
1039                     LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.DataError,
1040                         "Exception - Unable to get properties", e);
1041                 }
1042                 if (template.contains(aic3nw))
1043                     aic3template = true;
1044
1045                 // Build the common set of HEAT template parameters
1046                 Map<String, Object> stackParams = populateNetworkParams(neutronNetworkType,
1047                     networkName,
1048                     physicalNetworkName,
1049                     vlans,
1050                     routeTargets,
1051                     shared,
1052                     external,
1053                     aic3template);
1054
1055                 // Validate (and update) the input parameters against the DB definition
1056                 // Shouldn't happen unless DB config is wrong, since all networks use same inputs
1057                 try {
1058                     stackParams = heat.validateStackParams(stackParams, heatTemplate);
1059                 } catch (IllegalArgumentException e) {
1060                     String error = "UpdateNetwork: Configuration Error: Network Type=" + networkType;
1061                     LOGGER.error(MessageEnum.RA_CONFIG_EXC, "Network Type=" + networkType, "OpenStack", "",
1062                         MsoLogger.ErrorCode.DataError, "Exception - UpdateNetwork: Configuration Error");
1063                     alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
1064                     LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.SchemaError,
1065                         error);
1066                     throw new NetworkException(error, MsoExceptionCategory.INTERNAL, e);
1067                 }
1068
1069                 if (subnets != null) {
1070                     try {
1071                         if (aic3template) {
1072                             template = mergeSubnetsAIC3(template, subnets, stackParams);
1073                         } else {
1074                             template = mergeSubnets(template, subnets);
1075                         }
1076                     } catch (MsoException me) {
1077                         me.addContext(UPDATE_NETWORK_CONTEXT);
1078                         String error = "Update Network (heat): type " + neutronNetworkType
1079                             + " in "
1080                             + cloudSiteId
1081                             + "/"
1082                             + tenantId
1083                             + ": "
1084                             + me;
1085                         LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, neutronNetworkType.toString(), cloudSiteId,
1086                             tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError,
1087                             "Exception - UpdateNetwork mergeSubnets ", me);
1088                         LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1089                             MsoLogger.ResponseCode.InternalError, error);
1090                         throw new NetworkException(me);
1091                     }
1092                 }
1093
1094                 if (policyFqdns != null && aic3template) {
1095                     try {
1096                         mergePolicyRefs(policyFqdns, stackParams);
1097                     } catch (MsoException me) {
1098                         me.addContext(UPDATE_NETWORK_CONTEXT);
1099                         String error = "UpdateNetwork (heat) mergePolicyRefs type " + neutronNetworkType
1100                             + " in "
1101                             + cloudSiteId
1102                             + "/"
1103                             + tenantId
1104                             + ": "
1105                             + me;
1106                         LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, neutronNetworkType.toString(), cloudSiteId,
1107                             tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError,
1108                             "Exception - UpdateNetwork mergePolicyRefs", me);
1109                         LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1110                             MsoLogger.ResponseCode.InternalError, error);
1111                         throw new NetworkException(me);
1112                     }
1113                 }
1114
1115                 if (routeTableFqdns != null && !routeTableFqdns.isEmpty() && aic3template) {
1116                     try {
1117                         mergeRouteTableRefs(routeTableFqdns, stackParams);
1118                     } catch (MsoException me) {
1119                         me.addContext(UPDATE_NETWORK_CONTEXT);
1120                         String error = "UpdateNetwork (heat) mergeRouteTableRefs type " + neutronNetworkType
1121                             + " in "
1122                             + cloudSiteId
1123                             + "/"
1124                             + tenantId
1125                             + ": "
1126                             + me;
1127                         LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, neutronNetworkType.toString(), cloudSiteId,
1128                             tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError,
1129                             "Exception - UpdateNetwork mergeRouteTableRefs", me);
1130                         LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1131                             MsoLogger.ResponseCode.InternalError, error);
1132                         throw new NetworkException(me);
1133                     }
1134                 }
1135
1136                 // Update the network stack
1137                 // Ignore MsoStackNotFound exception because we already checked.
1138                 long updateStackStarttime = System.currentTimeMillis();
1139                 try {
1140                     heatStack = heat.updateStack(cloudSiteId,
1141                         tenantId,
1142                         networkId,
1143                         template,
1144                         stackParams,
1145                         true,
1146                         heatTemplate.getTimeoutMinutes());
1147                     LOGGER.recordMetricEvent(updateStackStarttime, MsoLogger.StatusCode.COMPLETE,
1148                         MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
1149                         "UpdateStack", null);
1150                 } catch (MsoException me) {
1151                     me.addContext(UPDATE_NETWORK_CONTEXT);
1152                     String error = "Update Network: " + networkId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
1153                     LOGGER.recordMetricEvent(updateStackStarttime, MsoLogger.StatusCode.COMPLETE,
1154                         MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateStack", null);
1155                     LOGGER.error(MessageEnum.RA_UPDATE_NETWORK_ERR, networkId, cloudSiteId, tenantId, "OpenStack", "",
1156                         MsoLogger.ErrorCode.DataError, "Exception - update network", me);
1157                     LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1158                         MsoLogger.ResponseCode.CommunicationError, error);
1159                     throw new NetworkException(me);
1160                 }
1161
1162                 Map<String, Object> outputs = heatStack.getOutputs();
1163                 Map<String, String> sMap = new HashMap<>();
1164                 if (outputs != null) {
1165                     for (String key : outputs.keySet()) {
1166                         if (key != null && key.startsWith("subnet")) {
1167                             if (aic3template) //one subnet output expected
1168                             {
1169                                 Map<String, String> map = getSubnetUUId(key, outputs, subnets);
1170                                 sMap.putAll(map);
1171                             } else //multiples subnet_%aaid% outputs allowed
1172                             {
1173                                 String subnetUUId = (String) outputs.get(key);
1174                                 sMap.put(key.substring("subnet_id_".length()), subnetUUId);
1175                             }
1176                         }
1177                     }
1178                 }
1179                 subnetIdMap.value = sMap;
1180
1181                 // Reach this point if createStack is successful.
1182                 // Populate remaining rollback info and response parameters.
1183                 networkRollback.setNetworkStackId(heatStack.getCanonicalName());
1184                 if (null != outputs) {
1185                     networkRollback.setNeutronNetworkId((String) outputs.get(NETWORK_ID));
1186                 } else {
1187                     LOGGER.debug("outputs is NULL");
1188                 }
1189                 networkRollback.setNetworkType(networkType);
1190                 // Save previous parameters
1191                 networkRollback.setNetworkName(previousNetworkName);
1192                 networkRollback.setPhysicalNetwork(previousPhysicalNetwork);
1193                 networkRollback.setVlans(previousVlans);
1194
1195                 rollback.value = networkRollback;
1196
1197                 LOGGER.debug("Network " + networkId + " successfully updated via HEAT");
1198             }
1199         }
1200         LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully updated network");
1201         return;
1202     }
1203
1204     private NetworkResource networkCheck (CatalogDatabase db,
1205                                           long startTime,
1206                                           String networkType,
1207                                           String modelCustomizationUuid,
1208                                           String networkName,
1209                                           String physicalNetworkName,
1210                                           List <Integer> vlans,
1211                                           List <String> routeTargets,
1212                                           CloudSite cloudSite) throws NetworkException {
1213         // Retrieve the Network Resource definition
1214         NetworkResource networkResource = null;
1215                 try {
1216                         if (isNullOrEmpty(modelCustomizationUuid)) {
1217                                 networkResource = db.getNetworkResource(networkType);
1218                         } else {
1219                                 networkResource = db
1220                                                 .getNetworkResourceByModelCustUuid(modelCustomizationUuid);
1221                         }
1222                         if (networkResource == null) {
1223                                 String error = "Create/UpdateNetwork: Unable to get network resource with NetworkType:"
1224                                                 + networkType
1225                                                 + " or ModelCustomizationUUID:"
1226                                                 + modelCustomizationUuid;
1227                                 LOGGER.error(MessageEnum.RA_UNKOWN_PARAM,
1228                                                 "NetworkType/ModelCustomizationUUID", networkType + "/"
1229                                                                 + modelCustomizationUuid, "OpenStack", "",
1230                                                 MsoLogger.ErrorCode.DataError,
1231                                                 "Create/UpdateNetwork: Unknown NetworkType/ModelCustomizationUUID");
1232
1233                                 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1234                         }
1235                         LOGGER.debug("Got Network definition from Catalog: "
1236                                         + networkResource.toString());
1237
1238                         String mode = networkResource.getOrchestrationMode();
1239                         NetworkType neutronNetworkType = NetworkType
1240                                         .valueOf(networkResource.getNeutronNetworkType());
1241
1242                         // All Networks are orchestrated via HEAT or Neutron
1243                         if (!("HEAT".equals(mode) || NEUTRON_MODE.equals(mode))) {
1244                                 String error = "CreateNetwork: Configuration Error: Network Type = "
1245                                                 + networkType;
1246                                 LOGGER.error(MessageEnum.RA_NETWORK_ORCHE_MODE_NOT_SUPPORT,
1247                                                 mode, "OpenStack", "", MsoLogger.ErrorCode.DataError,
1248                                                 "CreateNetwork: Configuration Error");
1249                                 // Alarm on this error, configuration must be fixed
1250                                 alarmLogger.sendAlarm(MSO_CONFIGURATION_ERROR,
1251                                                 MsoAlarmLogger.CRITICAL, error);
1252
1253                                 throw new NetworkException(error, MsoExceptionCategory.INTERNAL);
1254                         }
1255
1256                         MavenLikeVersioning aicV = new MavenLikeVersioning();
1257                         aicV.setVersion(cloudSite.getAic_version());
1258                         if ((aicV.isMoreRecentThan(networkResource.getAicVersionMin()) || aicV
1259                                         .isTheSameVersion(networkResource.getAicVersionMin())) // aic
1260                                                                                                                                                         // >=
1261                                                                                                                                                         // min
1262                                         && (aicV.isTheSameVersion(networkResource
1263                                                         .getAicVersionMax()) || !(aicV
1264                                                         .isMoreRecentThan(networkResource
1265                                                                         .getAicVersionMax())))) // aic <= max
1266                         {
1267                                 LOGGER.debug("Network Type:" + networkType + " VersionMin:"
1268                                                 + networkResource.getAicVersionMin() + " VersionMax:"
1269                                                 + networkResource.getAicVersionMax()
1270                                                 + " supported on Cloud:" + cloudSite.getId()
1271                                                 + " with AIC_Version:" + cloudSite.getAic_version());
1272                         } else {
1273                                 String error = "Network Type:" + networkType + " Version_Min:"
1274                                                 + networkResource.getAicVersionMin() + " Version_Max:"
1275                                                 + networkResource.getAicVersionMax()
1276                                                 + " not supported on Cloud:" + cloudSite.getId()
1277                                                 + " with AIC_Version:" + cloudSite.getAic_version();
1278                                 LOGGER.error(MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "",
1279                                                 MsoLogger.ErrorCode.DataError,
1280                                                 "Network Type not supported on Cloud");
1281                                 LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1282                                                 MsoLogger.ResponseCode.DataError, error);
1283                                 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1284                         }
1285
1286                         // Validate the Network parameters.
1287                         String missing = validateNetworkParams(neutronNetworkType,
1288                                         networkName, physicalNetworkName, vlans, routeTargets);
1289                         if (!missing.isEmpty()) {
1290                                 String error = "Create Network: Missing parameters: " + missing;
1291                                 LOGGER.error(MessageEnum.RA_MISSING_PARAM, missing,
1292                                                 "OpenStack", "", MsoLogger.ErrorCode.DataError,
1293                                                 "Create Network: Missing parameters");
1294
1295                                 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1296                         }
1297                 } finally {
1298                         db.close();
1299                 }
1300         return networkResource;
1301     }
1302
1303     @Override
1304     public void queryNetwork (String cloudSiteId,
1305                               String tenantId,
1306                               String networkNameOrId,
1307                               MsoRequest msoRequest,
1308                               Holder <Boolean> networkExists,
1309                               Holder <String> networkId,
1310                               Holder <String> neutronNetworkId,
1311                               Holder <NetworkStatus> status,
1312                               Holder <List <Integer>> vlans,
1313                               Holder <Map <String, String>> subnetIdMap) throws NetworkException {
1314         queryNetworkInfo(cloudSiteId,
1315                       tenantId,
1316                       networkNameOrId,
1317                       msoRequest,
1318                       networkExists,
1319                       networkId,
1320                       neutronNetworkId,
1321                       status,
1322                       vlans,
1323                       subnetIdMap);
1324     }
1325
1326     @Override
1327     public void queryNetworkContrail (String cloudSiteId,
1328                                       String tenantId,
1329                                       String networkNameOrId,
1330                                       MsoRequest msoRequest,
1331                                       Holder <Boolean> networkExists,
1332                                       Holder <String> networkId,
1333                                       Holder <String> neutronNetworkId,
1334                                       Holder <NetworkStatus> status,
1335                                       Holder <List <String>> routeTargets,
1336                                       Holder <Map <String, String>> subnetIdMap) throws NetworkException {
1337         queryNetworkInfo(cloudSiteId,
1338                       tenantId,
1339                       networkNameOrId,
1340                       msoRequest,
1341                       networkExists,
1342                       networkId,
1343                       neutronNetworkId,
1344                       status,
1345                       null,
1346                       subnetIdMap);
1347     }
1348
1349     /**
1350      * This is the queryNetworkInfo method. It returns the existence and status of
1351      * the specified network, along with its Neutron UUID and list of VLANs.
1352      * This method attempts to find the network using both Heat and Neutron.
1353      * Heat stacks are first searched based on the provided network name/id.
1354      * If none is found, the Neutron is directly queried.
1355      */
1356     private void queryNetworkInfo(String cloudSiteId,
1357                               String tenantId,
1358                               String networkNameOrId,
1359                               MsoRequest msoRequest,
1360                               Holder <Boolean> networkExists,
1361                               Holder <String> networkId,
1362                               Holder <String> neutronNetworkId,
1363                               Holder <NetworkStatus> status,
1364                               Holder <List <Integer>> vlans,
1365                               Holder <Map <String, String>> subnetIdMap) throws NetworkException {
1366         MsoLogger.setLogContext (msoRequest);
1367         MsoLogger.setServiceName ("QueryNetwork");
1368         LOGGER.debug ("*** QUERY Network with Network: " + networkNameOrId
1369                 + " in "
1370                 + cloudSiteId
1371                 + "/"
1372                 + tenantId);
1373
1374         // Will capture execution time for metrics
1375         long startTime = System.currentTimeMillis ();
1376
1377         if (isNullOrEmpty (cloudSiteId)
1378             || isNullOrEmpty(tenantId)
1379             || isNullOrEmpty(networkNameOrId)) {
1380
1381             String error = "Missing mandatory parameter cloudSiteId, tenantId or networkId";
1382             LOGGER.error (MessageEnum.RA_MISSING_PARAM, "cloudSiteId or tenantId or networkNameOrId", "OpenStack", "", MsoLogger.ErrorCode.DataError, "Missing mandatory parameter cloudSiteId, tenantId or networkId");
1383             LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
1384             throw new NetworkException (error, MsoExceptionCategory.USERDATA);
1385         }
1386
1387         cloudConfig = cloudConfigFactory.getCloudConfig();
1388         Optional<CloudSite> cloudSiteOpt = cloudConfig.getCloudSite(cloudSiteId);
1389         if (!cloudSiteOpt.isPresent())
1390         {
1391                 String error = "Configuration Error. Stack " + networkNameOrId + " in "
1392                                 + cloudSiteId
1393                                 + "/"
1394                                 + tenantId
1395                                 + ": "
1396                                 + " CloudSite does not exist in MSO Configuration";
1397                 LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Configuration Error");
1398             LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
1399                 // Set the detailed error as the Exception 'message'
1400                 throw new NetworkException (error, MsoExceptionCategory.USERDATA);
1401         }
1402
1403         // Use MsoNeutronUtils for all NEUTRON commands
1404         MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_NETWORK_ADAPTER,msoPropertiesFactory,cloudConfigFactory);
1405         MsoNeutronUtils neutron = new MsoNeutronUtils (MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory);
1406
1407         String mode;
1408         String neutronId;
1409         // Try Heat first, since networks may be named the same as the Heat stack
1410         StackInfo heatStack = null;
1411         long queryStackStarttime = System.currentTimeMillis ();
1412         try {
1413             heatStack = heat.queryStack (cloudSiteId, tenantId, networkNameOrId);
1414             LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", null);
1415         } catch (MsoException me) {
1416                 me.addContext ("QueryNetwork");
1417             String error = "Query Network (heat): " + networkNameOrId
1418                            + " in "
1419                            + cloudSiteId
1420                            + "/"
1421                            + tenantId
1422                            + ": "
1423                            + me;
1424             LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "BPMN", "QueryStack", null);
1425             LOGGER.error (MessageEnum.RA_QUERY_NETWORK_EXC, networkNameOrId, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Exception - Query Network (heat)", me);
1426             LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1427             throw new NetworkException (me);
1428         }
1429
1430         // Populate the outputs based on the returned Stack information
1431         if (heatStack != null && heatStack.getStatus () != HeatStatus.NOTFOUND) {
1432             // Found it. Get the neutronNetworkId for further query
1433             Map <String, Object> outputs = heatStack.getOutputs ();
1434             neutronId = (String) outputs.get (NETWORK_ID);
1435             mode = "HEAT";
1436
1437             Map <String, String> sMap = new HashMap <> ();
1438             if (outputs != null) {
1439                 for (String key : outputs.keySet ()) {
1440                         if (key != null && key.startsWith ("subnet_id_")) //multiples subnet_%aaid% outputs
1441                         {
1442                                 String subnetUUId = (String) outputs.get(key);
1443                                 sMap.put (key.substring("subnet_id_".length()), subnetUUId);
1444                         }
1445                         else if (key != null && key.startsWith ("subnet")) //one subnet output expected
1446                         {
1447                                 Map <String, String> map = getSubnetUUId(key, outputs, null);
1448                                 sMap.putAll(map);
1449                         }
1450
1451                 }
1452             }
1453             subnetIdMap.value = sMap;
1454         } else {
1455             // Input ID was not a Heat stack ID. Try it directly in Neutron
1456             neutronId = networkNameOrId;
1457             mode = NEUTRON_MODE;
1458         }
1459
1460         // Query directly against the Neutron Network for the details
1461         // no RouteTargets available for ContrailV2 in neutron net-show
1462         // networkId is heatStackId
1463         long queryNetworkStarttime = System.currentTimeMillis ();
1464         try {
1465             NetworkInfo netInfo = neutron.queryNetwork (neutronId, tenantId, cloudSiteId);
1466             LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryNetwork", null);
1467             if (netInfo != null) {
1468                 // Found. Populate the output elements
1469                 networkExists.value = Boolean.TRUE;
1470                 if ("HEAT".equals (mode)) {
1471                     networkId.value = heatStack.getCanonicalName ();
1472                 } else {
1473                     networkId.value = netInfo.getId ();
1474                 }
1475                 neutronNetworkId.value = netInfo.getId ();
1476                 status.value = netInfo.getStatus ();
1477                 if (vlans != null)
1478                         vlans.value = netInfo.getVlans ();
1479
1480                 LOGGER.debug ("Network " + networkNameOrId
1481                               + " found ("
1482                               + mode
1483                               + "), ID = "
1484                               + networkId.value
1485                               + ("HEAT".equals (mode) ? ",NeutronId = " + neutronNetworkId.value : ""));
1486             } else {
1487                 // Not found. Populate the status fields, leave the rest null
1488                 networkExists.value = Boolean.FALSE;
1489                 status.value = NetworkStatus.NOTFOUND;
1490                 neutronNetworkId.value = null;
1491                 if (vlans != null)
1492                         vlans.value = new ArrayList<>();
1493
1494                 LOGGER.debug ("Network " + networkNameOrId + " not found");
1495             }
1496         } catch (MsoException me) {
1497             me.addContext ("QueryNetwork");
1498             String error = "Query Network (neutron): " + networkNameOrId
1499                            + " in "
1500                            + cloudSiteId
1501                            + "/"
1502                            + tenantId
1503                            + ": "
1504                            + me;
1505             LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryNetwork", null);
1506             LOGGER.error (MessageEnum.RA_QUERY_NETWORK_EXC, networkNameOrId, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - Query Network (neutron)", me);
1507             LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
1508             throw new NetworkException (me);
1509         }
1510         LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully queried network");
1511         return;
1512     }
1513
1514     /**
1515      * This is the "Delete Network" web service implementation.
1516      * It will delete a Network in the specified cloud and tenant.
1517      *
1518      * If the network is not found, it is treated as a success.
1519      *
1520      * This service supports two modes of Network creation/update/delete:
1521      * - via Heat Templates
1522      * - via Neutron API
1523      * The network orchestration mode for each network type is declared in its
1524      * catalog definition.
1525      *
1526      * For Heat-based orchestration, the networkId should be the stack ID.
1527      * For Neutron-based orchestration, the networkId should be the Neutron network UUID.
1528      *
1529      * The method returns nothing on success. Rollback is not possible for delete
1530      * commands, so any failure on delete will require manual fallout in the client.
1531      */
1532     @Override
1533     public void deleteNetwork (String cloudSiteId,
1534                                String tenantId,
1535                                String networkType,
1536                                String modelCustomizationUuid,
1537                                String networkId,
1538                                MsoRequest msoRequest,
1539                                Holder <Boolean> networkDeleted) throws NetworkException {
1540         MsoLogger.setLogContext (msoRequest);
1541         MsoLogger.setServiceName ("DeleteNetwork");
1542         LOGGER.debug ("*** DELETE Network adapter with Network: " + networkId
1543                                       + " in "
1544                                       + cloudSiteId
1545                                       + "/"
1546                                       + tenantId);
1547
1548         // Will capture execution time for metrics
1549         long startTime = System.currentTimeMillis ();
1550
1551         // Get a handle to the Catalog Database
1552
1553         // Make sure DB connection is always closed
1554         try (CatalogDatabase db = getCatalogDB()) {
1555             if (isNullOrEmpty(cloudSiteId)
1556                 || isNullOrEmpty(tenantId)
1557                 || isNullOrEmpty(networkId)) {
1558                 String error = "Missing mandatory parameter cloudSiteId, tenantId or networkId";
1559                 LOGGER.error(MessageEnum.RA_MISSING_PARAM, "cloudSiteId or tenantId or networkId", "Openstack", "",
1560                     MsoLogger.ErrorCode.DataError, "Missing mandatory parameter cloudSiteId, tenantId or networkId");
1561                 LOGGER
1562                     .recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
1563                 throw new NetworkException(error, MsoExceptionCategory.USERDATA);
1564             }
1565
1566             // Retrieve the Network Resource definition
1567             NetworkResource networkResource = null;
1568             if (isNullOrEmpty(modelCustomizationUuid)) {
1569                 networkResource = db.getNetworkResource(networkType);
1570             } else if (!isNullOrEmpty(networkType)) {
1571                 networkResource = db.getNetworkResourceByModelCustUuid(modelCustomizationUuid);
1572             }
1573             String mode = "";
1574             if (networkResource != null) {
1575                 LOGGER.debug("Got Network definition from Catalog: " + networkResource.toString());
1576
1577                 mode = networkResource.getOrchestrationMode();
1578             }
1579
1580             if (NEUTRON_MODE.equals(mode)) {
1581
1582                 // Use MsoNeutronUtils for all NEUTRON commands
1583                 MsoNeutronUtils neutron = new MsoNeutronUtils(MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory);
1584                 long deleteNetworkStarttime = System.currentTimeMillis();
1585                 try {
1586                     // The deleteNetwork function in MsoNeutronUtils returns success if the network
1587                     // was not found. So don't bother to query first.
1588                     boolean deleted = neutron.deleteNetwork(networkId, tenantId, cloudSiteId);
1589                     LOGGER.recordMetricEvent(deleteNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
1590                         MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
1591                         "DeleteNetwork", null);
1592                     networkDeleted.value = deleted;
1593                 } catch (MsoException me) {
1594                     me.addContext("DeleteNetwork");
1595                     String error = "Delete Network (neutron): " + networkId
1596                         + " in "
1597                         + cloudSiteId
1598                         + "/"
1599                         + tenantId
1600                         + ": "
1601                         + me;
1602                     LOGGER.recordMetricEvent(deleteNetworkStarttime, MsoLogger.StatusCode.ERROR,
1603                         MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteNetwork", null);
1604                     LOGGER.error(MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "Openstack", "",
1605                         MsoLogger.ErrorCode.DataError, "Delete Network (neutron)", me);
1606                     LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1607                         MsoLogger.ResponseCode.CommunicationError, error);
1608                     throw new NetworkException(me);
1609                 }
1610             } else { // DEFAULT to ("HEAT".equals (mode))
1611                 long deleteStackStarttime = System.currentTimeMillis();
1612                 // Use MsoHeatUtils for all HEAT commands
1613                 MsoHeatUtils heat = new MsoHeatUtils(MSO_PROP_NETWORK_ADAPTER, msoPropertiesFactory,
1614                     cloudConfigFactory);
1615
1616                 try {
1617                     // The deleteStack function in MsoHeatUtils returns NOTFOUND if the stack was not found or if the stack was deleted.
1618                     //  So query first to report back if stack WAS deleted or just NOTOFUND
1619                     StackInfo heatStack = null;
1620                     heatStack = heat.queryStack(cloudSiteId, tenantId, networkId);
1621                     if (heatStack != null && heatStack.getStatus() != HeatStatus.NOTFOUND) {
1622                         heat.deleteStack(tenantId, cloudSiteId, networkId, true);
1623                         LOGGER.recordMetricEvent(deleteStackStarttime, MsoLogger.StatusCode.COMPLETE,
1624                             MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
1625                             "DeleteStack", null);
1626                         networkDeleted.value = true;
1627                     } else {
1628                         networkDeleted.value = false;
1629                     }
1630                 } catch (MsoException me) {
1631                     me.addContext("DeleteNetwork");
1632                     String error = "Delete Network (heat): " + networkId
1633                         + " in "
1634                         + cloudSiteId
1635                         + "/"
1636                         + tenantId
1637                         + ": "
1638                         + me;
1639                     LOGGER.recordMetricEvent(deleteStackStarttime, MsoLogger.StatusCode.ERROR,
1640                         MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null);
1641                     LOGGER.error(MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "Openstack", "",
1642                         MsoLogger.ErrorCode.DataError, "Delete Network (heat)", me);
1643                     LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1644                         MsoLogger.ResponseCode.CommunicationError, error);
1645                     throw new NetworkException(me);
1646                 }
1647             }
1648         }
1649
1650         // On success, nothing is returned.
1651         LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully deleted network");
1652         return;
1653     }
1654
1655     public CatalogDatabase getCatalogDB() {
1656         return CatalogDatabase.getInstance();
1657     }
1658
1659     /**
1660      * This web service endpoint will rollback a previous Create VNF operation.
1661      * A rollback object is returned to the client in a successful creation
1662      * response. The client can pass that object as-is back to the rollbackVnf
1663      * operation to undo the creation.
1664      *
1665      * The rollback includes removing the VNF and deleting the tenant if the
1666      * tenant did not exist prior to the VNF creation.
1667      */
1668     @Override
1669     public void rollbackNetwork (NetworkRollback rollback) throws NetworkException {
1670         MsoLogger.setServiceName ("RollbackNetwork");
1671         // Will capture execution time for metrics
1672         long startTime = System.currentTimeMillis ();
1673
1674         if (rollback == null) {
1675                 LOGGER.error (MessageEnum.RA_ROLLBACK_NULL, "Openstack", "", MsoLogger.ErrorCode.DataError, "rollback is null");
1676             LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "No action to perform");
1677             return;
1678         }
1679
1680         MsoLogger.setLogContext (rollback.getMsoRequest());
1681
1682         // Get the elements of the VnfRollback object for easier access
1683         String cloudSiteId = rollback.getCloudId ();
1684         String tenantId = rollback.getTenantId ();
1685         String networkId = rollback.getNetworkStackId ();
1686         String networkType = rollback.getNetworkType ();
1687         String modelCustomizationUuid = rollback.getModelCustomizationUuid();
1688
1689         LOGGER.debug ("*** ROLLBACK Network " + networkId + " in " + cloudSiteId + "/" + tenantId);
1690
1691         // rollback may be null (e.g. if network already existed when Create was called)
1692         // Get a handle to the Catalog Database
1693
1694         // Make sure DB connection is always closed
1695         try (CatalogDatabase db = getCatalogDB()) {
1696
1697             // Retrieve the Network Resource definition
1698             NetworkResource networkResource = null;
1699             if (isNullOrEmpty(modelCustomizationUuid)) {
1700                 networkResource = db.getNetworkResource(networkType);
1701             } else {
1702                 networkResource = db.getNetworkResourceByModelCustUuid(modelCustomizationUuid);
1703             }
1704             String mode = "";
1705             if (networkResource != null) {
1706
1707                 LOGGER.debug("Got Network definition from Catalog: " + networkResource.toString());
1708
1709                 mode = networkResource.getOrchestrationMode();
1710             }
1711
1712             if (rollback.getNetworkCreated()) {
1713                 // Rolling back a newly created network, so delete it.
1714                 if (NEUTRON_MODE.equals(mode)) {
1715                     // Use MsoNeutronUtils for all NEUTRON commands
1716                     MsoNeutronUtils neutron = new MsoNeutronUtils(MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory);
1717                     long deleteNetworkStarttime = System.currentTimeMillis();
1718                     try {
1719                         // The deleteNetwork function in MsoNeutronUtils returns success if the network
1720                         // was not found. So don't bother to query first.
1721                         neutron.deleteNetwork(networkId, tenantId, cloudSiteId);
1722                         LOGGER.recordMetricEvent(deleteNetworkStarttime, MsoLogger.StatusCode.COMPLETE,
1723                             MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
1724                             "DeleteNetwork", null);
1725                     } catch (MsoException me) {
1726                         me.addContext("RollbackNetwork");
1727                         String error = "Rollback Network (neutron): " + networkId
1728                             + " in "
1729                             + cloudSiteId
1730                             + "/"
1731                             + tenantId
1732                             + ": "
1733                             + me;
1734                         LOGGER.recordMetricEvent(deleteNetworkStarttime, MsoLogger.StatusCode.ERROR,
1735                             MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteNetwork", null);
1736                         LOGGER
1737                             .error(MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack", "",
1738                                 MsoLogger.ErrorCode.BusinessProcesssError, "Exception - Rollback Network (neutron)",
1739                                 me);
1740                         LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1741                             MsoLogger.ResponseCode.CommunicationError, error);
1742                         throw new NetworkException(me);
1743                     }
1744                 } else { // DEFAULT to if ("HEAT".equals (mode))
1745                     // Use MsoHeatUtils for all HEAT commands
1746                     MsoHeatUtils heat = new MsoHeatUtils(MSO_PROP_NETWORK_ADAPTER, msoPropertiesFactory,
1747                         cloudConfigFactory);
1748                     long deleteStackStarttime = System.currentTimeMillis();
1749                     try {
1750                         // The deleteStack function in MsoHeatUtils returns success if the stack
1751                         // was not found. So don't bother to query first.
1752                         heat.deleteStack(tenantId, cloudSiteId, networkId, true);
1753                         LOGGER.recordMetricEvent(deleteStackStarttime, MsoLogger.StatusCode.COMPLETE,
1754                             MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack",
1755                             "DeleteStack", null);
1756                     } catch (MsoException me) {
1757                         me.addContext("RollbackNetwork");
1758                         String error = "Rollback Network (heat): " + networkId
1759                             + " in "
1760                             + cloudSiteId
1761                             + "/"
1762                             + tenantId
1763                             + ": "
1764                             + me;
1765                         LOGGER.recordMetricEvent(deleteStackStarttime, MsoLogger.StatusCode.ERROR,
1766                             MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null);
1767                         LOGGER
1768                             .error(MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack", "",
1769                                 MsoLogger.ErrorCode.BusinessProcesssError, "Exception - Rollback Network (heat)", me);
1770                         LOGGER.recordAuditEvent(startTime, MsoLogger.StatusCode.ERROR,
1771                             MsoLogger.ResponseCode.CommunicationError, error);
1772                         throw new NetworkException(me);
1773                     }
1774                 }
1775             }
1776         }
1777         LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully rolled back network");
1778         return;
1779     }
1780
1781     private String validateNetworkParams (NetworkType neutronNetworkType,
1782                                           String networkName,
1783                                           String physicalNetwork,
1784                                           List <Integer> vlans,
1785                                           List <String> routeTargets) {
1786         String sep = "";
1787         StringBuilder missing = new StringBuilder ();
1788         if (isNullOrEmpty(networkName)) {
1789             missing.append ("networkName");
1790             sep = ",";
1791         }
1792
1793         if (neutronNetworkType == NetworkType.PROVIDER || neutronNetworkType == NetworkType.MULTI_PROVIDER) {
1794             if (isNullOrEmpty(physicalNetwork)) {
1795                 missing.append (sep).append ("physicalNetworkName");
1796                 sep = ",";
1797             }
1798             if (vlans == null || vlans.isEmpty ()) {
1799                 missing.append (sep).append (VLANS);
1800             }
1801         }
1802
1803         return missing.toString ();
1804     }
1805
1806     private Map <String, Object> populateNetworkParams (NetworkType neutronNetworkType,
1807                                                         String networkName,
1808                                                         String physicalNetwork,
1809                                                         List <Integer> vlans,
1810                                                         List <String> routeTargets,
1811                                                         String shared,
1812                                                         String external,
1813                                                         boolean aic3template) {
1814         // Build the common set of HEAT template parameters
1815         Map <String, Object> stackParams = new HashMap <> ();
1816         stackParams.put ("network_name", networkName);
1817
1818         if (neutronNetworkType == NetworkType.PROVIDER) {
1819             // For Provider type
1820             stackParams.put (PHYSICAL_NETWORK, physicalNetwork);
1821             stackParams.put ("vlan", vlans.get (0).toString ());
1822         } else if (neutronNetworkType == NetworkType.MULTI_PROVIDER) {
1823             // For Multi-provider, PO supports a custom resource extension of ProviderNet.
1824             // It supports all ProviderNet properties except segmentation_id, and adds a
1825             // comma-separated-list of VLANs as a "segments" property.
1826             // Note that this does not match the Neutron definition of Multi-Provider network,
1827             // which contains a list of 'segments', each having physical_network, network_type,
1828             // and segmentation_id.
1829             StringBuilder buf = new StringBuilder ();
1830             String sep = "";
1831             for (Integer vlan : vlans) {
1832                 buf.append (sep).append (vlan.toString ());
1833                 sep = ",";
1834             }
1835             String csl = buf.toString ();
1836
1837             stackParams.put (PHYSICAL_NETWORK, physicalNetwork);
1838             stackParams.put (VLANS, csl);
1839         }
1840         if (routeTargets != null && !routeTargets.isEmpty()) {
1841             StringBuilder sb = new StringBuilder ();
1842             String sep = "";
1843             for (String rt : routeTargets) {
1844                 if (!isNullOrEmpty(rt))
1845                 {
1846                         if (aic3template)
1847                                 sb.append(sep).append("target:").append(rt);
1848                         else
1849                                 sb.append (sep).append (rt);
1850
1851                         sep = ",";
1852                 }
1853             }
1854             String csl = sb.toString ();
1855
1856             stackParams.put ("route_targets", csl);
1857         }
1858         if (isNullOrEmpty(shared)) {
1859             stackParams.put ("shared", "False");
1860         } else {
1861             stackParams.put ("shared", shared);
1862         }
1863         if (isNullOrEmpty(external)) {
1864             stackParams.put ("external", "False");
1865         } else {
1866             stackParams.put ("external", external);
1867         }
1868         return stackParams;
1869     }
1870
1871
1872
1873     /** policyRef_list structure in stackParams
1874     [
1875      {
1876          "network_policy_refs_data_sequence": {
1877              "network_policy_refs_data_sequence_major": "1",
1878              "network_policy_refs_data_sequence_minor": "0"
1879          }
1880      },
1881      {
1882          "network_policy_refs_data_sequence": {
1883              "network_policy_refs_data_sequence_major": "2",
1884              "network_policy_refs_data_sequence_minor": "0"
1885          }
1886      }
1887         ]
1888     **/
1889     private void mergePolicyRefs(List <String> pFqdns, Map <String, Object> stackParams) throws MsoException {
1890                 //Resource Property
1891                 List<ContrailPolicyRef> prlist =  new ArrayList <> ();
1892                 int index = 1;
1893                 for (String pf : pFqdns) {
1894                         if (!isNullOrEmpty(pf))
1895                         {
1896                                 ContrailPolicyRef pr = new ContrailPolicyRef();
1897                                 pr.populate(String.valueOf(index), "0");
1898                                 index++;
1899                                 LOGGER.debug("Contrail PolicyRefs Data:" + pr.toString());
1900                                 prlist.add(pr);
1901                         }
1902                 }
1903
1904                 JsonNode node = null;
1905                 try
1906                 {
1907                         ObjectMapper mapper = new ObjectMapper();
1908                         node = mapper.convertValue(prlist, JsonNode.class);
1909                         String jsonString = mapper.writeValueAsString(prlist);
1910                         LOGGER.debug("Json PolicyRefs Data:" + jsonString);
1911                 }
1912                 catch (Exception e)
1913                 {
1914                         String error = "Error creating JsonNode for policyRefs Data";
1915                         LOGGER.error (MessageEnum.RA_MARSHING_ERROR, error, "Openstack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception creating JsonNode for policyRefs Data", e);
1916                         throw new MsoAdapterException (error);
1917                 }
1918                 //update parameters
1919                 if (pFqdns != null && node != null)
1920                 {
1921                         StringBuilder buf = new StringBuilder ();
1922                         String sep = "";
1923                         for (String pf : pFqdns) {
1924                                 if (!isNullOrEmpty(pf))
1925                                 {
1926                                         buf.append (sep).append (pf);
1927                                         sep = ",";
1928                                 }
1929                         }
1930                         String csl = buf.toString ();
1931                         stackParams.put ("policy_refs", csl);
1932                         stackParams.put ("policy_refsdata", node);
1933                 }
1934
1935                 LOGGER.debug ("StackParams updated with policy refs");
1936                 return;
1937     }
1938
1939     private void mergeRouteTableRefs(List <String> rtFqdns, Map <String, Object> stackParams) throws MsoException {
1940
1941                 //update parameters
1942                 if (rtFqdns != null)
1943                 {
1944                         StringBuilder buf = new StringBuilder ();
1945                         String sep = "";
1946                         for (String rtf : rtFqdns) {
1947                                 if (!isNullOrEmpty(rtf))
1948                                 {
1949                                         buf.append (sep).append (rtf);
1950                                         sep = ",";
1951                                 }
1952                         }
1953                         String csl = buf.toString ();
1954                         stackParams.put ("route_table_refs", csl);
1955                 }
1956
1957                 LOGGER.debug ("StackParams updated with route_table refs");
1958                 return;
1959     }
1960
1961
1962     /*** Subnet Output structure from Juniper
1963      {
1964     "ipam_subnets": [
1965         {
1966             "subnet": {
1967                 "ip_prefix": "10.100.1.0",
1968                 "ip_prefix_len": 28
1969             },
1970             "addr_from_start": null,
1971             "enable_dhcp": false,
1972             "default_gateway": "10.100.1.1",
1973             "dns_nameservers": [],
1974             "dhcp_option_list": null,
1975             "subnet_uuid": "10391fbf-6b9c-4160-825d-2d018b7649cf",
1976             "allocation_pools": [
1977                 {
1978                     "start": "10.100.1.3",
1979                     "end": "10.100.1.5"
1980                 },
1981                 {
1982                     "start": "10.100.1.6",
1983                     "end": "10.100.1.9"
1984                 }
1985             ],
1986             "host_routes": null,
1987             "dns_server_address": "10.100.1.13",
1988             "subnet_name": "subnet_MsoNW1_692c9032-e1a2-4d64-828c-7b9a4fcc05b0"
1989         },
1990         {
1991             "subnet": {
1992                 "ip_prefix": "10.100.2.16",
1993                 "ip_prefix_len": 28
1994             },
1995             "addr_from_start": null,
1996             "enable_dhcp": true,
1997             "default_gateway": "10.100.2.17",
1998             "dns_nameservers": [],
1999             "dhcp_option_list": null,
2000             "subnet_uuid": "c7aac5ea-66fe-443a-85f9-9c38a608c0f6",
2001             "allocation_pools": [
2002                 {
2003                     "start": "10.100.2.18",
2004                     "end": "10.100.2.20"
2005                 }
2006             ],
2007             "host_routes": null,
2008             "dns_server_address": "10.100.2.29",
2009             "subnet_name": "subnet_MsoNW1_692c9032-e1a2-4d64-828c-7b9a4fcc05b1"
2010         }
2011     ],
2012     "host_routes": null
2013         }
2014     ***/
2015     private String mergeSubnetsAIC3 (String heatTemplate, List <Subnet> subnets, Map <String, Object> stackParams) throws MsoException {
2016
2017                 //Resource Property
2018                 List<ContrailSubnet> cslist =  new ArrayList <> ();
2019                 for (Subnet subnet : subnets) {
2020                         ContrailSubnet cs = new ContrailSubnet();
2021                         LOGGER.debug("Input Subnet:" + subnet.toString());
2022                         cs.populateWith(subnet);
2023                         LOGGER.debug("Contrail Subnet:" + cs.toString());
2024                         cslist.add(cs);
2025                 }
2026
2027                 JsonNode node = null;
2028                 try
2029                 {
2030                         ObjectMapper mapper = new ObjectMapper();
2031                         node = mapper.convertValue(cslist, JsonNode.class);
2032                         String jsonString = mapper.writeValueAsString(cslist);
2033                         LOGGER.debug("Json Subnet List:" + jsonString);
2034                 }
2035                 catch (Exception e)
2036                 {
2037                         String error = "Error creating JsonNode from input subnets";
2038                         LOGGER.error (MessageEnum.RA_MARSHING_ERROR, error, "", "", MsoLogger.ErrorCode.DataError, "Exception creating JsonNode from input subnets", e);
2039                         throw new MsoAdapterException (error);
2040                 }
2041                 //update parameters
2042                 if (node != null)
2043                 {
2044                         stackParams.put ("subnet_list", node);
2045                 }
2046                 //Outputs - All subnets are in one ipam_subnets structure
2047                 String outputTempl = "  subnet:\n" + "    description: Openstack subnet identifier\n"
2048                                 + "    value: { get_attr: [network, network_ipam_refs, 0, attr]}\n";
2049
2050                 // append outputs in heatTemplate
2051                 int outputsIdx = heatTemplate.indexOf ("outputs:");
2052                 heatTemplate = insertStr (heatTemplate, outputTempl, outputsIdx + 8);
2053                 LOGGER.debug ("Template updated with all AIC3.0 subnets:" + heatTemplate);
2054                 return heatTemplate;
2055     }
2056
2057
2058     private String mergeSubnets (String heatTemplate, List <Subnet> subnets) throws MsoException {
2059
2060                 String resourceTempl = "  subnet_%subnetId%:\n" + "    type: OS::Neutron::Subnet\n"
2061                                 + "    properties:\n"
2062                                 + "      name: %name%\n"
2063                                 + "      network_id: { get_resource: network }\n"
2064                                 + "      cidr: %cidr%\n";
2065
2066                 /* make these optional
2067                                + "      ip_version: %ipversion%\n"
2068                                + "      enable_dhcp: %enabledhcp%\n"
2069                                + "      gateway_ip: %gatewayip%\n"
2070                                + "      allocation_pools:\n"
2071                                + "       - start: %poolstart%\n"
2072                                + "         end: %poolend%\n";
2073
2074                  */
2075
2076                 String outputTempl = "  subnet_id_%subnetId%:\n" + "    description: Openstack subnet identifier\n"
2077                                 + "    value: {get_resource: subnet_%subnetId%}\n";
2078
2079                 StringBuilder curR;
2080                 String curO;
2081                 StringBuilder resourcesBuf = new StringBuilder ();
2082                 StringBuilder outputsBuf = new StringBuilder ();
2083                 for (Subnet subnet : subnets) {
2084
2085                         // build template for each subnet
2086                         curR = new StringBuilder(resourceTempl);
2087                         if (subnet.getSubnetId () != null) {
2088                                 curR = new StringBuilder(curR.toString().replace("%subnetId%", subnet.getSubnetId()));
2089                         } else {
2090                                 String error = "Missing Required AAI SubnetId for subnet in HEAT Template";
2091                                 LOGGER.error (MessageEnum.RA_MISSING_PARAM, error, "Openstack", "", MsoLogger.ErrorCode.DataError, "Missing Required AAI ID  for subnet in HEAT Template");
2092                                 throw new MsoAdapterException (error);
2093                         }
2094
2095                         if (subnet.getSubnetName () != null) {
2096                                 curR = new StringBuilder(curR.toString().replace("%name%", subnet.getSubnetName()));
2097                         } else {
2098                                 curR = new StringBuilder(curR.toString().replace("%name%", subnet.getSubnetId()));
2099                         }
2100
2101                         if (subnet.getCidr () != null) {
2102                                 curR = new StringBuilder(curR.toString().replace("%cidr%", subnet.getCidr()));
2103                         } else {
2104                                 String error = "Missing Required cidr for subnet in HEAT Template";
2105                                 LOGGER.error (MessageEnum.RA_MISSING_PARAM, error, "Openstack", "", MsoLogger.ErrorCode.DataError, "Missing Required cidr for subnet in HEAT Template");
2106                                 throw new MsoAdapterException (error);
2107                         }
2108
2109                         if (subnet.getIpVersion () != null) {
2110                                 curR.append("      ip_version: " + subnet.getIpVersion() + "\n");
2111                         }
2112                         if (subnet.getEnableDHCP () != null) {
2113                                 curR.append("      enable_dhcp: ").append(Boolean.toString(subnet.getEnableDHCP())).append("\n");
2114                         }
2115                         if (subnet.getGatewayIp () != null && !subnet.getGatewayIp ().isEmpty() ) {
2116                                 curR.append("      gateway_ip: " + subnet.getGatewayIp() + "\n");
2117                         }
2118
2119                         if (subnet.getAllocationPools() != null) {
2120                                 curR.append("      allocation_pools:\n");
2121                                 for (Pool pool : subnet.getAllocationPools())
2122                                 {
2123                                         if (!isNullOrEmpty(pool.getStart()) && !isNullOrEmpty(pool.getEnd()))
2124                                         {
2125                                                 curR.append("       - start: " + pool.getStart() + "\n");
2126                                                 curR.append("         end: " + pool.getEnd() + "\n");
2127                                         }
2128                                 }
2129                         }
2130
2131                         resourcesBuf.append (curR);
2132
2133                         curO = outputTempl;
2134                         curO = curO.replace ("%subnetId%", subnet.getSubnetId ());
2135
2136                         outputsBuf.append (curO);
2137
2138                 }
2139                 // append resources and outputs in heatTemplate
2140                 LOGGER.debug ("Tempate initial:" + heatTemplate);
2141                 int outputsIdx = heatTemplate.indexOf ("outputs:");
2142                 heatTemplate = insertStr (heatTemplate, outputsBuf.toString (), outputsIdx + 8);
2143                 int resourcesIdx = heatTemplate.indexOf ("resources:");
2144                 heatTemplate = insertStr (heatTemplate, resourcesBuf.toString (), resourcesIdx + 10);
2145
2146                 LOGGER.debug ("Template updated with all subnets:" + heatTemplate);
2147                 return heatTemplate;
2148     }
2149
2150     private Map <String, String> getSubnetUUId(String key,  Map <String, Object> outputs, List <Subnet> subnets) {
2151
2152         Map <String, String> sMap = new HashMap <> ();
2153
2154         try{
2155                 Object obj = outputs.get(key);
2156                 ObjectMapper mapper = new ObjectMapper();
2157                 String jStr = mapper.writeValueAsString(obj);
2158                 LOGGER.debug ("Subnet_Ipam Output JSON String:" + obj.getClass() + " " + jStr);
2159
2160                 JsonNode rootNode = mapper.readTree(jStr);
2161                 for (JsonNode sNode : rootNode.path("ipam_subnets"))
2162                 {
2163                         LOGGER.debug("Output Subnet Node" + sNode.toString());
2164                         String name = sNode.path("subnet_name").getTextValue();
2165                         String uuid = sNode.path("subnet_uuid").getTextValue();
2166                         String aaiId = name; // default
2167                         // try to find aaiId for name in input subnetList
2168                         if (subnets != null)
2169                         {
2170                                 for (Subnet subnet : subnets)
2171                                 {
2172                                         if ( subnet !=  null && !isNullOrEmpty(subnet.getSubnetName()))
2173                                         {
2174                                                 if (subnet.getSubnetName().equals(name))
2175                                                 {
2176                                                         aaiId = subnet.getSubnetId();
2177                                                         break;
2178                                                 }
2179                                         }
2180                                 }
2181                         }
2182                         sMap.put(aaiId, uuid); //bpmn needs aaid to uuid map
2183                 }
2184         }
2185         catch (Exception e)
2186         {
2187                 LOGGER.error (MessageEnum.RA_MARSHING_ERROR, "error getting subnet-uuids", "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception getting subnet-uuids", e);
2188         }
2189
2190         LOGGER.debug ("Return sMap" + sMap.toString());
2191         return sMap;
2192     }
2193
2194     private static String insertStr (String template, String snippet, int index) {
2195
2196         String updatedTemplate;
2197
2198         LOGGER.debug ("Index:" + index + " Snippet:" + snippet);
2199
2200         String templateBeg = template.substring (0, index);
2201         String templateEnd = template.substring (index);
2202
2203         updatedTemplate = templateBeg + "\n" + snippet + templateEnd;
2204
2205         LOGGER.debug ("Template updated with a subnet:" + updatedTemplate);
2206         return updatedTemplate;
2207     }
2208
2209 }