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