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