bfb4ee16afdf0f74da3328ee339737d3dcdb1d81
[groupbasedpolicy.git] / renderers / ios-xe / src / main / java / org / opendaylight / groupbasedpolicy / renderer / ios_xe_provider / impl / manager / PolicyManagerImpl.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.manager;
10
11 import static org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.manager.PolicyManagerImpl.DsAction.Create;
12 import static org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.manager.PolicyManagerImpl.DsAction.Delete;
13
14 import javax.annotation.Nonnull;
15 import javax.annotation.Nullable;
16 import java.util.ArrayList;
17 import java.util.HashMap;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Optional;
21 import com.google.common.base.Function;
22 import com.google.common.base.Preconditions;
23 import com.google.common.util.concurrent.AsyncFunction;
24 import com.google.common.util.concurrent.CheckedFuture;
25 import com.google.common.util.concurrent.Futures;
26 import com.google.common.util.concurrent.ListenableFuture;
27 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
28 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
29 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
30 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
31 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.api.manager.PolicyManager;
32 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.PolicyManagerUtil;
33 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.StatusUtil;
34 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.writer.NetconfTransactionCreator;
35 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.writer.PolicyWriter;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.Renderers;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.Renderer;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.RendererKey;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.RendererPolicy;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.RendererPolicyBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.Configuration;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.Status;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.StatusBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.RendererEndpoint;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.renderer.endpoint.PeerEndpoint;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.status.UnconfiguredEndpointsBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt;
49 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
50 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54 public class PolicyManagerImpl implements PolicyManager {
55
56     private static final Logger LOG = LoggerFactory.getLogger(PolicyManagerImpl.class);
57     private static final String BASE_POLICY_MAP_NAME = "service-chains-";
58     private final DataBroker dataBroker;
59     private final NodeManager nodeManager;
60
61     public PolicyManagerImpl(final DataBroker dataBroker,
62                              final NodeManager nodeManager) {
63         this.dataBroker = Preconditions.checkNotNull(dataBroker);
64         this.nodeManager = Preconditions.checkNotNull(nodeManager);
65     }
66
67     @Override
68     @Nonnull
69     public ListenableFuture<Boolean> syncPolicy(@Nullable final Configuration dataAfter, @Nullable final Configuration dataBefore,
70                                                 final long version) {
71         final ListenableFuture<Optional<Status>> result;
72         if (dataBefore == null && dataAfter != null) {
73             result = syncEndpoints(dataAfter, Create);
74         } else if (dataBefore != null && dataAfter == null) {
75             result = syncEndpoints(dataBefore, Delete);
76         } else {
77             syncEndpoints(dataBefore, Delete);
78             syncEndpoints(dataAfter, Create);
79             result = Futures.immediateFuture(Optional.empty());
80         }
81
82         return Futures.transform(result, new AsyncFunction<Optional<Status>, Boolean>() {
83             @Override
84             public ListenableFuture<Boolean> apply(@Nullable final Optional<Status> statusValue) throws Exception {
85                 Preconditions.checkArgument(statusValue != null, "provided status must not be null");
86                 return Futures.transform(reportPolicy(version, statusValue), new Function<Void, Boolean>() {
87                     @Override
88                     public Boolean apply(@Nullable final Void input) {
89                         return Boolean.TRUE;
90                     }
91                 });
92             }
93         });
94     }
95
96     private ListenableFuture<Optional<Status>> syncEndpoints(final Configuration dataAfter, DsAction action) {
97         if (dataAfter.getRendererEndpoints() == null
98                 || dataAfter.getRendererEndpoints().getRendererEndpoint() == null) {
99             LOG.debug("no configuration obtained - skipping");
100             return Futures.immediateFuture(Optional.empty());
101         }
102
103         final PolicyConfigurationContext context = new PolicyConfigurationContext();
104         final Map<String, PolicyWriter> policyWriterPerDeviceCache = new HashMap<>();
105         for (RendererEndpoint rendererEndpoint : dataAfter.getRendererEndpoints().getRendererEndpoint()) {
106             // Store the endpoint currently being configured
107             context.setCurrentRendererEP(rendererEndpoint);
108
109             if (dataAfter.getEndpoints() == null || dataAfter.getEndpoints().getAddressEndpointWithLocation() == null) {
110                 final String info = "renderer-endpoint: missing address-endpoint-with-location";
111                 context.appendUnconfiguredRendererEP(StatusUtil.assembleFullyNotConfigurableRendererEP(context, info));
112                 continue;
113             }
114             final List<AddressEndpointWithLocation> endpointsWithLocation = dataAfter.getEndpoints()
115                     .getAddressEndpointWithLocation();
116             final InstanceIdentifier mountpointIid = PolicyManagerUtil.getMountpointIidFromAbsoluteLocation(rendererEndpoint, endpointsWithLocation);
117             final DataBroker mountpoint = nodeManager.getNodeMountPoint(mountpointIid);
118             if (mountpoint == null) {
119                 final String info = String.format("no data-broker for mount-point [%s] available", mountpointIid);
120                 context.appendUnconfiguredRendererEP(StatusUtil.assembleFullyNotConfigurableRendererEP(context, info));
121                 continue;
122             }
123             // Generate policy writer key - policy map name, composed from base value, interface name and node id
124             final String interfaceName = PolicyManagerUtil.getInterfaceNameFromAbsoluteLocation(rendererEndpoint, endpointsWithLocation);
125             final NodeId nodeId = nodeManager.getNodeIdByMountpointIid(mountpointIid);
126             if (interfaceName == null || nodeId == null) {
127                 LOG.warn("Cannot compose policy-map, missing value. Interface: {}, NodeId: {}", interfaceName, nodeId);
128                 continue;
129             }
130             final String policyMapName = BASE_POLICY_MAP_NAME.concat(interfaceName);
131             final String policyWriterKey = policyMapName.concat("-" + nodeId.getValue());
132             // Find appropriate writer
133             PolicyWriter policyWriter = policyWriterPerDeviceCache.get(policyWriterKey);
134             if (policyWriter == null) {
135                 // Initialize new policy writer
136                 final String managementIpAddress = nodeManager.getNodeManagementIpByMountPointIid(mountpointIid);
137                 if (managementIpAddress == null) {
138                     final String info = String.format("can not create policyWriter, managementIpAddress for mountpoint %s is null",
139                             mountpointIid);
140                     context.appendUnconfiguredRendererEP(StatusUtil.assembleFullyNotConfigurableRendererEP(context, info));
141                     continue;
142                 }
143                 policyWriter = new PolicyWriter(mountpoint, interfaceName, managementIpAddress, policyMapName, nodeId);
144                 policyWriterPerDeviceCache.put(policyWriterKey, policyWriter);
145             }
146
147             // Assign policyWriter for current policy-map
148             context.setPolicyWriter(policyWriter);
149
150             final Sgt sourceSgt = PolicyManagerUtil.findSgtTag(rendererEndpoint, dataAfter.getEndpoints()
151                     .getAddressEndpointWithLocation());
152             // Peer Endpoint
153             for (PeerEndpoint peerEndpoint : rendererEndpoint.getPeerEndpoint()) {
154                 final Sgt destinationSgt = PolicyManagerUtil.findSgtTag(peerEndpoint, dataAfter.getEndpoints()
155                         .getAddressEndpointWithLocation());
156                 if (sourceSgt == null || destinationSgt == null) {
157                     final String info = String.format("endpoint-policy: missing sgt value(sourceSgt=%s, destinationSgt=%s)",
158                             sourceSgt, destinationSgt);
159                     context.appendUnconfiguredRendererEP(
160                             StatusUtil.assembleNotConfigurableRendererEPForPeer(context, peerEndpoint, info));
161                     continue;
162                 }
163                 PolicyManagerUtil.syncResolvedPolicy(sourceSgt, destinationSgt, context, dataAfter, peerEndpoint,
164                         dataBroker, action);
165             }
166         }
167
168         final List<CheckedFuture<Boolean, TransactionCommitFailedException>> allFutureResults = new ArrayList<>();
169         if (action.equals(Create)) {
170             // TODO ensure that last transaction is done before the next one starts
171             policyWriterPerDeviceCache.values().forEach((pw) -> allFutureResults.add(pw.commitToDatastore()));
172         } else if (action.equals(Delete)) {
173             policyWriterPerDeviceCache.values().forEach((pw) -> allFutureResults.add(pw.removeFromDatastore()));
174         } else {
175             LOG.info("unsupported policy manage action: {}", action);
176         }
177         final ListenableFuture<List<Boolean>> cumulativeResult = Futures.allAsList(allFutureResults);
178
179         return Futures.transform(cumulativeResult, new Function<List<Boolean>, Optional<Status>>() {
180             @Nullable
181             @Override
182             public Optional<Status> apply(@Nullable final List<Boolean> input) {
183                 //TODO: inspect if all booleans are true
184
185                 LOG.trace("considering all submits as successful - otherwise there will be exception");
186                 final Status status = new StatusBuilder()
187                         .setUnconfiguredEndpoints(new UnconfiguredEndpointsBuilder()
188                                 .setUnconfiguredRendererEndpoint(context.getUnconfiguredRendererEPBag())
189                                 .build())
190                         .build();
191
192                 return Optional.of(status);
193             }
194         });
195     }
196
197     private CheckedFuture<Void, TransactionCommitFailedException> reportPolicy(long version, @Nonnull final Optional<Status> statusValue) {
198         final Optional<ReadWriteTransaction> optionalReadWriteTransaction =
199                 NetconfTransactionCreator.netconfReadWriteTransaction(dataBroker);
200         if (!optionalReadWriteTransaction.isPresent()) {
201             LOG.warn("Failed to create transaction, mountpoint: {}", dataBroker);
202             return Futures.immediateCheckedFuture(null);
203         }
204         final ReadWriteTransaction readWriteTransaction = optionalReadWriteTransaction.get();
205         final InstanceIdentifier<RendererPolicy> iid = InstanceIdentifier.create(Renderers.class)
206                 .child(Renderer.class, new RendererKey(NodeManager.iosXeRenderer))
207                 .child(RendererPolicy.class);
208         final RendererPolicy rendererPolicy = new RendererPolicyBuilder()
209                 .setVersion(version)
210                 .setStatus(statusValue.orElse(null))
211                 .build();
212         readWriteTransaction.merge(LogicalDatastoreType.OPERATIONAL, iid, rendererPolicy);
213         return readWriteTransaction.submit();
214     }
215
216     @Override
217     public void close() {
218         //NOOP
219     }
220
221     public enum DsAction {Create, Delete}
222
223     public enum ActionCase {ALLOW, CHAIN}
224 }