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