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