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