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