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