Fixes addressing test reports
[groupbasedpolicy.git] / neutron-mapper / src / main / java / org / opendaylight / groupbasedpolicy / neutron / mapper / mapping / rule / NeutronSecurityRuleAware.java
1 /*
2  * Copyright (c) 2014 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.neutron.mapper.mapping.rule;
10
11 import static com.google.common.base.Preconditions.checkNotNull;
12
13 import java.util.HashMap;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Set;
17 import java.util.stream.Collector;
18 import java.util.stream.Collectors;
19
20 import javax.annotation.Nonnull;
21
22 import org.opendaylight.controller.config.yang.config.neutron_mapper.impl.NeutronMapperModule;
23 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
24 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
25 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.groupbasedpolicy.api.sf.ChainActionDefinition;
28 import org.opendaylight.groupbasedpolicy.dto.EpgKeyDto;
29 import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.NeutronAware;
30 import org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.NeutronSecurityGroupAware;
31 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
32 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.SecurityGroupUtils;
33 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.SecurityRuleUtils;
34 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
35 import org.opendaylight.groupbasedpolicy.util.IidFactory;
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.common.rev140421.ActionName;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClauseName;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ParameterName;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SelectorName;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.change.action.of.security.group.rules.input.action.ActionChoice;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.change.action.of.security.group.rules.input.action.action.choice.SfcActionCase;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValueBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.Contract;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.endpoint.group.ConsumerNamedSelector;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.endpoint.group.ConsumerNamedSelectorBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.endpoint.group.ProviderNamedSelector;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.endpoint.group.ProviderNamedSelectorBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ActionInstance;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ActionInstanceBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ClassifierInstance;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.groups.attributes.security.groups.SecurityGroup;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.groups.attributes.security.groups.SecurityGroupKey;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.SecurityRules;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.security.rules.SecurityRule;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.security.rules.SecurityRuleKey;
63 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
66
67 import com.google.common.annotations.VisibleForTesting;
68 import com.google.common.base.Optional;
69 import com.google.common.base.Preconditions;
70 import com.google.common.collect.HashMultiset;
71 import com.google.common.collect.ImmutableList;
72 import com.google.common.collect.Multiset;
73 import com.google.common.collect.Sets;
74
75 public class NeutronSecurityRuleAware implements NeutronAware<SecurityRule> {
76
77     private static final Logger LOG = LoggerFactory.getLogger(NeutronSecurityRuleAware.class);
78     public static final InstanceIdentifier<SecurityRule> SECURITY_RULE_WILDCARD_IID =
79             InstanceIdentifier.builder(Neutron.class).child(SecurityRules.class).child(SecurityRule.class).build();
80     private static final String CONTRACT_PROVIDER = "Contract provider: ";
81     private final DataBroker dataProvider;
82     private final Multiset<InstanceIdentifier<ClassifierInstance>> createdClassifierInstances;
83     private final Multiset<InstanceIdentifier<ActionInstance>> createdActionInstances;
84     private final Map<SecurityRuleKey, SecurityRule> pendingCreatedRules;
85     private final Map<SecurityGroupKey, SecurityGroup> pendingDeletedGroups;
86     final static String PROVIDED_BY = "provided_by-";
87     final static String POSSIBLE_CONSUMER = "possible_consumer-";
88
89     public NeutronSecurityRuleAware(DataBroker dataProvider) {
90         this(dataProvider, HashMultiset.<InstanceIdentifier<ClassifierInstance>>create(),
91                 HashMultiset.<InstanceIdentifier<ActionInstance>>create());
92     }
93
94     @VisibleForTesting
95     NeutronSecurityRuleAware(DataBroker dataProvider,
96             Multiset<InstanceIdentifier<ClassifierInstance>> classifierInstanceNames,
97             Multiset<InstanceIdentifier<ActionInstance>> createdActionInstances) {
98         this.dataProvider = checkNotNull(dataProvider);
99         this.createdClassifierInstances = checkNotNull(classifierInstanceNames);
100         this.createdActionInstances = checkNotNull(createdActionInstances);
101         this.pendingCreatedRules = new HashMap<>();
102         this.pendingDeletedGroups = new HashMap<>();
103     }
104
105     @Override
106     public void onCreated(SecurityRule secRule, Neutron neutron) {
107         LOG.trace("created securityRule - {}", secRule);
108         if (neutron.getSecurityGroups() == null || neutron.getSecurityGroups().getSecurityGroup() == null
109                 || !neutron.getSecurityGroups()
110                     .getSecurityGroup()
111                     .stream()
112                     .filter(sg -> sg.getKey().getUuid().equals(secRule.getSecurityGroupId()))
113                     .findFirst()
114                     .isPresent()) {
115             pendingCreatedRules.put(secRule.getKey(), secRule);
116             LOG.warn("Security group of security rule {} does not exist yet. The rule will be processed"
117                     + "when the missing security group is created.", secRule.getKey());
118             return;
119         }
120         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
121         boolean isNeutronSecurityRuleAdded = addNeutronSecurityRule(secRule, neutron, rwTx);
122         if (isNeutronSecurityRuleAdded) {
123             DataStoreHelper.submitToDs(rwTx);
124         } else {
125             rwTx.cancel();
126         }
127     }
128
129     public void flushPendingSecurityRulesFor(@Nonnull SecurityGroupKey secGroupKey, Neutron neutron) {
130         List<SecurityRule> rules = pendingCreatedRules.values()
131             .stream()
132             .filter(sr -> sr.getSecurityGroupId().equals(secGroupKey.getUuid()))
133             .collect(Collectors.toList());
134         rules.forEach(sr -> {
135             LOG.trace("Flushing pending security rule {}", sr);
136             ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
137             boolean isNeutronSecurityRuleAdded = addNeutronSecurityRule(sr, neutron, rwTx);
138             if (isNeutronSecurityRuleAdded) {
139                 DataStoreHelper.submitToDs(rwTx);
140             } else {
141                 rwTx.cancel();
142             }
143             pendingCreatedRules.remove(sr.getKey());
144         });
145     }
146
147     public boolean addNeutronSecurityRule(SecurityRule secRule, Neutron neutron, ReadWriteTransaction rwTx) {
148         return addNeutronSecurityRuleWithAction(secRule, neutron, MappingUtils.ALLOW_ACTION_CHOICE, rwTx);
149     }
150
151     public boolean addNeutronSecurityRuleWithAction(SecurityRule secRule, Neutron neutron, ActionChoice action,
152             ReadWriteTransaction rwTx) {
153         TenantId tenantId = new TenantId(secRule.getTenantId().getValue());
154         Uuid providerSecGroupId = secRule.getSecurityGroupId();
155         EndpointGroupId providerEpgId = new EndpointGroupId(providerSecGroupId.getValue());
156
157         Description contractDescription = createContractDescription(secRule, neutron);
158         SingleRuleContract singleRuleContract = createSingleRuleContract(secRule, contractDescription, action);
159         Contract contract = singleRuleContract.getContract();
160         rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.contractIid(tenantId, contract.getId()), contract, true);
161         SelectorName providerSelector = getSelectorNameWithConsumer(secRule, neutron);
162         writeProviderNamedSelectorToEpg(providerSelector, contract.getId(), new EpgKeyDto(providerEpgId, tenantId), rwTx);
163
164         if (secRule.getRemoteGroupId() != null) {
165             Uuid consumerSecGroupId = secRule.getRemoteGroupId();
166             designContractsBetweenProviderAndConsumer(tenantId, providerSecGroupId, consumerSecGroupId, neutron, rwTx);
167             designContractsBetweenProviderAndConsumer(tenantId, consumerSecGroupId, providerSecGroupId, neutron, rwTx);
168         } else {
169             for (Uuid consumerSecGroupId : SecurityRuleUtils.findSecurityGroupsHavingSecurityRules(neutron)) {
170                 designContractsBetweenProviderAndConsumer(tenantId, providerSecGroupId, consumerSecGroupId, neutron, rwTx);
171                 designContractsBetweenProviderAndConsumer(tenantId, consumerSecGroupId, providerSecGroupId, neutron, rwTx);
172             }
173         }
174
175         ClassifierInstance classifierInstance = singleRuleContract.getSingleClassifierRule().getClassifierInstance();
176         createClassifierInstanceIfNotExists(tenantId, classifierInstance, rwTx);
177         createAllowActionInstanceIfNotExists(tenantId, rwTx);
178         return true;
179     }
180
181     @VisibleForTesting
182     static Description createContractDescription(SecurityRule secRule, Neutron neutron) {
183         if (NeutronMapperModule.isDebugEnabled()) {
184             Optional<SecurityGroup> providerSecGroup =
185                     SecurityGroupUtils.findSecurityGroup(secRule.getSecurityGroupId(), neutron.getSecurityGroups());
186             if (!providerSecGroup.isPresent()) {
187                 LOG.error("Neutron Security Group with UUID {} does not exist but it is in {}", secRule.getSecurityGroupId().getValue(),
188                         secRule);
189                 throw new IllegalStateException(
190                         "Neutron Security Group with UUID " + secRule.getSecurityGroupId().getValue() + " does not exist.");
191             }
192             return new Description(CONTRACT_PROVIDER + SecurityGroupUtils.getNameOrUuid(providerSecGroup.get()));
193         }
194
195         return new Description(CONTRACT_PROVIDER + secRule.getSecurityGroupId());
196     }
197
198     @VisibleForTesting
199     static SingleRuleContract createSingleRuleContract(SecurityRule secRule, Description contractDescription, ActionChoice action) {
200         if (secRule.getRemoteIpPrefix() != null) {
201             return new SingleRuleContract(secRule, 0, contractDescription, action);
202         }
203         return new SingleRuleContract(secRule, 400, contractDescription, action);
204     }
205
206     @VisibleForTesting
207     void designContractsBetweenProviderAndConsumer(TenantId tenantId, Uuid provSecGroupId, Uuid consSecGroupId,
208             Neutron neutron, ReadWriteTransaction rwTx) {
209         Set<SecurityRule> provSecRules = getProvidedSecRulesBetween(provSecGroupId, consSecGroupId, neutron);
210         Set<SecurityRule> consSecRules = getProvidedSecRulesBetween(consSecGroupId, provSecGroupId, neutron);
211         EndpointGroupId consEpgId = new EndpointGroupId(consSecGroupId.getValue());
212         for (SecurityRule provSecRule : provSecRules) {
213             if (isProviderSecRuleSuitableForConsumerSecRules(provSecRule, consSecRules)) {
214                 SelectorName consumerSelector = getSelectorNameWithProvider(provSecRule, neutron);
215                 ContractId contractId = SecRuleEntityDecoder.getContractId(provSecRule);
216                 writeConsumerNamedSelectorToEpg(consumerSelector, contractId, new EpgKeyDto(consEpgId, tenantId), rwTx);
217             }
218             // TODO add case when port ranges overlap
219         }
220     }
221
222     @VisibleForTesting
223     Set<SecurityRule> getProvidedSecRulesBetween(Uuid provSecGroup, Uuid consSecGroup, Neutron neutron) {
224         return Sets.union(SecurityRuleUtils.findSecurityRulesBySecGroupAndRemoteSecGroup(provSecGroup, consSecGroup, neutron),
225                 SecurityRuleUtils.findSecurityRulesBySecGroupAndRemoteSecGroup(provSecGroup, null, neutron));
226     }
227
228     @VisibleForTesting
229     static boolean isProviderSecRuleSuitableForConsumerSecRules(SecurityRule provSecRule,
230             Set<SecurityRule> consSecRules) {
231         Direction directionProvSecRule = SecRuleEntityDecoder.getDirection(provSecRule);
232         for (SecurityRule consSecRule : consSecRules) {
233             Direction directionConsSecRule = SecRuleEntityDecoder.getDirection(consSecRule);
234             if (isDirectionOpposite(directionProvSecRule, directionConsSecRule)
235                     && isOneWithinTwo(provSecRule, consSecRule)) {
236                 return true;
237             }
238         }
239         return false;
240     }
241
242     public boolean changeActionOfNeutronSecurityRule(SecurityRule secRule, ActionChoice action, Neutron neutron, ReadWriteTransaction rwTx) {
243         addSfcChainActionInstance(action, new TenantId(secRule.getTenantId().getValue()), rwTx);
244         LOG.trace("Changing to action {} for secuirity group rule {}", action, secRule);
245         return addNeutronSecurityRuleWithAction(secRule, neutron, action, rwTx);
246     }
247
248     private void addSfcChainActionInstance(ActionChoice action, TenantId tenantId, ReadWriteTransaction rwTx) {
249         if (action instanceof SfcActionCase) {
250             String sfcChainName = ((SfcActionCase) action).getSfcChainName();
251             ActionName actionName = new ActionName(sfcChainName);
252             ActionInstance sfcActionInstance = new ActionInstanceBuilder().setName(actionName)
253                 .setActionDefinitionId(ChainActionDefinition.ID)
254                 .setParameterValue(
255                         ImmutableList.of(new ParameterValueBuilder().setName(
256                                 new ParameterName(ChainActionDefinition.SFC_CHAIN_NAME))
257                             .setStringValue(sfcChainName)
258                             .build()))
259                 .build();
260             rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.actionInstanceIid(tenantId, actionName),
261                     sfcActionInstance, true);
262         }
263     }
264
265     private void writeProviderNamedSelectorToEpg(SelectorName providerSelector, ContractId contractId, EpgKeyDto epgKey,
266             WriteTransaction wTx) {
267         ProviderNamedSelector providerNamedSelector = new ProviderNamedSelectorBuilder().setName(providerSelector)
268             .setContract(ImmutableList.of(contractId))
269             .build();
270         wTx.put(LogicalDatastoreType.CONFIGURATION,
271                 IidFactory.providerNamedSelectorIid(epgKey.getTenantId(), epgKey.getEpgId(),
272                         providerNamedSelector.getName()), providerNamedSelector, true);
273     }
274
275     private void writeConsumerNamedSelectorToEpg(SelectorName consumerSelector, ContractId contractId, EpgKeyDto epgKey,
276             WriteTransaction wTx) {
277         ConsumerNamedSelector consumerNamedSelector = new ConsumerNamedSelectorBuilder().setName(consumerSelector)
278             .setContract(ImmutableList.of(contractId))
279             .build();
280         wTx.put(LogicalDatastoreType.CONFIGURATION,
281                 IidFactory.consumerNamedSelectorIid(epgKey.getTenantId(), epgKey.getEpgId(),
282                         consumerNamedSelector.getName()), consumerNamedSelector, true);
283     }
284
285     @VisibleForTesting
286     void createClassifierInstanceIfNotExists(TenantId tenantId, ClassifierInstance classifierInstance,
287             WriteTransaction wTx) {
288         InstanceIdentifier<ClassifierInstance> classifierInstanceIid = IidFactory.classifierInstanceIid(tenantId,
289                 classifierInstance.getName());
290         if (!createdClassifierInstances.contains(classifierInstanceIid)) {
291             wTx.put(LogicalDatastoreType.CONFIGURATION, classifierInstanceIid, classifierInstance, true);
292         }
293         createdClassifierInstances.add(classifierInstanceIid);
294     }
295
296     @VisibleForTesting
297     void createAllowActionInstanceIfNotExists(TenantId tenantId, ReadWriteTransaction rwTx) {
298         InstanceIdentifier<ActionInstance> actionInstanceIid = IidFactory.actionInstanceIid(tenantId,
299                 MappingUtils.ACTION_ALLOW.getName());
300         if (!createdActionInstances.contains(actionInstanceIid)) {
301             rwTx.put(LogicalDatastoreType.CONFIGURATION, actionInstanceIid, MappingUtils.ACTION_ALLOW, true);
302         }
303         createdActionInstances.add(actionInstanceIid);
304     }
305
306     @Override
307     public void onUpdated(SecurityRule oldSecRule, SecurityRule newSecRule, Neutron oldNeutron, Neutron newNeutron) {
308         LOG.warn("updated securityRule - Never should be called "
309                 + "- neutron API does not allow UPDATE on neutron security group rule. \nSecurity group rule: {}",
310                 newSecRule);
311     }
312
313     public void addPendingDeletedSecGroup(SecurityGroup secGroup) {
314         LOG.trace("Caching pending deleted security group {}", secGroup.getKey());
315         pendingDeletedGroups.put(secGroup.getKey(), secGroup);
316     }
317
318     @Override
319     public void onDeleted(SecurityRule deletedSecRule, Neutron oldNeutron, Neutron newNeutron) {
320         LOG.trace("deleted securityRule - {}", deletedSecRule);
321         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
322         boolean isNeutronSecurityRuleDeleted = deleteNeutronSecurityRule(deletedSecRule, oldNeutron, rwTx);
323         if (isNeutronSecurityRuleDeleted) {
324             DataStoreHelper.submitToDs(rwTx);
325             if (newNeutron == null || newNeutron.getSecurityRules() == null
326                 || newNeutron.getSecurityRules().getSecurityRule() == null
327                 || !newNeutron.getSecurityRules()
328                         .getSecurityRule()
329                         .stream()
330                         .filter(rule -> rule.getSecurityGroupId().equals(deletedSecRule.getSecurityGroupId()))
331                         .findAny()
332                         .isPresent()) {
333                 SecurityGroupKey secGroupKey = new SecurityGroupKey(deletedSecRule.getSecurityGroupId());
334                 SecurityGroup pendingSg = pendingDeletedGroups.get(secGroupKey);
335                 if (pendingSg != null) {
336                     LOG.trace("Processing pending deleted security group {}", secGroupKey);
337                     NeutronSecurityGroupAware.deleteGbpEndpointGroup(dataProvider,
338                             new TenantId(deletedSecRule.getTenantId().getValue()),
339                             new EndpointGroupId(secGroupKey.getUuid().getValue()));
340                     pendingDeletedGroups.remove(secGroupKey);
341                 }
342             }
343         } else {
344             rwTx.cancel();
345         }
346     }
347
348     public boolean deleteNeutronSecurityRule(SecurityRule secRule, Neutron neutron, ReadWriteTransaction rwTx) {
349         TenantId tenantId = new TenantId(secRule.getTenantId().getValue());
350         Uuid providerSecGroupId = secRule.getSecurityGroupId();
351         EndpointGroupId providerEpgId = new EndpointGroupId(providerSecGroupId.getValue());
352
353         SelectorName providerSelector = getSelectorNameWithConsumer(secRule, neutron);
354         deleteProviderNamedSelectorFromEpg(providerSelector, new EpgKeyDto(providerEpgId, tenantId), rwTx);
355
356         if (secRule.getRemoteGroupId() != null) {
357             Uuid consumerSecGroupId = secRule.getRemoteGroupId();
358             undesignContractsBetweenProviderAndConsumer(tenantId, providerSecGroupId, consumerSecGroupId, secRule, neutron, rwTx);
359             undesignContractsBetweenProviderAndConsumer(tenantId, consumerSecGroupId, providerSecGroupId, secRule, neutron, rwTx);
360         } else {
361             for (Uuid consumerSecGroupId : SecurityRuleUtils.findSecurityGroupsHavingSecurityRules(neutron)) {
362                 undesignContractsBetweenProviderAndConsumer(tenantId, providerSecGroupId, consumerSecGroupId, secRule, neutron, rwTx);
363                 undesignContractsBetweenProviderAndConsumer(tenantId, consumerSecGroupId, providerSecGroupId, secRule, neutron, rwTx);
364             }
365         }
366
367         ContractId contractId = SecRuleEntityDecoder.getContractId(secRule);
368         rwTx.delete(LogicalDatastoreType.CONFIGURATION, IidFactory.contractIid(tenantId, contractId));
369
370         ClassifierInstance classifierInstance = SecRuleEntityDecoder.getClassifierInstance(secRule);
371         deleteClassifierInstanceIfNotUsed(tenantId, classifierInstance, rwTx);
372         return true;
373     }
374
375     @VisibleForTesting
376     void undesignContractsBetweenProviderAndConsumer(TenantId tenantId, Uuid provSecGroupId,
377             Uuid consSecGroupId, SecurityRule removedSecRule, Neutron neutron, ReadWriteTransaction rwTx) {
378         Set<SecurityRule> provSecRules = getProvidedSecRulesBetween(provSecGroupId, consSecGroupId, neutron);
379         Set<SecurityRule> consSecRules = getProvidedSecRulesBetween(consSecGroupId, provSecGroupId, neutron);
380         EndpointGroupId consEpgId = new EndpointGroupId(consSecGroupId.getValue());
381         for (SecurityRule provSecRule : provSecRules) {
382             if (isProvidersSecRuleSuitableForConsumersSecRulesAndGoodToRemove(provSecRule, consSecRules, removedSecRule)) {
383                 SelectorName consumerSelector = getSelectorNameWithProvider(provSecRule, neutron);
384                 deleteConsumerNamedSelector(consumerSelector, new EpgKeyDto(consEpgId, tenantId), rwTx);
385             }
386             // TODO add case when port ranges overlap
387         }
388     }
389
390     @VisibleForTesting
391     static boolean isProvidersSecRuleSuitableForConsumersSecRulesAndGoodToRemove(SecurityRule provSecRule,
392             Set<SecurityRule> consSecRules, SecurityRule removedSecRule) {
393         Direction directionProvSecRule = SecRuleEntityDecoder.getDirection(provSecRule);
394         for (SecurityRule consSecRule : consSecRules) {
395             if (isRuleIdEqual(removedSecRule, consSecRule) || isRuleIdEqual(removedSecRule, provSecRule)) {
396                 Direction directionConsSecRule = SecRuleEntityDecoder.getDirection(consSecRule);
397                 if (isDirectionOpposite(directionProvSecRule, directionConsSecRule)
398                         && isOneWithinTwo(provSecRule, consSecRule)) {
399                     return true;
400                 }
401             }
402         }
403         return false;
404     }
405
406     @VisibleForTesting
407     static boolean isRuleIdEqual(SecurityRule one, SecurityRule two) {
408         checkNotNull(one);
409         checkNotNull(two);
410         return one.getSecurityGroupId().equals(two.getSecurityGroupId());
411     }
412
413     private void deleteProviderNamedSelectorFromEpg(SelectorName providerSelector, EpgKeyDto providerEpgKey,
414             ReadWriteTransaction rwTx) {
415         InstanceIdentifier<ProviderNamedSelector> providerSelectorIid = IidFactory.providerNamedSelectorIid(
416                 providerEpgKey.getTenantId(), providerEpgKey.getEpgId(), providerSelector);
417         DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION, providerSelectorIid, rwTx);
418     }
419
420     private void deleteConsumerNamedSelector(SelectorName consumerSelector, EpgKeyDto consumerEpgKey,
421             ReadWriteTransaction rwTx) {
422         InstanceIdentifier<ConsumerNamedSelector> consumerSelectorIid = IidFactory.consumerNamedSelectorIid(
423                 consumerEpgKey.getTenantId(), consumerEpgKey.getEpgId(), consumerSelector);
424         DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION, consumerSelectorIid, rwTx);
425     }
426
427     private void deleteClassifierInstanceIfNotUsed(TenantId tenantId, ClassifierInstance classifierInstance,
428             ReadWriteTransaction rwTx) {
429         InstanceIdentifier<ClassifierInstance> classifierInstanceIid = IidFactory.classifierInstanceIid(tenantId,
430                 classifierInstance.getName());
431         createdClassifierInstances.remove(classifierInstanceIid);
432         if (!createdClassifierInstances.contains(classifierInstanceIid)) {
433             DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION, classifierInstanceIid, rwTx);
434         }
435     }
436
437     @VisibleForTesting
438     void deleteAllowActionInstanceIfNotUsed(TenantId tenantId, ReadWriteTransaction rwTx) {
439         InstanceIdentifier<ActionInstance> actionInstanceIid = IidFactory.actionInstanceIid(tenantId,
440                 MappingUtils.ACTION_ALLOW.getName());
441         createdActionInstances.remove(actionInstanceIid);
442         if (!createdActionInstances.contains(actionInstanceIid)) {
443             DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION, actionInstanceIid, rwTx);
444         }
445     }
446
447     private SelectorName getSelectorNameWithConsumer(SecurityRule secRule, Neutron neutron) {
448         ClauseName clauseName = SecRuleNameDecoder.getClauseName(secRule);
449         StringBuilder selectorNameBuilder = new StringBuilder().append(clauseName.getValue());
450         Uuid consumerSecGroupId = secRule.getRemoteGroupId();
451         if (consumerSecGroupId == null) {
452             return new SelectorName(selectorNameBuilder.toString());
453         }
454
455         // we cannot use name of security group in selector, because name can be changed
456         // therefore name is used only in debug mode
457         if (NeutronMapperModule.isDebugEnabled()) {
458             Optional<SecurityGroup> potentialConsumerSecGroup =
459                     SecurityGroupUtils.findSecurityGroup(secRule.getRemoteGroupId(), neutron.getSecurityGroups());
460             if (!potentialConsumerSecGroup.isPresent()) {
461                 LOG.error("Neutron Security Group with UUID {} does not exist but it is in {}",
462                         consumerSecGroupId.getValue(), secRule);
463                 throw new IllegalStateException(
464                         "Neutron Security Group with UUID " + consumerSecGroupId.getValue() + " does not exist.");
465             }
466
467             selectorNameBuilder.append(MappingUtils.NAME_DOUBLE_DELIMETER)
468                 .append(POSSIBLE_CONSUMER)
469                 .append(SecurityGroupUtils.getNameOrUuid(potentialConsumerSecGroup.get()));
470             return new SelectorName(selectorNameBuilder.toString());
471         }
472
473         selectorNameBuilder.append(MappingUtils.NAME_DOUBLE_DELIMETER)
474             .append(POSSIBLE_CONSUMER)
475             .append(consumerSecGroupId.getValue());
476         return new SelectorName(selectorNameBuilder.toString());
477     }
478
479     private SelectorName getSelectorNameWithProvider(SecurityRule secRule, Neutron neutron) {
480         ClauseName clauseName = SecRuleNameDecoder.getClauseName(secRule);
481         Uuid providerSecGroupId = secRule.getSecurityGroupId();
482
483         // we cannot use name of security group in selector, because name can be changed
484         // therefore name is used only in debug mode
485         if (NeutronMapperModule.isDebugEnabled()) {
486             Optional<SecurityGroup> potentialProviderSecGroup =
487                     SecurityGroupUtils.findSecurityGroup(secRule.getSecurityGroupId(), neutron.getSecurityGroups());
488             if (!potentialProviderSecGroup.isPresent()) {
489                 LOG.error("Neutron Security Group with UUID {} does not exist but it is in {}",
490                         providerSecGroupId.getValue(), secRule);
491                 throw new IllegalStateException(
492                         "Neutron Security Group with UUID " + providerSecGroupId.getValue() + " does not exist.");
493             }
494             String selectorName = new StringBuilder().append(clauseName.getValue())
495                 .append(MappingUtils.NAME_DOUBLE_DELIMETER)
496                 .append(PROVIDED_BY)
497                 .append(SecurityGroupUtils.getNameOrUuid(potentialProviderSecGroup.get()))
498                 .toString();
499             return new SelectorName(selectorName);
500         }
501
502         String selectorName = new StringBuilder().append(clauseName.getValue())
503             .append(MappingUtils.NAME_DOUBLE_DELIMETER)
504             .append(PROVIDED_BY)
505             .append(providerSecGroupId.getValue())
506             .toString();
507         return new SelectorName(selectorName);
508     }
509
510     @VisibleForTesting
511     static boolean isDirectionOpposite(Direction one, Direction two) {
512         return (one == Direction.In && two == Direction.Out) || (one == Direction.Out && two == Direction.In);
513     }
514
515     @VisibleForTesting
516     static boolean isOneWithinTwo(SecurityRule one, SecurityRule two) {
517         if (!isOneGroupIdWithinTwoRemoteGroupId(one, two) || !isOneGroupIdWithinTwoRemoteGroupId(two, one))
518             return false;
519         if (!SecRuleEntityDecoder.isEtherTypeOfOneWithinTwo(one, two))
520             return false;
521         if (!SecRuleEntityDecoder.isProtocolOfOneWithinTwo(one, two))
522             return false;
523         if (!SecRuleEntityDecoder.isPortsOfOneWithinTwo(one, two))
524             return false;
525         if (two.getRemoteIpPrefix() != null
526                 && one.getRemoteIpPrefix() == null)
527             return false;
528         return true;
529     }
530
531     @VisibleForTesting
532     static boolean isOneGroupIdWithinTwoRemoteGroupId(SecurityRule one, SecurityRule two) {
533         return (two.getRemoteGroupId() == null || two.getRemoteGroupId().equals(
534                 one.getSecurityGroupId()));
535     }
536
537 }