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