blob: d714e3eeee8fd740d297da77b6016fcf29b65599 [file] [log] [blame]
Hyunsun Moon60a10672016-06-12 17:39:12 -07001/*
2 * Copyright 2016-present Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.opencord.cordvtn.impl;
17
18import org.onlab.osgi.DefaultServiceDirectory;
19import org.onlab.osgi.ServiceDirectory;
20import org.onosproject.core.ApplicationId;
21import org.onosproject.core.CoreService;
22import org.onosproject.mastership.MastershipService;
23import org.onosproject.net.Host;
24import org.onosproject.net.config.NetworkConfigEvent;
25import org.onosproject.net.config.NetworkConfigListener;
26import org.onosproject.net.config.NetworkConfigRegistry;
27import org.onosproject.net.host.HostEvent;
28import org.onosproject.net.host.HostListener;
29import org.onosproject.net.host.HostService;
30import org.onosproject.xosclient.api.OpenStackAccess;
31import org.onosproject.xosclient.api.VtnPort;
32import org.onosproject.xosclient.api.VtnPortApi;
33import org.onosproject.xosclient.api.VtnPortId;
34import org.onosproject.xosclient.api.VtnService;
35import org.onosproject.xosclient.api.VtnServiceApi;
36import org.onosproject.xosclient.api.VtnServiceApi.ServiceType;
37import org.onosproject.xosclient.api.VtnServiceId;
38import org.onosproject.xosclient.api.XosAccess;
39import org.onosproject.xosclient.api.XosClientService;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070040import org.opencord.cordvtn.api.Constants;
Hyunsun Moon60a10672016-06-12 17:39:12 -070041import org.opencord.cordvtn.api.CordVtnConfig;
Hyunsun Moon60a10672016-06-12 17:39:12 -070042import org.opencord.cordvtn.api.Instance;
43import org.opencord.cordvtn.api.InstanceHandler;
44import org.slf4j.Logger;
45
46import java.util.Objects;
47import java.util.Optional;
48import java.util.Set;
49import java.util.concurrent.ExecutorService;
50import java.util.stream.Collectors;
51import java.util.stream.StreamSupport;
52
53import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070054import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
55import static org.onlab.util.Tools.groupedThreads;
56import static org.opencord.cordvtn.api.Constants.ERROR_OPENSTACK_ACCESS;
57import static org.opencord.cordvtn.api.Constants.ERROR_XOS_ACCESS;
Hyunsun Moon60a10672016-06-12 17:39:12 -070058import static org.slf4j.LoggerFactory.getLogger;
59
60/**
61 * Provides default virtual network connectivity for service instances.
62 */
63public abstract class AbstractInstanceHandler implements InstanceHandler {
64
65 protected final Logger log = getLogger(getClass());
66
67 protected CoreService coreService;
68 protected MastershipService mastershipService;
69 protected NetworkConfigRegistry configRegistry;
70 protected HostService hostService;
71 protected XosClientService xosClient;
Hyunsun Moon60a10672016-06-12 17:39:12 -070072
73 protected ApplicationId appId;
Hyunsun Moon60a10672016-06-12 17:39:12 -070074 protected Optional<ServiceType> serviceType = Optional.empty();
75 protected NetworkConfigListener configListener = new InternalConfigListener();
76 protected HostListener hostListener = new InternalHostListener();
77
Hyunsun Moon60a10672016-06-12 17:39:12 -070078 private XosAccess xosAccess = null;
79 private OpenStackAccess osAccess = null;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070080 private final ExecutorService eventExecutor = newSingleThreadScheduledExecutor(
81 groupedThreads(this.getClass().getSimpleName(), "event-handler"));
Hyunsun Moon60a10672016-06-12 17:39:12 -070082
83 protected void activate() {
84 ServiceDirectory services = new DefaultServiceDirectory();
85 coreService = services.get(CoreService.class);
86 configRegistry = services.get(NetworkConfigRegistry.class);
87 mastershipService = services.get(MastershipService.class);
88 hostService = services.get(HostService.class);
89 xosClient = services.get(XosClientService.class);
Hyunsun Moon60a10672016-06-12 17:39:12 -070090
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070091 appId = coreService.registerApplication(Constants.CORDVTN_APP_ID);
Hyunsun Moon60a10672016-06-12 17:39:12 -070092 hostService.addListener(hostListener);
93 configRegistry.addListener(configListener);
94
95 log.info("Started");
96 }
97
98 protected void deactivate() {
99 hostService.removeListener(hostListener);
100 configRegistry.removeListener(configListener);
101 eventExecutor.shutdown();
102
103 log.info("Stopped");
104 }
105
106 protected VtnService getVtnService(VtnServiceId serviceId) {
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700107 checkNotNull(osAccess, ERROR_OPENSTACK_ACCESS);
108 checkNotNull(xosAccess, ERROR_XOS_ACCESS);
Hyunsun Moon60a10672016-06-12 17:39:12 -0700109
110 // TODO remove openstack access when XOS provides all information
111 VtnServiceApi serviceApi = xosClient.getClient(xosAccess).vtnService();
112 VtnService service = serviceApi.service(serviceId, osAccess);
113 if (service == null) {
114 log.warn("Failed to get VtnService for {}", serviceId);
115 }
116 return service;
117 }
118
119 protected VtnPort getVtnPort(Instance instance) {
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700120 checkNotNull(osAccess, ERROR_OPENSTACK_ACCESS);
121 checkNotNull(xosAccess, ERROR_XOS_ACCESS);
Hyunsun Moon60a10672016-06-12 17:39:12 -0700122
123 VtnPortId vtnPortId = instance.portId();
124 VtnPortApi portApi = xosClient.getClient(xosAccess).vtnPort();
125 VtnPort vtnPort = portApi.vtnPort(vtnPortId, osAccess);
126 if (vtnPort == null) {
127 log.warn("Failed to get port information of {}", instance);
128 return null;
129 }
130 return vtnPort;
131 }
132
133 protected Set<Instance> getInstances(VtnServiceId serviceId) {
134 return StreamSupport.stream(hostService.getHosts().spliterator(), false)
135 .filter(host -> Objects.equals(
136 serviceId.id(),
137 host.annotations().value(Instance.SERVICE_ID)))
138 .map(Instance::of)
139 .collect(Collectors.toSet());
140 }
141
142 protected void readConfiguration() {
143 CordVtnConfig config = configRegistry.getConfig(appId, CordVtnConfig.class);
144 if (config == null) {
145 log.debug("No configuration found");
146 return;
147 }
148 osAccess = config.openstackAccess();
149 xosAccess = config.xosAccess();
150 }
151
152 private class InternalHostListener implements HostListener {
153
154 @Override
155 public void event(HostEvent event) {
156 Host host = event.subject();
157 if (!mastershipService.isLocalMaster(host.location().deviceId())) {
158 // do not allow to proceed without mastership
159 return;
160 }
161
162 Instance instance = Instance.of(host);
163 if (serviceType.isPresent() &&
164 !serviceType.get().equals(instance.serviceType())) {
165 // not my service instance, do nothing
166 return;
167 }
168
169 switch (event.type()) {
170 case HOST_UPDATED:
171 case HOST_ADDED:
172 eventExecutor.execute(() -> instanceDetected(instance));
173 break;
174 case HOST_REMOVED:
175 eventExecutor.execute(() -> instanceRemoved(instance));
176 break;
177 default:
178 break;
179 }
180 }
181 }
182
183 private class InternalConfigListener implements NetworkConfigListener {
184
185 @Override
186 public void event(NetworkConfigEvent event) {
187 if (!event.configClass().equals(CordVtnConfig.class)) {
188 return;
189 }
190
191 switch (event.type()) {
192 case CONFIG_ADDED:
193 case CONFIG_UPDATED:
194 readConfiguration();
195 break;
196 default:
197 break;
198 }
199 }
200 }
201}