f39c1bf7339e5747dd4e746eead4298aba1dc32b
[groupbasedpolicy.git] / neutron-mapper / src / main / java / org / opendaylight / groupbasedpolicy / neutron / mapper / mapping / NeutronSecurityRuleAware.java
1 package org.opendaylight.groupbasedpolicy.neutron.mapper.mapping;
2
3 import static com.google.common.base.Preconditions.checkNotNull;
4
5 import java.util.UUID;
6
7 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
8 import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
9 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
10 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
11 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
12 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
13 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.NeutronMapperIidFactory;
14 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
15 import org.opendaylight.groupbasedpolicy.util.IidFactory;
16 import org.opendaylight.neutron.spi.INeutronSecurityRuleAware;
17 import org.opendaylight.neutron.spi.NeutronSecurityRule;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierName;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClauseName;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.RuleName;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SelectorName;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubjectName;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.mapper.rev150223.mappings.endpoint.group.pair.to.contract.mappings.EndpointGroupPairToContractMapping;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.mapper.rev150223.mappings.endpoint.group.pair.to.contract.mappings.EndpointGroupPairToContractMappingBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Contract;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.ContractBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup.IntraGroupPolicy;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroupBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.Clause;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.Subject;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.contract.subject.Rule;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ConsumerNamedSelector;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ConsumerNamedSelectorBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ProviderNamedSelector;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.endpoint.group.ProviderNamedSelectorBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ClassifierInstance;
43 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 import com.google.common.base.Optional;
48 import com.google.common.collect.ImmutableList;
49
50 public class NeutronSecurityRuleAware implements INeutronSecurityRuleAware {
51
52     private static final Logger LOG = LoggerFactory.getLogger(NeutronSecurityRuleAware.class);
53     private final DataBroker dataProvider;
54
55     public NeutronSecurityRuleAware(DataBroker dataProvider) {
56         this.dataProvider = checkNotNull(dataProvider);
57     }
58
59     @Override
60     public int canCreateNeutronSecurityRule(NeutronSecurityRule securityRule) {
61         LOG.trace("canCreateNeutronSecurityRule - {}", securityRule);
62         // nothing to consider
63         return StatusCode.OK;
64     }
65
66     @Override
67     public void neutronSecurityRuleCreated(NeutronSecurityRule securityRule) {
68         LOG.trace("neutronSecurityRuleCreated - {}", securityRule);
69         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
70         boolean isNeutronSecurityRuleAdded = addNeutronSecurityRule(securityRule, rwTx);
71         if (isNeutronSecurityRuleAdded) {
72             DataStoreHelper.submitToDs(rwTx);
73         } else {
74             rwTx.cancel();
75         }
76     }
77
78     /**
79      * <b>ASSUMPTION</b>: Endpoint group with id
80      * {@link NeutronSecurityRule#getSecurityRuleGroupID()} and
81      * endpoint group with id {@link NeutronSecurityRule#getSecurityRemoteGroupID()} already exist
82      * in transaction.
83      *
84      * @param secRule neutron security rule from which GBP entities are created
85      * @param rwTx GBP entities are stored to this transaction. This method NEVER submits or cancel
86      *        the transaction.
87      * @return {@code true} if operation was successful; {@code false} if an illegal state occurs -
88      *         the transaction may contain just partial result
89      */
90     public static boolean addNeutronSecurityRule(NeutronSecurityRule secRule, ReadWriteTransaction rwTx) {
91         TransformSecRule transform = new TransformSecRule(secRule);
92         TenantId tenantId = transform.getTenantId();
93         EndpointGroupId providerEpgId = transform.getProviderEpgId();
94         EndpointGroupId consumerEpgId = transform.getConsumerEpgId();
95         SubjectName subjectName = transform.getSubjectName();
96
97         Optional<ContractId> potentialContractId = readContractIdFromEpgPairToContractMapping(providerEpgId,
98                 consumerEpgId, rwTx);
99         ContractId contractId = null;
100         if (potentialContractId.isPresent()) {
101             contractId = potentialContractId.get();
102             Optional<Subject> potentialSubject = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
103                     IidFactory.subjectIid(tenantId, contractId, subjectName), rwTx);
104             if (!potentialSubject.isPresent()) {
105                 // it also means that clause for this subject does not exist
106                 rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.subjectIid(tenantId, contractId, subjectName),
107                         transform.createSubject());
108                 rwTx.put(LogicalDatastoreType.CONFIGURATION,
109                         IidFactory.clauseIid(tenantId, contractId, transform.getClauseName()), transform.createClause());
110             }
111         } else {
112             // check assumption that provider EPG exists
113             Optional<EndpointGroup> potentialProviderEpg = DataStoreHelper.readFromDs(
114                     LogicalDatastoreType.CONFIGURATION, IidFactory.endpointGroupIid(tenantId, providerEpgId), rwTx);
115             if (!potentialProviderEpg.isPresent()) {
116                 LOG.warn("Illegal state - Endpoint group {} does not exist.", providerEpgId.getValue());
117                 return false;
118             }
119
120             if (providerEpgId.equals(consumerEpgId)) {
121                 EndpointGroup providerConsumerEpg = potentialProviderEpg.get();
122                 if (providerConsumerEpg.getIntraGroupPolicy() == null
123                         || !providerConsumerEpg.getIntraGroupPolicy().equals(IntraGroupPolicy.RequireContract)) {
124                     EndpointGroup newProviderConsumerEpg = new EndpointGroupBuilder(providerConsumerEpg).setIntraGroupPolicy(
125                             IntraGroupPolicy.RequireContract)
126                         .build();
127                     rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.endpointGroupIid(tenantId, providerEpgId),
128                             newProviderConsumerEpg);
129                 }
130             } else {
131                 Optional<EndpointGroup> potentialConsumerEpg = DataStoreHelper.readFromDs(
132                         LogicalDatastoreType.CONFIGURATION, IidFactory.endpointGroupIid(tenantId, consumerEpgId), rwTx);
133                 if (!potentialConsumerEpg.isPresent()) {
134                     if (MappingUtils.EPG_ANY_ID.equals(consumerEpgId)) {
135                         EndpointGroup epgAny = createEpgAny();
136                         rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.endpointGroupIid(tenantId, MappingUtils.EPG_ANY_ID),
137                                 epgAny);
138                     } else {
139                         LOG.warn("Illegal state - Endpoint group {} does not exist.", consumerEpgId.getValue());
140                         return false;
141                     }
142                 }
143             }
144             // creates and stores contract with clause and subject
145             Subject subject = transform.createSubject();
146             Clause clause = transform.createClause();
147             Contract contract = createContract(clause, subject);
148             contractId = contract.getId();
149             rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.contractIid(tenantId, contractId), contract);
150             putEpgPairToContractMapping(providerEpgId, consumerEpgId, contractId, rwTx);
151
152             // adds provider and consumer named selectors
153             ProviderNamedSelector providerSelector = createProviderNamedSelector(contractId);
154             rwTx.put(LogicalDatastoreType.CONFIGURATION,
155                     IidFactory.providerNamedSelectorIid(tenantId, providerEpgId, providerSelector.getName()),
156                     providerSelector);
157             ConsumerNamedSelector consumerSelector = createConsumerNamedSelector(contractId);
158             rwTx.put(LogicalDatastoreType.CONFIGURATION,
159                     IidFactory.consumerNamedSelectorIid(tenantId, consumerEpgId, consumerSelector.getName()),
160                     consumerSelector);
161         }
162
163         // create classifier-instance
164         ClassifierName classifierName = transform.getClassifierName();
165         ClassifierInstance classifier = transform.createClassifier();
166         rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.classifierInstanceIid(tenantId, classifierName),
167                 classifier, true);
168         // create action-instance if it does not exist yet
169         Optional<ActionInstance> potentialAction = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
170                 IidFactory.actionInstanceIid(tenantId, MappingUtils.ACTION_ALLOW.getName()), rwTx);
171         if (!potentialAction.isPresent()) {
172             rwTx.put(LogicalDatastoreType.CONFIGURATION,
173                     IidFactory.actionInstanceIid(tenantId, MappingUtils.ACTION_ALLOW.getName()),
174                     MappingUtils.ACTION_ALLOW, true);
175         }
176
177         // create rule
178         Rule rule = transform.createRule(0);
179         rwTx.put(LogicalDatastoreType.CONFIGURATION,
180                 IidFactory.ruleIid(tenantId, contractId, subjectName, rule.getName()), rule);
181         return true;
182     }
183
184     private static EndpointGroup createEpgAny() {
185         return new EndpointGroupBuilder().setId(MappingUtils.EPG_ANY_ID)
186                 .setDescription(new Description(MappingUtils.NEUTRON_RULE__ + "epg_any"))
187                 .setIntraGroupPolicy(IntraGroupPolicy.RequireContract)
188                 .build();
189     }
190
191     @Override
192     public int canUpdateNeutronSecurityRule(NeutronSecurityRule delta, NeutronSecurityRule original) {
193         LOG.warn("canUpdateNeutronSecurityRule - Never should be called "
194                 + "- neutron API does not allow UPDATE on neutron security group rule. \nDelta: {} \nOriginal: {}",
195                 delta, original);
196         return StatusCode.BAD_REQUEST;
197     }
198
199     @Override
200     public void neutronSecurityRuleUpdated(NeutronSecurityRule securityRule) {
201         LOG.warn("neutronSecurityRuleUpdated - Never should be called "
202                 + "- neutron API does not allow UPDATE on neutron security group rule. \nSecurity group rule: {}",
203                 securityRule);
204     }
205
206     @Override
207     public int canDeleteNeutronSecurityRule(NeutronSecurityRule securityRule) {
208         LOG.trace("canDeleteNeutronSecurityRule - {}", securityRule);
209         // nothing to consider
210         return StatusCode.OK;
211     }
212
213     @Override
214     public void neutronSecurityRuleDeleted(NeutronSecurityRule secRule) {
215         LOG.trace("neutronSecurityRuleCreated - {}", secRule);
216         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
217         boolean isNeutronSecurityRuleDelete = deleteNeutronSecurityRule(secRule, rwTx);
218         if (isNeutronSecurityRuleDelete) {
219             DataStoreHelper.submitToDs(rwTx);
220         } else {
221             DataStoreHelper.submitToDs(rwTx);
222         }
223     }
224
225     /**
226      * @param secRule neutron security rule from which GBP entities are deleted
227      * @param rwTx GBP entities are stored to this transaction. This method NEVER submits or cancel
228      *        the transaction.
229      * @return {@code true} if operation was successful; {@code false} if an illegal state occurs -
230      *         the transaction may contain just partial result
231      */
232     public static boolean deleteNeutronSecurityRule(NeutronSecurityRule secRule, ReadWriteTransaction rwTx) {
233         TransformSecRule transform = new TransformSecRule(secRule);
234         TenantId tenantId = transform.getTenantId();
235         EndpointGroupId providerEpgId = transform.getProviderEpgId();
236         EndpointGroupId consumerEpgId = transform.getConsumerEpgId();
237
238         Optional<ContractId> potentialContractId = readContractIdFromEpgPairToContractMapping(providerEpgId,
239                 consumerEpgId, rwTx);
240         if (!potentialContractId.isPresent()) {
241             LOG.warn("Illegal state - mapping EPG pair (provider EPG {} consumer EPG {}) does not exist.",
242                     providerEpgId.getValue(), consumerEpgId.getValue());
243             return false;
244         }
245
246         ContractId contractId = potentialContractId.get();
247         ClassifierName classifierName = transform.getClassifierName();
248         InstanceIdentifier<ClassifierInstance> classifierIid = IidFactory.classifierInstanceIid(tenantId,
249                 classifierName);
250         Optional<ClassifierInstance> potentialClassifier = DataStoreHelper.removeIfExists(
251                 LogicalDatastoreType.CONFIGURATION, classifierIid, rwTx);
252         if (!potentialClassifier.isPresent()) {
253             LOG.warn("Illegal state - classifier-instance {} does not exist. {}", classifierName.getValue(),
254                     classifierIid);
255             return false;
256         }
257
258         RuleName ruleName = transform.getRuleName();
259         SubjectName subjectName = transform.getSubjectName();
260         InstanceIdentifier<Rule> ruleIid = IidFactory.ruleIid(tenantId, contractId, subjectName, ruleName);
261         Optional<Rule> potentionalRule = DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION, ruleIid,
262                 rwTx);
263         if (!potentionalRule.isPresent()) {
264             LOG.warn("Illegal state - rule {} does not exist. {}", ruleName.getValue(), ruleIid);
265             return false;
266         }
267
268         InstanceIdentifier<Subject> subjectIid = IidFactory.subjectIid(tenantId, contractId, subjectName);
269         Optional<Subject> potentionalSubject = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
270                 subjectIid, rwTx);
271         if (!potentionalSubject.isPresent()) {
272             LOG.warn("Illegal state - subject {} does not exist. {}", subjectName.getValue(), subjectName);
273             return false;
274         }
275
276         ClauseName clauseName = transform.getClauseName();
277         InstanceIdentifier<Clause> clauseIid = IidFactory.clauseIid(tenantId, contractId, clauseName);
278         Optional<Clause> potentialClause = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, clauseIid,
279                 rwTx);
280         if (!potentialClause.isPresent()) {
281             LOG.warn("Illegal state - clause {} does not exist. {}", clauseName.getValue(), clauseIid);
282             return false;
283         }
284
285         Subject subject = potentionalSubject.get();
286         if (subject.getRule() == null || subject.getRule().isEmpty()) {
287             rwTx.delete(LogicalDatastoreType.CONFIGURATION, clauseIid);
288             rwTx.delete(LogicalDatastoreType.CONFIGURATION, subjectIid);
289         }
290
291         InstanceIdentifier<Contract> contractIid = IidFactory.contractIid(tenantId, contractId);
292         Optional<Contract> potentialContract = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
293                 contractIid, rwTx);
294         if (!potentialContract.isPresent()) {
295             LOG.warn("Illegal state - contract {} does not exist. {}", contractId.getValue(), contractIid);
296             return false;
297         }
298
299         Contract contract = potentialContract.get();
300         if (contract.getSubject() == null || contract.getSubject().isEmpty()) {
301             // remove contract and named selectors from EPGs
302             rwTx.delete(LogicalDatastoreType.CONFIGURATION, contractIid);
303             SelectorName providerSelectorName = createNameOfNamedSelector(contractId);
304             InstanceIdentifier<ProviderNamedSelector> providerSelectorIid = IidFactory.providerNamedSelectorIid(
305                     tenantId, providerEpgId, providerSelectorName);
306             Optional<ProviderNamedSelector> potentialProviderSelector = DataStoreHelper.removeIfExists(
307                     LogicalDatastoreType.CONFIGURATION, providerSelectorIid, rwTx);
308             if (!potentialProviderSelector.isPresent()) {
309                 LOG.warn("Illegal state - provider-name-selector {} does not exist. {}",
310                         providerSelectorName.getValue(), providerSelectorIid);
311                 return false;
312             }
313             SelectorName consumerSelectorName = createNameOfNamedSelector(contractId);
314             InstanceIdentifier<ConsumerNamedSelector> consumerSelectorIid = IidFactory.consumerNamedSelectorIid(
315                     tenantId, consumerEpgId, consumerSelectorName);
316             Optional<ConsumerNamedSelector> potentialConsuemrSelector = DataStoreHelper.removeIfExists(
317                     LogicalDatastoreType.CONFIGURATION, consumerSelectorIid, rwTx);
318             if (!potentialConsuemrSelector.isPresent()) {
319                 LOG.warn("Illegal state - consumer-name-selector {} does not exist. {}",
320                         consumerSelectorName.getValue(), consumerSelectorIid);
321                 return false;
322             }
323         }
324         return true;
325     }
326
327     public static Optional<ContractId> readContractIdFromEpgPairToContractMapping(EndpointGroupId providerEpgId,
328             EndpointGroupId consumerEpgId, ReadTransaction rTx) {
329         Optional<EndpointGroupPairToContractMapping> potentialMapping = DataStoreHelper.readFromDs(
330                 LogicalDatastoreType.OPERATIONAL,
331                 NeutronMapperIidFactory.endpointGroupPairToContractMappingIid(providerEpgId, consumerEpgId), rTx);
332         if (potentialMapping.isPresent()) {
333             return Optional.of(potentialMapping.get().getContractId());
334         }
335         return Optional.absent();
336     }
337
338     private static void putEpgPairToContractMapping(EndpointGroupId providerEpgId, EndpointGroupId consumerEpgId,
339             ContractId contractId, WriteTransaction wTx) {
340         EndpointGroupPairToContractMapping epgPairToContractMapping = new EndpointGroupPairToContractMappingBuilder().setProviderEpgId(
341                 providerEpgId)
342             .setConsumerEpgId(consumerEpgId)
343             .setContractId(contractId)
344             .build();
345         wTx.put(LogicalDatastoreType.OPERATIONAL, NeutronMapperIidFactory.endpointGroupPairToContractMappingIid(
346                 epgPairToContractMapping.getProviderEpgId(), epgPairToContractMapping.getConsumerEpgId()),
347                 epgPairToContractMapping, true);
348     }
349
350     private static Contract createContract(Clause clause, Subject subject) {
351         ContractId contractId = new ContractId(UUID.randomUUID().toString());
352         return new ContractBuilder().setId(contractId)
353             .setClause(ImmutableList.of(clause))
354             .setSubject(ImmutableList.of(subject))
355             .build();
356     }
357
358     private static ProviderNamedSelector createProviderNamedSelector(ContractId contractId) {
359         return new ProviderNamedSelectorBuilder().setName(createNameOfNamedSelector(contractId))
360             .setContract(ImmutableList.of(contractId))
361             .build();
362     }
363
364     private static ConsumerNamedSelector createConsumerNamedSelector(ContractId contractId) {
365         return new ConsumerNamedSelectorBuilder().setName(createNameOfNamedSelector(contractId))
366             .setContract(ImmutableList.of(contractId))
367             .build();
368     }
369
370     private static SelectorName createNameOfNamedSelector(ContractId contractId) {
371         return new SelectorName(MappingUtils.NEUTRON_RULE__ + contractId.getValue());
372     }
373
374 }