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