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