Merge "Tenant crud part 1"
[groupbasedpolicy.git] / neutron-mapper / src / main / java / org / opendaylight / groupbasedpolicy / neutron / mapper / NeutronMapper.java
1 /*
2  * Copyright (c) 2015 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 package org.opendaylight.groupbasedpolicy.neutron.mapper;
9
10 import java.io.IOException;
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.List;
14 import java.util.Set;
15
16 import javax.annotation.Nullable;
17
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
20 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType;
21 import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
22 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
23 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
24 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
25 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
26 import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.NeutronAware;
27 import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.NeutronFloatingIpAware;
28 import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.NeutronNetworkAware;
29 import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.NeutronPortAware;
30 import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.NeutronRouterAware;
31 import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.NeutronSecurityGroupAware;
32 import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.NeutronSubnetAware;
33 import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.rule.NeutronSecurityRuleAware;
34 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
35 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.NetworkUtils;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointService;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionEgress;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionIngress;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.EthertypeV4;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.EthertypeV6;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.floatingips.Floatingip;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.NeutronBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.groups.attributes.SecurityGroups;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.groups.attributes.SecurityGroupsBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.groups.attributes.security.groups.SecurityGroup;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.groups.attributes.security.groups.SecurityGroupBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.SecurityRules;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.SecurityRulesBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.security.rules.SecurityRule;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.security.rules.SecurityRuleBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
57 import org.opendaylight.yangtools.concepts.ListenerRegistration;
58 import org.opendaylight.yangtools.yang.binding.DataObject;
59 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
60 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
61
62 import com.google.common.base.Function;
63 import com.google.common.base.Predicate;
64 import com.google.common.collect.FluentIterable;
65 import com.google.common.collect.Iterators;
66 import com.google.common.collect.PeekingIterator;
67
68 public class NeutronMapper implements DataTreeChangeListener<Neutron>, AutoCloseable {
69
70     private final static SecurityRuleBuilder EIG_INGRESS_IPV4_SEC_RULE_BUILDER = new SecurityRuleBuilder()
71         .setId(new Uuid("19b85ad2-bdfc-11e5-9912-ba0be0483c18"))
72         .setDirection(DirectionIngress.class)
73         .setEthertype(EthertypeV4.class)
74         .setSecurityGroupId(MappingUtils.EIG_UUID);
75     private final static SecurityRuleBuilder EIG_EGRESS_IPV4_SEC_RULE_BUILDER = new SecurityRuleBuilder()
76         .setId(new Uuid("19b85ad2-bdfc-11e5-9912-ba0be0483c18"))
77         .setDirection(DirectionEgress.class)
78         .setEthertype(EthertypeV4.class)
79         .setSecurityGroupId(MappingUtils.EIG_UUID);
80     private final static SecurityRuleBuilder EIG_INGRESS_IPV6_SEC_RULE_BUILDER = new SecurityRuleBuilder()
81         .setId(new Uuid("19b85ad2-bdfc-11e5-9912-ba0be0483c18"))
82         .setDirection(DirectionIngress.class)
83         .setEthertype(EthertypeV6.class)
84         .setSecurityGroupId(MappingUtils.EIG_UUID);
85     private final static SecurityRuleBuilder EIG_EGRESS_IPV6_SEC_RULE_BUILDER = new SecurityRuleBuilder()
86         .setId(new Uuid("19b85ad2-bdfc-11e5-9912-ba0be0483c18"))
87         .setDirection(DirectionEgress.class)
88         .setEthertype(EthertypeV6.class)
89         .setSecurityGroupId(MappingUtils.EIG_UUID);
90     private final static SecurityGroupBuilder EIG_SEC_GROUP_BUILDER =
91             new SecurityGroupBuilder().setUuid(MappingUtils.EIG_UUID).setDescription("EXTERNAL_group");
92
93     private final NeutronNetworkAware networkAware;
94     private final NeutronSecurityGroupAware securityGroupAware;
95     private final NeutronSecurityRuleAware securityRuleAware;
96     private final NeutronSubnetAware subnetAware;
97     private final NeutronPortAware portAware;
98     private final NeutronRouterAware routerAware;
99     private final NeutronFloatingIpAware floatingIpAware;
100
101     private final ListenerRegistration<NeutronMapper> registerDataTreeChangeListener;
102     private Neutron neutronBefore;
103     private Neutron neutronAfter;
104
105     public NeutronMapper(DataBroker dataProvider, RpcProviderRegistry rpcProvider) {
106         EndpointService epService = rpcProvider.getRpcService(EndpointService.class);
107         EndpointRegistrator epRegistrator = new EndpointRegistrator(epService);
108         networkAware = new NeutronNetworkAware(dataProvider);
109         securityGroupAware = new NeutronSecurityGroupAware(dataProvider);
110         securityRuleAware = new NeutronSecurityRuleAware(dataProvider);
111         subnetAware = new NeutronSubnetAware(dataProvider, epRegistrator);
112         portAware = new NeutronPortAware(dataProvider, epRegistrator);
113         routerAware = new NeutronRouterAware(dataProvider, epRegistrator);
114         floatingIpAware = new NeutronFloatingIpAware(dataProvider);
115         registerDataTreeChangeListener =
116                 dataProvider.registerDataTreeChangeListener(new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
117                         InstanceIdentifier.builder(Neutron.class).build()), this);
118     }
119
120     @Override
121     public void onDataTreeChanged(Collection<DataTreeModification<Neutron>> changes) {
122         for (DataTreeModification<Neutron> change : changes) {
123             DataObjectModification<Neutron> neutronModif = change.getRootNode();
124             resolveAndSetNeutron(neutronModif);
125             // network
126             List<DataObjectModification<Network>> networkModifs =
127                     findModifiedData(NeutronNetworkAware.NETWORK_WILDCARD_IID, neutronModif);
128             for (Uuid tenantFromCreatedRouterExternalNetwork : filterCreatedRouterExternalNetworksAndTransformToTenants(
129                     networkModifs)) {
130                 SecurityGroup eigSecGroup =
131                         EIG_SEC_GROUP_BUILDER.setTenantId(tenantFromCreatedRouterExternalNetwork).build();
132                 securityGroupAware.onCreated(eigSecGroup, neutronAfter);
133                 List<SecurityRule> eigSecRules = createEigSecurityRules(tenantFromCreatedRouterExternalNetwork);
134                 for (SecurityRule eigSecRule : eigSecRules) {
135                     securityRuleAware.onCreated(eigSecRule, neutronAfter);
136                 }
137             }
138             onDataObjectModification(networkModifs, networkAware);
139             // security group
140             List<DataObjectModification<SecurityGroup>> secGroupModifs =
141                     findModifiedData(NeutronSecurityGroupAware.SECURITY_GROUP_WILDCARD_IID, neutronModif);
142             onDataObjectModification(secGroupModifs, securityGroupAware);
143             // security rules
144             List<DataObjectModification<SecurityRule>> secRuleModifs =
145                     findModifiedData(NeutronSecurityRuleAware.SECURITY_RULE_WILDCARD_IID, neutronModif);
146             onDataObjectModification(secRuleModifs, securityRuleAware);
147             // subnet
148             List<DataObjectModification<Subnet>> subnetModifs = findModifiedData(NeutronSubnetAware.SUBNET_WILDCARD_IID, neutronModif);
149             onDataObjectModification(subnetModifs, subnetAware);
150             // port
151             List<DataObjectModification<Port>> portModifs = findModifiedData(NeutronPortAware.PORT_WILDCARD_IID, neutronModif);
152             onDataObjectModification(portModifs, portAware);
153             // router
154             List<DataObjectModification<Router>> routerModifs = findModifiedData(NeutronRouterAware.ROUTER_WILDCARD_IID, neutronModif);
155             onDataObjectModification(routerModifs, routerAware);
156             // floating IP
157             List<DataObjectModification<Floatingip>> floatingIpModifs = findModifiedData(NeutronFloatingIpAware.FLOATING_IP_WILDCARD_IID, neutronModif);
158             onDataObjectModification(floatingIpModifs, floatingIpAware);
159         }
160     }
161
162     private <T extends DataObject> void onDataObjectModification(List<DataObjectModification<T>> dataModifs,
163             NeutronAware<T> neutronAware) {
164         for (DataObjectModification<T> dataModif : dataModifs) {
165             switch (dataModif.getModificationType()) {
166                 case DELETE:
167                     neutronAware.onDeleted(dataModif.getDataBefore(), neutronBefore, neutronAfter);
168                     break;
169                 case SUBTREE_MODIFIED:
170                     neutronAware.onUpdated(dataModif.getDataBefore(), dataModif.getDataAfter(), neutronBefore,
171                             neutronAfter);
172                     break;
173                 case WRITE:
174                     if (dataModif.getDataBefore() == null) {
175                         neutronAware.onCreated(dataModif.getDataAfter(), neutronAfter);
176                     } else {
177                         neutronAware.onUpdated(dataModif.getDataBefore(), dataModif.getDataAfter(), neutronBefore,
178                                 neutronAfter);
179                     }
180                     break;
181                 default:
182                     throw new IllegalStateException("Unknown modification type within data " + dataModif);
183             }
184         }
185     }
186
187     private Set<Uuid> filterCreatedRouterExternalNetworksAndTransformToTenants(
188             List<DataObjectModification<Network>> modifiedNetworks) {
189         return FluentIterable.from(modifiedNetworks).filter(new Predicate<DataObjectModification<Network>>() {
190
191             @Override
192             public boolean apply(DataObjectModification<Network> modifiedNetwork) {
193                 return (ModificationType.WRITE == modifiedNetwork.getModificationType()
194                         && NetworkUtils.isRouterExternal(modifiedNetwork.getDataAfter()));
195             }
196         }).transform(new Function<DataObjectModification<Network>, Uuid>() {
197
198             @Override
199             public Uuid apply(DataObjectModification<Network> modifiedNetwork) {
200                 return modifiedNetwork.getDataAfter().getTenantId();
201             }
202         }).toSet();
203     }
204
205     private void resolveAndSetNeutron(DataObjectModification<Neutron> originalNeutron) {
206         Neutron oldNeutronBefore = originalNeutron.getDataBefore();
207         neutronBefore = resolveAndCreateNewNeutron(oldNeutronBefore);
208         Neutron oldNeutronAfter = originalNeutron.getDataAfter();
209         neutronAfter = resolveAndCreateNewNeutron(oldNeutronAfter);
210     }
211
212     private @Nullable Neutron resolveAndCreateNewNeutron(@Nullable Neutron originalNeutron) {
213         if (originalNeutron == null) {
214             return null;
215         }
216         NeutronBuilder newNeutronBuilder = new NeutronBuilder(originalNeutron);
217         resolveAndAddSecurityRulesAndGroups(originalNeutron, newNeutronBuilder);
218         return newNeutronBuilder.build();
219     }
220
221     private void resolveAndAddSecurityRulesAndGroups(Neutron originalNeutron, NeutronBuilder newNeutronBuilder) {
222         List<SecurityRule> eigSecRulesAndOriginalSecRules = new ArrayList<>();
223         List<SecurityGroup> eigSecGroupAndOriginalSecGroup = new ArrayList<>();
224         // resolve EIG sec rules and groups
225         List<Network> routerExternalNetworks = NetworkUtils.findRouterExternalNetworks(originalNeutron.getNetworks());
226         Set<Uuid> tenantsFromRouterExternalNetwork = resolveTenantsFromNetworks(routerExternalNetworks);
227         for (Uuid tenantFromRouterExternalNetwork : tenantsFromRouterExternalNetwork) {
228             eigSecRulesAndOriginalSecRules.addAll(createEigSecurityRules(tenantFromRouterExternalNetwork));
229             eigSecGroupAndOriginalSecGroup
230                 .add(EIG_SEC_GROUP_BUILDER.setTenantId(tenantFromRouterExternalNetwork).build());
231         }
232         // set new sec rules
233         SecurityRules newSecRules = null;
234         if (originalNeutron.getSecurityRules() != null) {
235             List<SecurityRule> originalSecRules = originalNeutron.getSecurityRules().getSecurityRule();
236             if (originalSecRules != null) {
237                 eigSecRulesAndOriginalSecRules.addAll(originalSecRules);
238             }
239             newSecRules = new SecurityRulesBuilder(originalNeutron.getSecurityRules())
240                 .setSecurityRule(eigSecRulesAndOriginalSecRules).build();
241         } else {
242             newSecRules = new SecurityRulesBuilder().setSecurityRule(eigSecRulesAndOriginalSecRules).build();
243         }
244         newNeutronBuilder.setSecurityRules(newSecRules);
245         // set new sec groups
246         SecurityGroups newSecGroups = null;
247         if (originalNeutron.getSecurityGroups() != null) {
248             List<SecurityGroup> originalSecGroups = originalNeutron.getSecurityGroups().getSecurityGroup();
249             if (originalSecGroups != null) {
250                 eigSecGroupAndOriginalSecGroup.addAll(originalSecGroups);
251             }
252             newSecGroups = new SecurityGroupsBuilder(originalNeutron.getSecurityGroups())
253                 .setSecurityGroup(eigSecGroupAndOriginalSecGroup).build();
254         } else {
255             newSecGroups = new SecurityGroupsBuilder().setSecurityGroup(eigSecGroupAndOriginalSecGroup).build();
256         }
257         newNeutronBuilder.setSecurityGroups(newSecGroups);
258     }
259
260     private Set<Uuid> resolveTenantsFromNetworks(List<Network> networks) {
261         return FluentIterable.from(networks).transform(new Function<Network, Uuid>() {
262
263             @Override
264             public Uuid apply(Network network) {
265                 return network.getTenantId();
266             }
267         }).toSet();
268     }
269
270     private List<SecurityRule> createEigSecurityRules(Uuid tenant) {
271         List<SecurityRule> eigSecRules = new ArrayList<>();
272         eigSecRules.add(EIG_INGRESS_IPV4_SEC_RULE_BUILDER.setTenantId(tenant).build());
273         eigSecRules.add(EIG_EGRESS_IPV4_SEC_RULE_BUILDER.setTenantId(tenant).build());
274         eigSecRules.add(EIG_INGRESS_IPV6_SEC_RULE_BUILDER.setTenantId(tenant).build());
275         eigSecRules.add(EIG_EGRESS_IPV6_SEC_RULE_BUILDER.setTenantId(tenant).build());
276         return eigSecRules;
277     }
278
279     /**
280      * Finds all modified subnodes of given type in {@link Neutron} node.
281      *
282      * @param <T>
283      * @param iid path to data in root node
284      * @param rootNode modified data of {@link Neutron} node
285      * @return {@link List} of modified subnodes
286      */
287     private <T extends DataObject> List<DataObjectModification<T>> findModifiedData(InstanceIdentifier<T> iid,
288             DataObjectModification<Neutron> rootNode) {
289         List<DataObjectModification<T>> modDtos = new ArrayList<>();
290         PeekingIterator<PathArgument> pathArgs = Iterators.peekingIterator(iid.getPathArguments().iterator());
291         DataObjectModification<? extends DataObject> modifDto = rootNode;
292         while (pathArgs.hasNext()) {
293             pathArgs.next();
294             for (DataObjectModification<? extends DataObject> childDto : modifDto.getModifiedChildren()) {
295                 if (pathArgs.hasNext() && childDto.getDataType().equals(pathArgs.peek().getType())) {
296                     if (childDto.getDataType().equals(iid.getTargetType())) {
297                         modDtos.add((DataObjectModification<T>) childDto);
298                     } else {
299                         modifDto = childDto;
300                         break;
301                     }
302                 }
303             }
304         }
305         return modDtos;
306     }
307
308     @Override
309     public void close() throws IOException {
310         registerDataTreeChangeListener.close();
311     }
312
313 }