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