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