Bug 3651: Fix creation of External EPG.
[groupbasedpolicy.git] / neutron-mapper / src / main / java / org / opendaylight / groupbasedpolicy / neutron / mapper / mapping / NeutronNetworkAware.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.groupbasedpolicy.neutron.mapper.mapping;
9
10 import static com.google.common.base.Preconditions.checkNotNull;
11
12 import java.util.UUID;
13
14 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
15 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
16 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
17 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
18 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.NeutronMapperIidFactory;
19 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.Utils;
20 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
21 import org.opendaylight.groupbasedpolicy.util.IidFactory;
22 import org.opendaylight.neutron.spi.INeutronNetworkAware;
23 import org.opendaylight.neutron.spi.NeutronNetwork;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2BridgeDomainId;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2FloodDomainId;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Name;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.mapper.rev150223.mappings.network.mappings.NetworkMapping;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.mapper.rev150223.mappings.network.mappings.NetworkMappingBuilder;
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.L2BridgeDomain;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomainBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2FloodDomain;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2FloodDomainBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3Context;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3ContextBuilder;
41 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 import com.google.common.base.Optional;
46
47 public class NeutronNetworkAware implements INeutronNetworkAware {
48
49     private static final Logger LOG = LoggerFactory.getLogger(NeutronNetworkAware.class);
50     private final DataBroker dataProvider;
51
52     public NeutronNetworkAware(DataBroker dataProvider) {
53         this.dataProvider = checkNotNull(dataProvider);
54     }
55
56     /**
57      * @see org.opendaylight.neutron.spi.INeutronNetworkAware#canCreateNetwork(org.opendaylight.neutron.spi.NeutronNetwork)
58      */
59     @Override
60     public int canCreateNetwork(NeutronNetwork network) {
61         LOG.trace("canCreateNetwork - {}", network);
62         // nothing to consider
63         return StatusCode.OK;
64     }
65
66     /**
67      * @see org.opendaylight.neutron.spi.INeutronNetworkAware#neutronNetworkCreated(org.opendaylight.neutron.spi.NeutronNetwork)
68      */
69     @Override
70     public void neutronNetworkCreated(NeutronNetwork network) {
71         LOG.trace("neutronNetworkCreated - {}", network);
72         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
73         L2FloodDomainId l2FdId = new L2FloodDomainId(network.getID());
74         TenantId tenantId = new TenantId(Utils.normalizeUuid(network.getTenantID()));
75         addEpgDhcpIfMissing(tenantId, rwTx);
76         addEpgRouterIfMissing(tenantId, rwTx);
77         // Note that Router External doesn't mean the router exists yet, it simply means it will connect to one.
78         if(network.getRouterExternal()) {
79             addEpgExternalIfMissing(tenantId, rwTx);
80         }
81         Description domainDescription = new Description(MappingUtils.NEUTRON_NETWORK__ + network.getID());
82         Name name = null;
83         if (network.getNetworkName() != null) {
84             name = new Name(network.getNetworkName());
85         }
86         L3ContextId l3ContextId = new L3ContextId(UUID.randomUUID().toString());
87         L3Context l3Context = new L3ContextBuilder().setId(l3ContextId)
88             .setDescription(domainDescription)
89             .setName(name)
90             .build();
91         rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l3ContextIid(tenantId, l3ContextId), l3Context, true);
92
93         L2BridgeDomainId l2BdId = new L2BridgeDomainId(UUID.randomUUID().toString());
94         L2BridgeDomain l2Bd = new L2BridgeDomainBuilder().setId(l2BdId)
95             .setParent(l3ContextId)
96             .setDescription(domainDescription)
97             .setName(name)
98             .build();
99         rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BdId), l2Bd, true);
100
101         L2FloodDomain l2Fd = new L2FloodDomainBuilder().setId(l2FdId)
102             .setParent(l2BdId)
103             .setDescription(domainDescription)
104             .setName(name)
105             .build();
106         rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l2FloodDomainIid(tenantId, l2FdId), l2Fd, true);
107
108         NetworkMapping networkMapping = new NetworkMappingBuilder().setNetworkId(l2FdId)
109             .setL2BridgeDomainId(l2BdId)
110             .setL3ContextId(l3ContextId)
111             .build();
112         rwTx.put(LogicalDatastoreType.OPERATIONAL, NeutronMapperIidFactory.networkMappingIid(l2FdId), networkMapping, true);
113
114         DataStoreHelper.submitToDs(rwTx);
115     }
116
117     private void addEpgExternalIfMissing(TenantId tenantId, ReadWriteTransaction rwTx) {
118         Optional<EndpointGroup> potentialEpgExternal = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
119                 IidFactory.endpointGroupIid(tenantId, MappingUtils.EPG_EXTERNAL_ID), rwTx);
120         if (!potentialEpgExternal.isPresent()) {
121             EndpointGroup epgExternal = new EndpointGroupBuilder().setId(MappingUtils.EPG_EXTERNAL_ID)
122                 .setDescription(new Description(MappingUtils.NEUTRON_EXTERNAL__ + "epg_external_networks"))
123                 .setIntraGroupPolicy(IntraGroupPolicy.RequireContract)
124                 .build();
125             rwTx.put(LogicalDatastoreType.CONFIGURATION,
126                     IidFactory.endpointGroupIid(tenantId, MappingUtils.EPG_EXTERNAL_ID), epgExternal, true);
127         }
128     }
129
130     private void addEpgDhcpIfMissing(TenantId tenantId, ReadWriteTransaction rwTx) {
131         InstanceIdentifier<EndpointGroup> epgDhcpIid = IidFactory.endpointGroupIid(tenantId, MappingUtils.EPG_DHCP_ID);
132         Optional<EndpointGroup> potentialDhcpEpg = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
133                 epgDhcpIid, rwTx);
134         if (!potentialDhcpEpg.isPresent()) {
135             EndpointGroup epgDhcp = new EndpointGroupBuilder().setId(MappingUtils.EPG_DHCP_ID)
136                 .setName(new Name("DHCP_group"))
137                 .setDescription(new Description("Group where are all DHCP endpoints."))
138                 .setIntraGroupPolicy(IntraGroupPolicy.RequireContract)
139                 .build();
140             rwTx.put(LogicalDatastoreType.CONFIGURATION, epgDhcpIid, epgDhcp);
141         }
142     }
143
144     private void addEpgRouterIfMissing(TenantId tenantId, ReadWriteTransaction rwTx) {
145         Optional<EndpointGroup> potentialEpgRouter = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
146                 IidFactory.endpointGroupIid(tenantId, MappingUtils.EPG_ROUTER_ID), rwTx);
147         if (!potentialEpgRouter.isPresent()) {
148             EndpointGroup epgRouter = new EndpointGroupBuilder().setId(MappingUtils.EPG_ROUTER_ID)
149                 .setDescription(new Description(MappingUtils.NEUTRON_ROUTER__ + "epg_routers"))
150                 .setIntraGroupPolicy(IntraGroupPolicy.RequireContract)
151                 .build();
152             rwTx.put(LogicalDatastoreType.CONFIGURATION,
153                     IidFactory.endpointGroupIid(tenantId, MappingUtils.EPG_ROUTER_ID), epgRouter);
154         }
155     }
156
157     /**
158      * @see org.opendaylight.neutron.spi.INeutronNetworkAware#canUpdateNetwork(org.opendaylight.neutron.spi.NeutronNetwork,
159      *      org.opendaylight.neutron.spi.NeutronNetwork)
160      */
161     @Override
162     public int canUpdateNetwork(NeutronNetwork delta, NeutronNetwork original) {
163         LOG.trace("canUpdateNetwork - delta: {} original: {}", delta, original);
164         // nothing to consider
165         return StatusCode.OK;
166     }
167
168     /**
169      * @see org.opendaylight.neutron.spi.INeutronNetworkAware#neutronNetworkUpdated(org.opendaylight.neutron.spi.NeutronNetwork)
170      */
171     @Override
172     public void neutronNetworkUpdated(NeutronNetwork network) {
173         LOG.trace("neutronNetworkUpdated - {}", network);
174         // TODO we could update just name
175     }
176
177     /**
178      * @see org.opendaylight.neutron.spi.INeutronNetworkAware#canDeleteNetwork(org.opendaylight.neutron.spi.NeutronNetwork)
179      */
180     @Override
181     public int canDeleteNetwork(NeutronNetwork network) {
182         LOG.trace("canDeleteNetwork - {}", network);
183         // nothing to consider
184         return StatusCode.OK;
185     }
186
187     /**
188      * @see org.opendaylight.neutron.spi.INeutronNetworkAware#neutronNetworkDeleted(org.opendaylight.neutron.spi.NeutronNetwork)
189      */
190     @Override
191     public void neutronNetworkDeleted(NeutronNetwork network) {
192         LOG.trace("neutronNetworkDeleted - {}", network);
193         ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
194         TenantId tenantId = new TenantId(Utils.normalizeUuid(network.getTenantID()));
195         L2FloodDomainId l2FdId = new L2FloodDomainId(network.getID());
196         Optional<NetworkMapping> potentionalNetworkMapping = DataStoreHelper.readFromDs(
197                 LogicalDatastoreType.OPERATIONAL, NeutronMapperIidFactory.networkMappingIid(l2FdId), rwTx);
198         if (!potentionalNetworkMapping.isPresent()) {
199             LOG.warn("Illegal state - network-mapping {} does not exist.", l2FdId.getValue());
200             rwTx.cancel();
201             return;
202         }
203
204         NetworkMapping networkMapping = potentionalNetworkMapping.get();
205         L2BridgeDomainId l2BdId = networkMapping.getL2BridgeDomainId();
206         L3ContextId l3ContextId = networkMapping.getL3ContextId();
207         if (l2BdId == null || l3ContextId == null) {
208             LOG.warn("Illegal state - network-mapping {} is not valid.", networkMapping);
209             rwTx.cancel();
210             return;
211         }
212
213         Optional<L2FloodDomain> potentialL2Fd = DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION,
214                 IidFactory.l2FloodDomainIid(tenantId, l2FdId), rwTx);
215         if (!potentialL2Fd.isPresent()) {
216             LOG.warn("Illegal state - l2-flood-domain {} does not exist.", l2FdId.getValue());
217             rwTx.cancel();
218             return;
219         }
220
221         Optional<L2BridgeDomain> potentialL2Bd = DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION,
222                 IidFactory.l2BridgeDomainIid(tenantId, l2BdId), rwTx);
223         if (!potentialL2Bd.isPresent()) {
224             LOG.warn("Illegal state - l2-bridge-domain {} does not exist.", l2BdId.getValue());
225             rwTx.cancel();
226             return;
227         }
228
229         Optional<L3Context> potentialL3Context = DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION,
230                 IidFactory.l3ContextIid(tenantId, l3ContextId), rwTx);
231         if (!potentialL3Context.isPresent()) {
232             LOG.warn("Illegal state - l3-context {} does not exist.", l3ContextId.getValue());
233             rwTx.cancel();
234             return;
235         }
236
237         DataStoreHelper.submitToDs(rwTx);
238     }
239
240 }