Introduced neutron-mapper
[groupbasedpolicy.git] / neutron-mapper / src / main / java / org / opendaylight / groupbasedpolicy / neutron / mapper / mapping / NeutronSecurityGroupAware.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.mapping;
9
10 import static com.google.common.base.Preconditions.checkNotNull;
11
12 import java.util.ArrayList;
13 import java.util.List;
14
15 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
16 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
17 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
18 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.DataStoreHelper;
19 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.IidFactory;
20 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
21 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.Utils;
22 import org.opendaylight.neutron.spi.INeutronSecurityGroupAware;
23 import org.opendaylight.neutron.spi.NeutronSecurityGroup;
24 import org.opendaylight.neutron.spi.NeutronSecurityRule;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Name;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroupBuilder;
32 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 import com.google.common.base.Optional;
37 import com.google.common.base.Preconditions;
38 import com.google.common.base.Strings;
39 import com.google.common.collect.ArrayListMultimap;
40 import com.google.common.collect.ImmutableList;
41 import com.google.common.collect.ImmutableListMultimap;
42 import com.google.common.collect.ListMultimap;
43
44 public class NeutronSecurityGroupAware implements INeutronSecurityGroupAware {
45
46     private static final Logger LOG = LoggerFactory.getLogger(NeutronSecurityGroupAware.class);
47     private final DataBroker dataProvider;
48
49     public NeutronSecurityGroupAware(DataBroker dataProvider) {
50         this.dataProvider = checkNotNull(dataProvider);
51     }
52
53     /**
54      * @see org.opendaylight.neutron.spi.INeutronSecurityGroupAware#canCreateNeutronSecurityGroup(org.opendaylight.neutron.spi.NeutronSecurityGroup)
55      */
56     @Override
57     public int canCreateNeutronSecurityGroup(NeutronSecurityGroup securityGroup) {
58         LOG.trace("canCreateNeutronSecurityGroup - {}", securityGroup);
59         // nothing to consider
60         return StatusCode.OK;
61     }
62
63     /**
64      * @see org.opendaylight.neutron.spi.INeutronSecurityGroupAware#neutronSecurityGroupCreated(org.opendaylight.neutron.spi.NeutronSecurityGroup)
65      */
66     @Override
67     public void neutronSecurityGroupCreated(NeutronSecurityGroup secGroup) {
68         LOG.trace("neutronSecurityGroupCreated - {}", secGroup);
69         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
70         boolean isSecGroupCreated = addNeutronSecurityGroup(secGroup, rwTx);
71         if (isSecGroupCreated) {
72             DataStoreHelper.submitToDs(rwTx);
73         } else {
74             rwTx.cancel();
75         }
76     }
77
78     public static boolean addNeutronSecurityGroup(NeutronSecurityGroup secGroup, ReadWriteTransaction rwTx) {
79         TenantId tenantId = new TenantId(Utils.normalizeUuid(secGroup.getSecurityGroupTenantID()));
80         EndpointGroupId providerEpgId = new EndpointGroupId(secGroup.getSecurityGroupUUID());
81         EndpointGroupBuilder providerEpgBuilder = new EndpointGroupBuilder().setId(providerEpgId);
82         providerEpgBuilder.setName(new Name(MappingUtils.NEUTRON_GROUP__ + Strings.nullToEmpty(secGroup.getSecurityGroupName())));
83         providerEpgBuilder.setDescription(new Description(MappingUtils.NEUTRON_GROUP__
84                 + Strings.nullToEmpty(secGroup.getSecurityGroupDescription())));
85         rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.endpointGroupIid(tenantId, providerEpgId),
86                 providerEpgBuilder.build(), true);
87         List<NeutronSecurityRule> secRules = secGroup.getSecurityRules();
88         SortedSecurityGroupRules sortedSecGrpRules = new SortedSecurityGroupRules(secRules);
89         ListMultimap<EndpointGroupId, NeutronSecurityRule> secRuleByRemoteSecGrpId = sortedSecGrpRules.secRuleByRemoteSecGrpId;
90         for (EndpointGroupId consumerEpgId : secRuleByRemoteSecGrpId.keySet()) {
91             addEpgIfMissing(tenantId, consumerEpgId, rwTx);
92             boolean areSecRulesAdded = addNeutronSecurityRule(secRuleByRemoteSecGrpId.get(consumerEpgId), rwTx);
93             if (!areSecRulesAdded) {
94                 return false;
95             }
96         }
97         ListMultimap<IpPrefix, NeutronSecurityRule> secRuleByRemoteIpPrefix = sortedSecGrpRules.secRuleByRemoteIpPrefix;
98         for (IpPrefix remoteIpPrefex : secRuleByRemoteIpPrefix.keySet()) {
99             boolean areSecRulesAdded = addNeutronSecurityRule(secRuleByRemoteIpPrefix.get(remoteIpPrefex), rwTx);
100             if (!areSecRulesAdded) {
101                 return false;
102             }
103         }
104         boolean areSecRulesAdded = addNeutronSecurityRule(sortedSecGrpRules.secRulesWithoutRemote, rwTx);
105         if (!areSecRulesAdded) {
106             return false;
107         }
108         return true;
109     }
110
111     public static void addEpgIfMissing(TenantId tenantId, EndpointGroupId epgId, ReadWriteTransaction rwTx) {
112         InstanceIdentifier<EndpointGroup> epgIid = IidFactory.endpointGroupIid(tenantId, epgId);
113         Optional<EndpointGroup> potentialConsumerEpg = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
114                 epgIid, rwTx);
115         if (!potentialConsumerEpg.isPresent()) {
116             EndpointGroup epg = new EndpointGroupBuilder().setId(epgId)
117                 .setName(new Name(MappingUtils.NEUTRON_GROUP__))
118                 .setDescription(new Description(MappingUtils.NEUTRON_GROUP__ + "EPG was created just based on remote group ID from a security rule."))
119                 .build();
120             rwTx.put(LogicalDatastoreType.CONFIGURATION, epgIid, epg);
121         }
122     }
123
124     private static boolean addNeutronSecurityRule(List<NeutronSecurityRule> secRules, ReadWriteTransaction rwTx) {
125         for (NeutronSecurityRule secRule : secRules) {
126             boolean isSecRuleAdded = NeutronSecurityRuleAware.addNeutronSecurityRule(secRule, rwTx);
127             if (!isSecRuleAdded) {
128                 return false;
129             }
130         }
131         return true;
132     }
133
134     /**
135      * @see org.opendaylight.neutron.spi.INeutronSecurityGroupAware#canUpdateNeutronSecurityGroup(org.opendaylight.neutron.spi.NeutronSecurityGroup,
136      *      org.opendaylight.neutron.spi.NeutronSecurityGroup)
137      */
138     @Override
139     public int canUpdateNeutronSecurityGroup(NeutronSecurityGroup delta, NeutronSecurityGroup original) {
140         LOG.warn("canUpdateNeutronSecurityGroup - Never should be called "
141                 + "- neutron API does not allow UPDATE on neutron security group. \nDelta: {} \nOriginal: {}", delta,
142                 original);
143         return StatusCode.BAD_REQUEST;
144     }
145
146     /**
147      * @see org.opendaylight.neutron.spi.INeutronSecurityGroupAware#neutronSecurityGroupUpdated(org.opendaylight.neutron.spi.NeutronSecurityGroup)
148      */
149     @Override
150     public void neutronSecurityGroupUpdated(NeutronSecurityGroup securityGroup) {
151         LOG.warn("neutronSecurityGroupUpdated - Never should be called "
152                 + "- neutron API does not allow UPDATE on neutron security group. \nSecurity group: {}", securityGroup);
153     }
154
155     /**
156      * @see org.opendaylight.neutron.spi.INeutronSecurityGroupAware#canDeleteNeutronSecurityGroup(org.opendaylight.neutron.spi.NeutronSecurityGroup)
157      */
158     @Override
159     public int canDeleteNeutronSecurityGroup(NeutronSecurityGroup securityGroup) {
160         LOG.trace("canDeleteNeutronSecurityGroup - {}", securityGroup);
161         // nothing to consider
162         return StatusCode.OK;
163     }
164
165     /**
166      * @see org.opendaylight.neutron.spi.INeutronSecurityGroupAware#neutronSecurityGroupDeleted(org.opendaylight.neutron.spi.NeutronSecurityGroup)
167      */
168     @Override
169     public void neutronSecurityGroupDeleted(NeutronSecurityGroup secGroup) {
170         LOG.trace("neutronSecurityGroupDeleted - {}", secGroup);
171         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
172         List<NeutronSecurityRule> secRules = secGroup.getSecurityRules();
173         if (secRules != null) {
174             boolean areSecRulesAdded = deleteNeutronSecurityRules(secRules, rwTx);
175             if (!areSecRulesAdded) {
176                 rwTx.cancel();
177                 return;
178             }
179         }
180         TenantId tenantId = new TenantId(Utils.normalizeUuid(secGroup.getSecurityGroupTenantID()));
181         EndpointGroupId epgId = new EndpointGroupId(secGroup.getSecurityGroupUUID());
182         Optional<EndpointGroup> potentialEpg = DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION,
183                 IidFactory.endpointGroupIid(tenantId, epgId), rwTx);
184         if (!potentialEpg.isPresent()) {
185             LOG.warn("Illegal state - Endpoint group {} does not exist.", epgId.getValue());
186             rwTx.cancel();
187             return;
188         }
189
190         DataStoreHelper.submitToDs(rwTx);
191     }
192
193     private boolean deleteNeutronSecurityRules(List<NeutronSecurityRule> secRules, ReadWriteTransaction rwTx) {
194         for (NeutronSecurityRule secRule : secRules) {
195             boolean isSecRuleDeleted = NeutronSecurityRuleAware.deleteNeutronSecurityRule(secRule, rwTx);
196             if (!isSecRuleDeleted) {
197                 return false;
198             }
199         }
200         return true;
201     }
202
203     private static final class SortedSecurityGroupRules {
204
205         private final ListMultimap<EndpointGroupId, NeutronSecurityRule> secRuleByRemoteSecGrpId;
206         private final ListMultimap<IpPrefix, NeutronSecurityRule> secRuleByRemoteIpPrefix;
207         private final List<NeutronSecurityRule> secRulesWithoutRemote;
208
209         private SortedSecurityGroupRules(List<NeutronSecurityRule> securityRules) {
210             Preconditions.checkNotNull(securityRules);
211             ListMultimap<EndpointGroupId, NeutronSecurityRule> tmpSecRuleByRemoteSecGrpId = ArrayListMultimap.create();
212             ListMultimap<IpPrefix, NeutronSecurityRule> tmpSecRuleByRemoteIpPrefix = ArrayListMultimap.create();
213             List<NeutronSecurityRule> tmpSecRulesWithoutRemote = new ArrayList<>();
214             for (NeutronSecurityRule securityRule : securityRules) {
215                 String remoteSecGroupId = securityRule.getSecurityRemoteGroupID();
216                 String remoteIpPrefix = securityRule.getSecurityRuleRemoteIpPrefix();
217                 boolean isRemoteSecGroupId = remoteSecGroupId != null && !"null".equals(remoteSecGroupId);
218                 boolean isRemoteIpPrefix = remoteIpPrefix != null && !"null".equals(remoteIpPrefix);
219                 if (isRemoteSecGroupId && isRemoteIpPrefix) {
220                     throw new IllegalArgumentException("Either remote group id or ip prefix "
221                             + "must be speciefied in neutron security group rule." + securityRule.toString());
222                 }
223                 if (isRemoteSecGroupId) {
224                     tmpSecRuleByRemoteSecGrpId.put(new EndpointGroupId(remoteSecGroupId), securityRule);
225                 } else if (isRemoteIpPrefix) {
226                     tmpSecRuleByRemoteIpPrefix.put(Utils.createIpPrefix(remoteIpPrefix), securityRule);
227                 } else {
228                     tmpSecRulesWithoutRemote.add(securityRule);
229                 }
230             }
231             secRuleByRemoteSecGrpId = ImmutableListMultimap.copyOf(tmpSecRuleByRemoteSecGrpId);
232             secRuleByRemoteIpPrefix = ImmutableListMultimap.copyOf(tmpSecRuleByRemoteIpPrefix);
233             secRulesWithoutRemote = ImmutableList.copyOf(tmpSecRulesWithoutRemote);
234         }
235     }
236
237 }