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