Remove netconf from commons/opendaylight pom
[controller.git] / opendaylight / netconf / sal-netconf-connector / src / main / java / org / opendaylight / controller / config / yang / md / sal / connector / netconf / NetconfConnectorModule.java
1 /*
2  * Copyright (c) 2014 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.controller.config.yang.md.sal.connector.netconf;
9
10 import static org.opendaylight.controller.config.api.JmxAttributeValidationException.checkCondition;
11 import static org.opendaylight.controller.config.api.JmxAttributeValidationException.checkNotNull;
12
13 import com.google.common.base.Optional;
14 import io.netty.util.concurrent.EventExecutor;
15 import java.math.BigDecimal;
16 import java.net.InetSocketAddress;
17 import java.util.List;
18 import java.util.concurrent.ExecutorService;
19 import java.util.concurrent.Executors;
20 import java.util.concurrent.ScheduledExecutorService;
21 import java.util.concurrent.ThreadFactory;
22 import org.opendaylight.controller.config.api.JmxAttributeValidationException;
23 import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
24 import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguration;
25 import org.opendaylight.controller.netconf.client.conf.NetconfReconnectingClientConfiguration;
26 import org.opendaylight.controller.netconf.client.conf.NetconfReconnectingClientConfigurationBuilder;
27 import org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication.LoginPassword;
28 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
29 import org.opendaylight.controller.sal.connect.api.RemoteDeviceHandler;
30 import org.opendaylight.controller.sal.connect.netconf.NetconfDevice;
31 import org.opendaylight.controller.sal.connect.netconf.NetconfStateSchemas;
32 import org.opendaylight.controller.sal.connect.netconf.listener.NetconfDeviceCommunicator;
33 import org.opendaylight.controller.sal.connect.netconf.listener.NetconfSessionPreferences;
34 import org.opendaylight.controller.sal.connect.netconf.sal.KeepaliveSalFacade;
35 import org.opendaylight.controller.sal.connect.netconf.sal.NetconfDeviceSalFacade;
36 import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
37 import org.opendaylight.controller.sal.core.api.Broker;
38 import org.opendaylight.protocol.framework.ReconnectStrategy;
39 import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
40 import org.opendaylight.protocol.framework.TimedReconnectStrategy;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
43 import org.opendaylight.yangtools.yang.model.repo.api.SchemaContextFactory;
44 import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceRegistry;
45 import org.osgi.framework.BundleContext;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 /**
50  *
51  */
52 public final class NetconfConnectorModule extends org.opendaylight.controller.config.yang.md.sal.connector.netconf.AbstractNetconfConnectorModule
53 {
54     private static final Logger LOG = LoggerFactory.getLogger(NetconfConnectorModule.class);
55
56     private BundleContext bundleContext;
57     private Optional<NetconfSessionPreferences> userCapabilities;
58     private SchemaSourceRegistry schemaRegistry;
59     private SchemaContextFactory schemaContextFactory;
60
61     public NetconfConnectorModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
62         super(identifier, dependencyResolver);
63     }
64
65     public NetconfConnectorModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, final NetconfConnectorModule oldModule, final java.lang.AutoCloseable oldInstance) {
66         super(identifier, dependencyResolver, oldModule, oldInstance);
67     }
68
69     @Override
70     protected void customValidation() {
71         checkNotNull(getAddress(), addressJmxAttribute);
72         checkCondition(isHostAddressPresent(getAddress()), "Host address not present in " + getAddress(), addressJmxAttribute);
73         checkNotNull(getPort(), portJmxAttribute);
74         checkNotNull(getDomRegistry(), portJmxAttribute);
75         checkNotNull(getDomRegistry(), domRegistryJmxAttribute);
76
77         checkNotNull(getConnectionTimeoutMillis(), connectionTimeoutMillisJmxAttribute);
78         checkCondition(getConnectionTimeoutMillis() > 0, "must be > 0", connectionTimeoutMillisJmxAttribute);
79
80         checkNotNull(getConnectionTimeoutMillis(), defaultRequestTimeoutMillisJmxAttribute);
81         checkCondition(getConnectionTimeoutMillis() > 0, "must be > 0", defaultRequestTimeoutMillisJmxAttribute);
82
83         checkNotNull(getBetweenAttemptsTimeoutMillis(), betweenAttemptsTimeoutMillisJmxAttribute);
84         checkCondition(getBetweenAttemptsTimeoutMillis() > 0, "must be > 0", betweenAttemptsTimeoutMillisJmxAttribute);
85
86         checkNotNull(getClientDispatcher(), clientDispatcherJmxAttribute);
87         checkNotNull(getBindingRegistry(), bindingRegistryJmxAttribute);
88         checkNotNull(getProcessingExecutor(), processingExecutorJmxAttribute);
89
90         // Check username + password in case of ssh
91         if(getTcpOnly() == false) {
92             checkNotNull(getUsername(), usernameJmxAttribute);
93             checkNotNull(getPassword(), passwordJmxAttribute);
94         }
95
96         userCapabilities = getUserCapabilities();
97
98         if(getKeepaliveExecutor() == null) {
99             LOG.warn("Keepalive executor missing. Using default instance for now, the configuration needs to be updated");
100
101             // Instantiate the default executor, now we know its necessary
102             if(DEFAULT_KEEPALIVE_EXECUTOR == null) {
103                 DEFAULT_KEEPALIVE_EXECUTOR = Executors.newScheduledThreadPool(2, new ThreadFactory() {
104                     @Override
105                     public Thread newThread(final Runnable r) {
106                         final Thread thread = new Thread(r);
107                         thread.setName("netconf-southound-keepalives-" + thread.getId());
108                         thread.setDaemon(true);
109                         return thread;
110                     }
111                 });
112             }
113         }
114     }
115
116     private boolean isHostAddressPresent(final Host address) {
117         return address.getDomainName() != null ||
118                address.getIpAddress() != null && (address.getIpAddress().getIpv4Address() != null || address.getIpAddress().getIpv6Address() != null);
119     }
120
121     @Deprecated
122     private static ScheduledExecutorService DEFAULT_KEEPALIVE_EXECUTOR;
123
124     @Override
125     public java.lang.AutoCloseable createInstance() {
126         final RemoteDeviceId id = new RemoteDeviceId(getIdentifier(), getSocketAddress());
127
128         final ExecutorService globalProcessingExecutor = getProcessingExecutorDependency().getExecutor();
129
130         final Broker domBroker = getDomRegistryDependency();
131         final BindingAwareBroker bindingBroker = getBindingRegistryDependency();
132
133         RemoteDeviceHandler<NetconfSessionPreferences> salFacade
134                 = new NetconfDeviceSalFacade(id, domBroker, bindingBroker, getDefaultRequestTimeoutMillis());
135
136         final Long keepaliveDelay = getKeepaliveDelay();
137         if(shouldSendKeepalive()) {
138             // Keepalive executor is optional for now and a default instance is supported
139             final ScheduledExecutorService executor = getKeepaliveExecutor() == null ?
140                     DEFAULT_KEEPALIVE_EXECUTOR : getKeepaliveExecutorDependency().getExecutor();
141             salFacade = new KeepaliveSalFacade(id, salFacade, executor, keepaliveDelay);
142         }
143
144         final NetconfDevice.SchemaResourcesDTO schemaResourcesDTO =
145                 new NetconfDevice.SchemaResourcesDTO(schemaRegistry, schemaContextFactory, new NetconfStateSchemas.NetconfStateSchemasResolverImpl());
146
147         final NetconfDevice device =
148                 new NetconfDevice(schemaResourcesDTO, id, salFacade, globalProcessingExecutor, getReconnectOnChangedSchema());
149
150         final NetconfDeviceCommunicator listener = userCapabilities.isPresent() ?
151                 new NetconfDeviceCommunicator(id, device, userCapabilities.get()) : new NetconfDeviceCommunicator(id, device);
152
153         if(shouldSendKeepalive()) {
154             ((KeepaliveSalFacade) salFacade).setListener(listener);
155         }
156
157         final NetconfReconnectingClientConfiguration clientConfig = getClientConfig(listener);
158         final NetconfClientDispatcher dispatcher = getClientDispatcherDependency();
159
160         listener.initializeRemoteConnection(dispatcher, clientConfig);
161
162         return new SalConnectorCloseable(listener, salFacade);
163     }
164
165     private boolean shouldSendKeepalive() {
166         return getKeepaliveDelay() > 0;
167     }
168
169     private Optional<NetconfSessionPreferences> getUserCapabilities() {
170         if(getYangModuleCapabilities() == null) {
171             return Optional.absent();
172         }
173
174         final List<String> capabilities = getYangModuleCapabilities().getCapability();
175         if(capabilities == null || capabilities.isEmpty()) {
176             return Optional.absent();
177         }
178
179         final NetconfSessionPreferences parsedOverrideCapabilities = NetconfSessionPreferences.fromStrings(capabilities);
180         JmxAttributeValidationException.checkCondition(
181                 parsedOverrideCapabilities.getNonModuleCaps().isEmpty(),
182                 "Capabilities to override can only contain module based capabilities, non-module capabilities will be retrieved from the device," +
183                         " configured non-module capabilities: " + parsedOverrideCapabilities.getNonModuleCaps(),
184                 yangModuleCapabilitiesJmxAttribute);
185
186         return Optional.of(parsedOverrideCapabilities);
187     }
188
189     public NetconfReconnectingClientConfiguration getClientConfig(final NetconfDeviceCommunicator listener) {
190         final InetSocketAddress socketAddress = getSocketAddress();
191         final long clientConnectionTimeoutMillis = getConnectionTimeoutMillis();
192
193         final ReconnectStrategyFactory sf = new TimedReconnectStrategyFactory(
194             getEventExecutorDependency(), getMaxConnectionAttempts(), getBetweenAttemptsTimeoutMillis(), getSleepFactor());
195         final ReconnectStrategy strategy = sf.createReconnectStrategy();
196
197         return NetconfReconnectingClientConfigurationBuilder.create()
198         .withAddress(socketAddress)
199         .withConnectionTimeoutMillis(clientConnectionTimeoutMillis)
200         .withReconnectStrategy(strategy)
201         .withAuthHandler(new LoginPassword(getUsername(), getPassword()))
202         .withProtocol(getTcpOnly() ?
203                 NetconfClientConfiguration.NetconfClientProtocol.TCP :
204                 NetconfClientConfiguration.NetconfClientProtocol.SSH)
205         .withConnectStrategyFactory(sf)
206         .withSessionListener(listener)
207         .build();
208     }
209
210     private static final class SalConnectorCloseable implements AutoCloseable {
211         private final RemoteDeviceHandler<NetconfSessionPreferences> salFacade;
212         private final NetconfDeviceCommunicator listener;
213
214         public SalConnectorCloseable(final NetconfDeviceCommunicator listener,
215                                      final RemoteDeviceHandler<NetconfSessionPreferences> salFacade) {
216             this.listener = listener;
217             this.salFacade = salFacade;
218         }
219
220         @Override
221         public void close() {
222             listener.close();
223             salFacade.close();
224         }
225     }
226
227     private static final class TimedReconnectStrategyFactory implements ReconnectStrategyFactory {
228         private final Long connectionAttempts;
229         private final EventExecutor executor;
230         private final double sleepFactor;
231         private final int minSleep;
232
233         TimedReconnectStrategyFactory(final EventExecutor executor, final Long maxConnectionAttempts, final int minSleep, final BigDecimal sleepFactor) {
234             if (maxConnectionAttempts != null && maxConnectionAttempts > 0) {
235                 connectionAttempts = maxConnectionAttempts;
236             } else {
237                 LOG.trace("Setting {} on {} to infinity", maxConnectionAttemptsJmxAttribute, this);
238                 connectionAttempts = null;
239             }
240
241             this.sleepFactor = sleepFactor.doubleValue();
242             this.executor = executor;
243             this.minSleep = minSleep;
244         }
245
246         @Override
247         public ReconnectStrategy createReconnectStrategy() {
248             final Long maxSleep = null;
249             final Long deadline = null;
250
251             return new TimedReconnectStrategy(executor, minSleep,
252                     minSleep, sleepFactor, maxSleep, connectionAttempts, deadline);
253         }
254     }
255
256     private InetSocketAddress getSocketAddress() {
257         if(getAddress().getDomainName() != null) {
258             return new InetSocketAddress(getAddress().getDomainName().getValue(), getPort().getValue());
259         } else {
260             final IpAddress ipAddress = getAddress().getIpAddress();
261             final String ip = ipAddress.getIpv4Address() != null ? ipAddress.getIpv4Address().getValue() : ipAddress.getIpv6Address().getValue();
262             return new InetSocketAddress(ip, getPort().getValue());
263         }
264     }
265
266     public void setSchemaRegistry(final SchemaSourceRegistry schemaRegistry) {
267         this.schemaRegistry = schemaRegistry;
268     }
269
270     public void setSchemaContextFactory(final SchemaContextFactory schemaContextFactory) {
271         this.schemaContextFactory = schemaContextFactory;
272     }
273 }