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