ios-xe renderer bugfix
[groupbasedpolicy.git] / renderers / ios-xe / src / main / java / org / opendaylight / groupbasedpolicy / renderer / ios_xe_provider / impl / writer / PolicyWriterUtil.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.writer;
10
11 import com.google.common.base.Optional;
12 import com.google.common.util.concurrent.CheckedFuture;
13 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
14 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
15 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
16 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
17 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
18 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
19 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.PolicyManagerUtil;
20 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.ServiceChainingUtil;
21 import org.opendaylight.yang.gen.v1.urn.ios.rev160308.ClassNameType;
22 import org.opendaylight.yang.gen.v1.urn.ios.rev160308.Native;
23 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._interface.common.grouping.ServicePolicy;
24 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._interface.common.grouping.service.policy.type.ServiceChain.Direction;
25 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ClassMap;
26 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ClassMapKey;
27 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.Interface;
28 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.PolicyMap;
29 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.PolicyMapKey;
30 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ServiceChain;
31 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native._interface.GigabitEthernet;
32 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native._interface.GigabitEthernetKey;
33 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map.Class;
34 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.policy.map.ClassKey;
35 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServiceFunctionForwarder;
36 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePath;
37 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServicePathKey;
38 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.Local;
39 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.ServiceFfName;
40 import org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.service.function.forwarder.ServiceFfNameKey;
41 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
42 import org.opendaylight.yangtools.yang.binding.DataObject;
43 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 import java.util.List;
48
49 /**
50  * Purpose: Util class for every policy writer
51  */
52 class PolicyWriterUtil {
53
54     private static final Logger LOG = LoggerFactory.getLogger(PolicyWriterUtil.class);
55
56     static boolean writeClassMaps(final List<ClassMap> classMapEntries, final NodeId nodeId, final DataBroker mountpoint) {
57         if (classMapEntries == null || classMapEntries.isEmpty()) {
58             return true;
59         }
60         for (ClassMap entry : classMapEntries) {
61             final java.util.Optional<WriteTransaction> optionalWriteTransaction =
62                     NetconfTransactionCreator.netconfWriteOnlyTransaction(mountpoint);
63             if (!optionalWriteTransaction.isPresent()) {
64                 LOG.warn("Failed to create write-only transaction, mountpoint: {}", mountpoint);
65                 return false;
66             }
67             final WriteTransaction writeTransaction = optionalWriteTransaction.get();
68             final InstanceIdentifier<ClassMap> classMapIid = classMapInstanceIdentifier(entry);
69             writeMergeTransaction(writeTransaction, classMapIid, entry);
70             // Check
71             final java.util.Optional<ReadOnlyTransaction> optionalTransaction =
72                     NetconfTransactionCreator.netconfReadOnlyTransaction(mountpoint);
73             if (!optionalTransaction.isPresent()) {
74                 LOG.warn("Failed to create read-only transaction, mountpoint: {}", mountpoint);
75                 return false;
76             }
77             final ReadOnlyTransaction readTransaction = optionalTransaction.get();
78             if (checkWritten(readTransaction, classMapIid) == null) {
79                 return false;
80             }
81             LOG.info("Created class-map {} on node {}", entry.getName(), nodeId.getValue());
82         }
83         return true;
84     }
85
86     static boolean removeClassMaps(final List<ClassMap> classMapEntries, final NodeId nodeId, final DataBroker mountpoint) {
87         boolean result = true;
88         if (classMapEntries == null || classMapEntries.isEmpty()) {
89             return true;
90         }
91         for (ClassMap entry : classMapEntries) {
92             final java.util.Optional<WriteTransaction> optionalWriteTransaction =
93                     NetconfTransactionCreator.netconfWriteOnlyTransaction(mountpoint);
94             if (!optionalWriteTransaction.isPresent()) {
95                 LOG.warn("Failed to create write-only transaction, mountpoint: {}", mountpoint);
96                 return false;
97             }
98             final WriteTransaction writeTransaction = optionalWriteTransaction.get();
99             final InstanceIdentifier<ClassMap> classMapIid = classMapInstanceIdentifier(entry);
100             deleteTransaction(writeTransaction, classMapIid);
101             // Check
102             final java.util.Optional<ReadOnlyTransaction> optionalReadTransaction =
103                     NetconfTransactionCreator.netconfReadOnlyTransaction(mountpoint);
104             if (!optionalReadTransaction.isPresent()) {
105                 LOG.warn("Failed to create read-only transaction, mountpoint: {}", mountpoint);
106                 return false;
107             }
108             final ReadOnlyTransaction readTransaction = optionalReadTransaction.get();
109             result = checkRemoved(readTransaction, classMapIid);
110             LOG.info("Class-map {} removed from node {}", entry.getName(), nodeId.getValue());
111         }
112         return result;
113     }
114
115     static boolean writePolicyMap(final String policyMapName, final List<Class> policyMapEntries, NodeId nodeId,
116                                   final DataBroker mountpoint) {
117         final java.util.Optional<WriteTransaction> optionalWriteTransaction =
118                 NetconfTransactionCreator.netconfWriteOnlyTransaction(mountpoint);
119         if (!optionalWriteTransaction.isPresent()) {
120             LOG.warn("Failed to create write-only transaction, mountpoint: {}", mountpoint);
121             return false;
122         }
123         final WriteTransaction writeTransaction = optionalWriteTransaction.get();
124         final PolicyMap policyMap = PolicyManagerUtil.createPolicyMap(policyMapName, policyMapEntries);
125         final InstanceIdentifier<PolicyMap> policyMapIid = policyMapInstanceIdentifier(policyMapName);
126         writeMergeTransaction(writeTransaction, policyMapIid, policyMap);
127         // Check
128         final java.util.Optional<ReadOnlyTransaction> optionalReadTransaction =
129                 NetconfTransactionCreator.netconfReadOnlyTransaction(mountpoint);
130         if (!optionalReadTransaction.isPresent()) {
131             LOG.warn("Failed to create read-only transaction, mountpoint: {}", mountpoint);
132             return false;
133         }
134         final ReadOnlyTransaction readTransaction = optionalReadTransaction.get();
135         if (checkWritten(readTransaction, policyMapIid) == null) {
136             return false;
137         }
138         LOG.info("Created policy-map {} on node {}", policyMap.getName(), nodeId.getValue());
139         return true;
140     }
141
142     static boolean removePolicyMapEntries(final String policyMapName, final List<Class> policyMapEntries,
143                                           final NodeId nodeId, final DataBroker mountpoint) {
144         if (policyMapEntries == null || policyMapEntries.isEmpty()) {
145             return true;
146         }
147         for (Class entry : policyMapEntries) {
148             final java.util.Optional<WriteTransaction> optionalWriteTransaction =
149                     NetconfTransactionCreator.netconfWriteOnlyTransaction(mountpoint);
150             if (!optionalWriteTransaction.isPresent()) {
151                 LOG.warn("Failed to create write-only transaction, mountpoint: {}", mountpoint);
152                 return false;
153             }
154             final WriteTransaction writeTransaction = optionalWriteTransaction.get();
155             final InstanceIdentifier policyMapEntryIid = policyMapEntryInstanceIdentifier(policyMapName, entry.getName());
156             if (deleteTransaction(writeTransaction, policyMapEntryIid)) {
157                 LOG.info("Policy map entry {} removed from node {}", entry.getName(), nodeId.getValue());
158             }
159         }
160         return true;
161     }
162
163     static boolean writeInterface(final String policyMapName, final String interfaceName, final NodeId nodeId,
164                                   final DataBroker mountpoint) {
165         final java.util.Optional<WriteTransaction> optionalWriteTransaction =
166                 NetconfTransactionCreator.netconfWriteOnlyTransaction(mountpoint);
167         if (!optionalWriteTransaction.isPresent()) {
168             LOG.warn("Failed to create write-only transaction, mountpoint: {}", mountpoint);
169             return false;
170         }
171         final WriteTransaction writeTransaction = optionalWriteTransaction.get();
172         final ServicePolicy servicePolicy = PolicyManagerUtil.createServicePolicy(policyMapName, Direction.Input);
173         final InstanceIdentifier<ServicePolicy> servicePolicyIid = interfaceInstanceIdentifier(interfaceName);
174         writeMergeTransaction(writeTransaction, servicePolicyIid, servicePolicy);
175         LOG.info("Service-policy interface {}, bound to policy-map {} created on  node {}",
176                 interfaceName, policyMapName, nodeId.getValue());
177         return true;
178     }
179
180     static boolean writeLocal(final Local localForwarder, final NodeId nodeId, final DataBroker mountpoint) {
181         if (localForwarder == null) {
182             return true;
183         }
184         final java.util.Optional<WriteTransaction> optionalWriteTransaction =
185                 NetconfTransactionCreator.netconfWriteOnlyTransaction(mountpoint);
186         if (!optionalWriteTransaction.isPresent()) {
187             LOG.warn("Failed to create write-only transaction, mountpoint: {}", mountpoint);
188             return false;
189         }
190         final WriteTransaction writeTransaction = optionalWriteTransaction.get();
191         final InstanceIdentifier<Local> localIid = localSffInstanceIdentifier();
192         writeMergeTransaction(writeTransaction, localIid, localForwarder);
193         LOG.info("Local forwarder created on node {}", nodeId.getValue());
194         return true;
195     }
196
197     static boolean removeLocal(final NodeId nodeId, final DataBroker mountpoint) {
198         // Remove local forwarder only when there are no more service-paths
199         if (ServiceChainingUtil.checkServicePathPresence(mountpoint)) {
200             final java.util.Optional<WriteTransaction> optionalWriteTransaction =
201                     NetconfTransactionCreator.netconfWriteOnlyTransaction(mountpoint);
202             if (!optionalWriteTransaction.isPresent()) {
203                 LOG.warn("Failed to create write-only transaction, mountpoint: {}", mountpoint);
204                 return false;
205             }
206             final WriteTransaction writeTransaction = optionalWriteTransaction.get();
207             final InstanceIdentifier<Local> localIid = localSffInstanceIdentifier();
208             deleteTransaction(writeTransaction, localIid);
209             LOG.info("Local forwarder removed from node {}", nodeId.getValue());
210         }
211         return true;
212     }
213
214     static boolean writeRemote(final List<ServiceFfName> remoteForwarders, final NodeId nodeId,
215                                final DataBroker mountpoint) {
216         if (remoteForwarders == null || remoteForwarders.isEmpty()) {
217             return true;
218         }
219         for (ServiceFfName forwarder : remoteForwarders) {
220             final java.util.Optional<WriteTransaction> optionalWriteTransaction =
221                     NetconfTransactionCreator.netconfWriteOnlyTransaction(mountpoint);
222             if (!optionalWriteTransaction.isPresent()) {
223                 LOG.warn("Failed to create transaction, mountpoint: {}", mountpoint);
224                 return false;
225             }
226             final WriteTransaction writeTransaction = optionalWriteTransaction.get();
227             final InstanceIdentifier<ServiceFfName> forwarderIid = remoteSffInstanceIdentifier(forwarder);
228             writeMergeTransaction(writeTransaction, forwarderIid, forwarder);
229             LOG.info("Remote forwarder {} created on node {}", forwarder.getName(), nodeId.getValue());
230         }
231         return true;
232     }
233
234     static boolean writeServicePaths(final List<ServiceChain> serviceChains, final NodeId nodeId,
235                                      final DataBroker mountpoint) {
236         for (org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ServiceChain serviceChain : serviceChains) {
237             for (ServicePath entry : serviceChain.getServicePath()) {
238                 final java.util.Optional<WriteTransaction> optionalWriteTransaction =
239                         NetconfTransactionCreator.netconfWriteOnlyTransaction(mountpoint);
240                 if (!optionalWriteTransaction.isPresent()) {
241                     LOG.warn("Failed to create write-only transaction, mountpoint: {}", mountpoint);
242                     return false;
243                 }
244                 final WriteTransaction writeTransaction = optionalWriteTransaction.get();
245                 final InstanceIdentifier<ServicePath> servicePathIid = servicePathInstanceIdentifier(entry.getKey());
246                 writeMergeTransaction(writeTransaction, servicePathIid, entry);
247                 LOG.info("Service path with ID: {} created on node {}", entry.getServicePathId(), nodeId.getValue());
248             }
249         }
250         return true;
251     }
252
253     static boolean removeServicePaths(final List<ServiceChain> serviceChains, final NodeId nodeId,
254                                       final DataBroker mountpoint) {
255         if (serviceChains == null || serviceChains.isEmpty()) {
256             return true;
257         }
258         for (ServiceChain chain : serviceChains) {
259             List<ServicePath> servicePaths = chain.getServicePath();
260             if (servicePaths == null || servicePaths.isEmpty()) {
261                 continue;
262             }
263             for (ServicePath servicePath : servicePaths) {
264                 final java.util.Optional<WriteTransaction> optionalWriteTransaction =
265                         NetconfTransactionCreator.netconfWriteOnlyTransaction(mountpoint);
266                 if (!optionalWriteTransaction.isPresent()) {
267                     LOG.warn("Failed to create write-only transaction, mountpoint: {}", mountpoint);
268                     return false;
269                 }
270                 final WriteTransaction writeTransaction = optionalWriteTransaction.get();
271                 final InstanceIdentifier<ServicePath> servicePathIid = servicePathInstanceIdentifier(servicePath.getKey());
272                 if (deleteTransaction(writeTransaction, servicePathIid)) {
273                     LOG.info("Service-path with ID: {} removed from node {}", servicePath.getServicePathId(),
274                             nodeId.getValue());
275                 }
276             }
277         }
278         return true;
279     }
280
281     private static InstanceIdentifier<ClassMap> classMapInstanceIdentifier(final ClassMap classMap) {
282         return InstanceIdentifier.builder(Native.class)
283                 .child(ClassMap.class, new ClassMapKey(classMap.getName())).build();
284     }
285
286     private static InstanceIdentifier<PolicyMap> policyMapInstanceIdentifier(final String policyMapName) {
287         return InstanceIdentifier.builder(Native.class)
288                 .child(PolicyMap.class, new PolicyMapKey(policyMapName)).build();
289     }
290
291     private static InstanceIdentifier<Class> policyMapEntryInstanceIdentifier(final String policyMapName,
292                                                                               final ClassNameType classNameType) {
293         return InstanceIdentifier.builder(Native.class)
294                 .child(PolicyMap.class, new PolicyMapKey(policyMapName))
295                 .child(Class.class, new ClassKey(classNameType)).build();
296     }
297
298     private static InstanceIdentifier<ServicePolicy> interfaceInstanceIdentifier(final String ethernetName) {
299         return InstanceIdentifier.builder(Native.class)
300                 .child(Interface.class)
301                 .child(GigabitEthernet.class, new GigabitEthernetKey(ethernetName))
302                 .child(ServicePolicy.class)
303                 .build();
304     }
305
306     private static InstanceIdentifier<Local> localSffInstanceIdentifier() {
307         return InstanceIdentifier.builder(Native.class)
308                 .child(org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ServiceChain.class)
309                 .child(ServiceFunctionForwarder.class)
310                 .child(Local.class).build();
311     }
312
313     private static InstanceIdentifier<ServiceFfName> remoteSffInstanceIdentifier(final ServiceFfName sffName) {
314         return InstanceIdentifier.builder(Native.class)
315                 .child(org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ServiceChain.class)
316                 .child(org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.service.chain.ServiceFunctionForwarder.class)
317                 .child(ServiceFfName.class, new ServiceFfNameKey(sffName.getName())).build();
318     }
319
320     private static InstanceIdentifier<ServicePath> servicePathInstanceIdentifier(final ServicePathKey key) {
321         return InstanceIdentifier.builder(Native.class)
322                 .child(org.opendaylight.yang.gen.v1.urn.ios.rev160308._native.ServiceChain.class)
323                 .child(ServicePath.class, key).build();
324     }
325
326     private static <U extends DataObject> void writeMergeTransaction(final WriteTransaction transaction,
327                                                                      final InstanceIdentifier<U> addIID,
328                                                                      final U data) {
329         try {
330             transaction.merge(LogicalDatastoreType.CONFIGURATION, addIID, data);
331             final CheckedFuture<Void, TransactionCommitFailedException> submitFuture = transaction.submit();
332             submitFuture.checkedGet();
333         } catch (TransactionCommitFailedException e) {
334             LOG.error("Write transaction failed to {}", e.getMessage());
335         } catch (Exception e) {
336             LOG.error("Failed to .. {}", e.getMessage());
337         }
338     }
339
340     private static <U extends DataObject> boolean deleteTransaction(final WriteTransaction transaction,
341                                                                     final InstanceIdentifier<U> addIID) {
342         try {
343             transaction.delete(LogicalDatastoreType.CONFIGURATION, addIID);
344             final CheckedFuture<Void, TransactionCommitFailedException> submitFuture = transaction.submit();
345             submitFuture.checkedGet();
346             return true;
347         } catch (TransactionCommitFailedException e) {
348             LOG.error("Write transaction failed to {}", e.getMessage());
349             return false;
350         } catch (Exception e) {
351             LOG.error("Failed to .. {}", e.getMessage());
352             return false;
353         }
354     }
355
356     private static <U extends DataObject> U checkWritten(final ReadOnlyTransaction transaction,
357                                                          final InstanceIdentifier<U> readIID) {
358         for (int attempt = 1; attempt <= 5; attempt++) {
359             try {
360                 final CheckedFuture<Optional<U>, ReadFailedException> submitFuture =
361                         transaction.read(LogicalDatastoreType.CONFIGURATION, readIID);
362                 final Optional<U> optional = submitFuture.checkedGet();
363                 if (optional != null && optional.isPresent()) {
364                     transaction.close(); // Release lock
365                     return optional.get();
366                 } else {
367                     // Could take some time until specific configuration appears on device, try to read a few times
368                     Thread.sleep(2000L);
369                 }
370             } catch (InterruptedException i) {
371                 LOG.error("Thread interrupted while waiting ... {} ", i);
372             } catch (ReadFailedException e) {
373                 LOG.warn("Read transaction failed to {} ", e);
374             } catch (Exception e) {
375                 LOG.error("Failed to .. {}", e.getMessage());
376             }
377         }
378         return null;
379     }
380
381     private static <U extends DataObject> boolean checkRemoved(final ReadOnlyTransaction transaction,
382                                                                final InstanceIdentifier<U> readIID) {
383         for (int attempt = 1; attempt <= 5; attempt++) {
384             try {
385                 final CheckedFuture<Optional<U>, ReadFailedException> submitFuture =
386                         transaction.read(LogicalDatastoreType.CONFIGURATION, readIID);
387                 final Optional<U> optional = submitFuture.checkedGet();
388                 if (optional != null && optional.isPresent()) {
389                     // Could take some time until specific configuration is removed from the device
390                     Thread.sleep(2000L);
391                 } else {
392                     transaction.close(); // Release lock
393                     return true;
394                 }
395             } catch (InterruptedException i) {
396                 LOG.error("Thread interrupted while waiting ... {} ", i);
397             } catch (ReadFailedException e) {
398                 LOG.warn("Read transaction failed to {} ", e);
399             } catch (Exception e) {
400                 LOG.error("Failed to .. {}", e.getMessage());
401             }
402         }
403         return false;
404     }
405
406 }