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