884e74e469defdecfb9a73440552f610aeace3b5
[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.List;
17 import java.util.Optional;
18 import com.google.common.base.Function;
19 import com.google.common.base.Preconditions;
20 import com.google.common.util.concurrent.AsyncFunction;
21 import com.google.common.util.concurrent.CheckedFuture;
22 import com.google.common.util.concurrent.Futures;
23 import com.google.common.util.concurrent.ListenableFuture;
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
28 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.api.manager.PolicyManager;
29 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.PolicyManagerUtil;
30 import org.opendaylight.groupbasedpolicy.renderer.ios_xe_provider.impl.util.StatusUtil;
31 import org.opendaylight.groupbasedpolicy.sxp.ep.provider.api.EPToSgtMapper;
32 import org.opendaylight.groupbasedpolicy.sxp.ep.provider.spi.SxpEpProviderProvider;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.RendererName;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.Renderers;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.Renderer;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.RendererKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.RendererPolicy;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.RendererPolicyBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.Configuration;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.Status;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.StatusBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocation;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.RendererEndpoint;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.renderer.endpoints.renderer.endpoint.PeerEndpoint;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.status.UnconfiguredEndpointsBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt;
47 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
48 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51
52 public class PolicyManagerImpl implements PolicyManager {
53
54     private static final Logger LOG = LoggerFactory.getLogger(PolicyManagerImpl.class);
55     public static final RendererName IOS_XE_RENDERER = new RendererName("ios-xe-renderer");
56     private static final String BASE_POLICY_MAP_NAME = "service-chains-";
57     private final DataBroker dataBroker;
58     private final NodeManager nodeManager;
59     private final EPToSgtMapper epToSgtMapper;
60
61     public PolicyManagerImpl(final DataBroker dataBroker,
62                              final NodeManager nodeManager, final EPToSgtMapper epToSgtMapper) {
63         this.dataBroker = Preconditions.checkNotNull(dataBroker);
64         this.nodeManager = Preconditions.checkNotNull(nodeManager);
65         this.epToSgtMapper = Preconditions.checkNotNull(epToSgtMapper);
66     }
67
68     @Override
69     @Nonnull
70     public ListenableFuture<Boolean> syncPolicy(@Nullable final Configuration dataAfter, @Nullable final Configuration dataBefore,
71                                                 final long version) {
72         ListenableFuture<Optional<Status>> creationResult;
73         if (dataBefore == null && dataAfter != null) {
74             creationResult = syncEndpoints(dataAfter, Create);
75         } else if (dataBefore != null && dataAfter == null) {
76             creationResult = syncEndpoints(dataBefore, Delete);
77         } else {
78             final ListenableFuture<Optional<Status>> deletionResult = syncEndpoints(dataBefore, Delete);
79             creationResult = Futures.transform(deletionResult, new AsyncFunction<Optional<Status>, Optional<Status>>() {
80                 @Nonnull
81                 @Override
82                 public ListenableFuture<Optional<Status>> apply(@Nonnull Optional<Status> deletionResult) throws Exception {
83                     if (deletionResult.isPresent()) {
84                         // Wait till task is done. Result is not used, delete case has no status
85                         deletionResult.get();
86                     }
87                     return syncEndpoints(dataAfter, Create);
88                 }
89             });
90         }
91         return Futures.transform(creationResult, new AsyncFunction<Optional<Status>, Boolean>() {
92             @Override
93             public ListenableFuture<Boolean> apply(@Nullable final Optional<Status> statusValue) throws Exception {
94                 Preconditions.checkArgument(statusValue != null, "provided status must not be null");
95                 return Futures.transform(reportPolicy(version, statusValue), new Function<Void, Boolean>() {
96                     @Override
97                     public Boolean apply(@Nullable final Void input) {
98                         return Boolean.TRUE;
99                     }
100                 });
101             }
102         });
103     }
104
105     /**
106      * Resolve policy for all endpoint pairs
107      *
108      * @param dataAfter - data used while processing
109      * @param action    - specifies whether data are intended for creating or removing of configuration
110      * @return status of policy resolution
111      */
112     @Nonnull
113     private ListenableFuture<Optional<Status>> syncEndpoints(final Configuration dataAfter, final DsAction action) {
114         if (dataAfter.getRendererEndpoints() == null
115                 || dataAfter.getRendererEndpoints().getRendererEndpoint() == null) {
116             LOG.debug("No configuration obtained - skipping");
117             return Futures.immediateFuture(Optional.empty());
118         }
119         final PolicyConfigurationContext context = new PolicyConfigurationContext();
120         // Renderer endpoint
121         for (RendererEndpoint rendererEndpoint : dataAfter.getRendererEndpoints().getRendererEndpoint()) {
122             context.setCurrentRendererEP(rendererEndpoint);
123
124             if (dataAfter.getEndpoints() == null || dataAfter.getEndpoints().getAddressEndpointWithLocation() == null) {
125                 final String info = "Renderer-endpoint: missing address-endpoint-with-location";
126                 context.appendUnconfiguredRendererEP(StatusUtil.assembleFullyNotConfigurableRendererEP(context, info));
127                 continue;
128             }
129             final List<AddressEndpointWithLocation> endpointsWithLocation = dataAfter.getEndpoints()
130                     .getAddressEndpointWithLocation();
131             final InstanceIdentifier mountpointIid = PolicyManagerUtil.getMountpointIidFromAbsoluteLocation(rendererEndpoint, endpointsWithLocation);
132             final DataBroker mountpoint = nodeManager.getNodeMountPoint(mountpointIid);
133             if (mountpoint == null) {
134                 final String info = String.format("No data-broker for mount-point [%s] available", mountpointIid);
135                 context.appendUnconfiguredRendererEP(StatusUtil.assembleFullyNotConfigurableRendererEP(context, info));
136                 continue;
137             }
138             final Optional<String> optionalManagementIpAddress = nodeManager.getNodeManagementIpByMountPointIid(mountpointIid);
139             if (!optionalManagementIpAddress.isPresent()) {
140                 final String info = String.format("Can not create policyWriter, managementIpAddress for mountpoint %s is null",
141                         mountpointIid);
142                 context.appendUnconfiguredRendererEP(StatusUtil.assembleFullyNotConfigurableRendererEP(context, info));
143                 continue;
144             }
145             final String managementIpAddress = optionalManagementIpAddress.get();
146             final String interfaceName = PolicyManagerUtil.getInterfaceNameFromAbsoluteLocation(rendererEndpoint, endpointsWithLocation);
147             final NodeId nodeId = nodeManager.getNodeIdByMountpointIid(mountpointIid);
148             if (interfaceName == null || nodeId == null) {
149                 final String info = String.format("Cannot compose policy-map, missing value. Interface: %s, NodeId: %s", interfaceName, nodeId);
150                 context.appendUnconfiguredRendererEP(StatusUtil.assembleFullyNotConfigurableRendererEP(context, info));
151                 LOG.warn(info);
152                 continue;
153             }
154             final String policyMapName = BASE_POLICY_MAP_NAME.concat(interfaceName);
155             final PolicyMapLocation policyMapLocation = new PolicyMapLocation(policyMapName, interfaceName, nodeId,
156                     managementIpAddress, mountpoint);
157             context.setPolicyMapLocation(policyMapLocation);
158
159             final Sgt sourceSgt = PolicyManagerUtil.findSgtTag(epToSgtMapper, rendererEndpoint, dataAfter.getEndpoints()
160                     .getAddressEndpointWithLocation());
161             // Peer Endpoint
162             for (PeerEndpoint peerEndpoint : rendererEndpoint.getPeerEndpoint()) {
163                 final Sgt destinationSgt = PolicyManagerUtil.findSgtTag(epToSgtMapper, peerEndpoint, dataAfter.getEndpoints()
164                         .getAddressEndpointWithLocation());
165                 if (sourceSgt == null || destinationSgt == null) {
166                     final String info = String.format("Endpoint-policy: missing sgt value(sourceSgt=%s, destinationSgt=%s)",
167                             sourceSgt, destinationSgt);
168                     context.appendUnconfiguredRendererEP(
169                             StatusUtil.assembleNotConfigurableRendererEPForPeer(context, peerEndpoint, info));
170                     continue;
171                 }
172                 // Resolve policy between endpoints
173                 if (action.equals(Create)) {
174                     LOG.debug("Setting up policy between endpoint {}, sgt: {} and peer {}, sgt: {}", rendererEndpoint,
175                             sourceSgt, peerEndpoint, destinationSgt);
176                     PolicyManagerUtil.syncEndpointPairCreatePolicy(sourceSgt, destinationSgt, context, dataAfter,
177                             peerEndpoint, dataBroker);
178                 } else {
179                     LOG.debug("Removing policy between endpoint {}, sgt: {} and peer {}, sgt: {}", rendererEndpoint,
180                             sourceSgt, peerEndpoint, destinationSgt);
181                     PolicyManagerUtil.syncEndpointPairRemovePolicy(sourceSgt, destinationSgt, context, dataAfter,
182                             peerEndpoint);
183                 }
184             }
185         }
186         final ListenableFuture<List<Boolean>> cumulativeResult = context.getCumulativeResult();
187         return Futures.transform(cumulativeResult, new Function<List<Boolean>, Optional<Status>>() {
188             @Nullable
189             @Override
190             public Optional<Status> apply(@Nullable final List<Boolean> input) {
191                 //TODO: inspect if all booleans are true
192
193                 LOG.trace("considering all submits as successful - otherwise there will be exception");
194                 final Status status = new StatusBuilder()
195                         .setUnconfiguredEndpoints(new UnconfiguredEndpointsBuilder()
196                                 .setUnconfiguredRendererEndpoint(context.getUnconfiguredRendererEPBag())
197                                 .build())
198                         .build();
199
200                 return Optional.of(status);
201             }
202         });
203     }
204
205     private CheckedFuture<Void, TransactionCommitFailedException> reportPolicy(final long version,
206                                                                                @Nonnull final Optional<Status> statusValue) {
207         if (statusValue.isPresent()) {
208             LOG.warn("IOS-XE renderer: operation not successfully completed, check unconfigured policy in operational/renderer:renderers");
209         }
210         final ReadWriteTransaction readWriteTransaction = dataBroker.newReadWriteTransaction();
211         final InstanceIdentifier<RendererPolicy> iid = InstanceIdentifier.create(Renderers.class)
212                 .child(Renderer.class, new RendererKey(IOS_XE_RENDERER))
213                 .child(RendererPolicy.class);
214         final RendererPolicy rendererPolicy = new RendererPolicyBuilder()
215                 .setVersion(version)
216                 .setStatus(statusValue.orElse(null))
217                 .build();
218         readWriteTransaction.merge(LogicalDatastoreType.OPERATIONAL, iid, rendererPolicy);
219         return readWriteTransaction.submit();
220     }
221
222     @Override
223     public void close() {
224         //NOOP
225     }
226
227     enum DsAction {Create, Delete}
228
229     public enum ActionCase {ALLOW, CHAIN}
230
231     /**
232      * Wrapper class - contains all necessary information to clearly localize policy-map/interface/node in network
233      */
234     public static class PolicyMapLocation {
235
236         private final String policyMapName;
237         private final String interfaceName;
238         private final NodeId nodeId;
239         private final String managementIpAddress;
240         private final DataBroker mountpoint;
241
242         public PolicyMapLocation(final String policyMapName, final String interfaceName, final NodeId nodeId,
243                                  final String managementIpAddress, final DataBroker mountpoint) {
244             this.policyMapName = Preconditions.checkNotNull(policyMapName);
245             this.interfaceName = Preconditions.checkNotNull(interfaceName);
246             this.nodeId = Preconditions.checkNotNull(nodeId);
247             this.managementIpAddress = Preconditions.checkNotNull(managementIpAddress);
248             this.mountpoint = Preconditions.checkNotNull(mountpoint);
249         }
250
251         public String getPolicyMapName() {
252             return policyMapName;
253         }
254
255         public String getInterfaceName() {
256             return interfaceName;
257         }
258
259         public NodeId getNodeId() {
260             return nodeId;
261         }
262
263         public String getManagementIpAddress() {
264             return managementIpAddress;
265         }
266
267         public DataBroker getMountpoint() {
268             return mountpoint;
269         }
270     }
271 }