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