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