Refactor Prov DB handling
[dmaap/datarouter.git] / datarouter-prov / src / main / java / org / onap / dmaap / datarouter / provisioning / ProvRunner.java
1 /*******************************************************************************
2  * ============LICENSE_START==================================================
3  * * org.onap.dmaap
4  * * ===========================================================================
5  * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
6  * * ===========================================================================
7  * * Licensed under the Apache License, Version 2.0 (the "License");
8  * * you may not use this file except in compliance with the License.
9  * * You may obtain a copy of the License at
10  * *
11  *  *      http://www.apache.org/licenses/LICENSE-2.0
12  * *
13  *  * Unless required by applicable law or agreed to in writing, software
14  * * distributed under the License is distributed on an "AS IS" BASIS,
15  * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * * See the License for the specific language governing permissions and
17  * * limitations under the License.
18  * * ============LICENSE_END====================================================
19  * *
20  * * ECOMP is a trademark and service mark of AT&T Intellectual Property.
21  * *
22  ******************************************************************************/
23
24
25 package org.onap.dmaap.datarouter.provisioning;
26
27 import static java.lang.System.exit;
28 import static java.lang.System.getProperty;
29
30 import com.att.eelf.configuration.EELFLogger;
31 import com.att.eelf.configuration.EELFManager;
32 import java.io.File;
33 import java.io.FileInputStream;
34 import java.io.IOException;
35 import java.security.Security;
36 import java.util.EnumSet;
37 import java.util.Properties;
38 import java.util.Timer;
39 import javax.servlet.DispatcherType;
40 import org.eclipse.jetty.http.HttpVersion;
41 import org.eclipse.jetty.server.Connector;
42 import org.eclipse.jetty.server.Handler;
43 import org.eclipse.jetty.server.HttpConfiguration;
44 import org.eclipse.jetty.server.HttpConnectionFactory;
45 import org.eclipse.jetty.server.NCSARequestLog;
46 import org.eclipse.jetty.server.Server;
47 import org.eclipse.jetty.server.ServerConnector;
48 import org.eclipse.jetty.server.SslConnectionFactory;
49 import org.eclipse.jetty.server.handler.ContextHandlerCollection;
50 import org.eclipse.jetty.server.handler.DefaultHandler;
51 import org.eclipse.jetty.server.handler.HandlerCollection;
52 import org.eclipse.jetty.server.handler.RequestLogHandler;
53 import org.eclipse.jetty.servlet.FilterHolder;
54 import org.eclipse.jetty.servlet.ServletContextHandler;
55 import org.eclipse.jetty.servlet.ServletHolder;
56 import org.eclipse.jetty.util.ssl.SslContextFactory;
57 import org.eclipse.jetty.util.thread.QueuedThreadPool;
58 import org.onap.dmaap.datarouter.provisioning.utils.AafPropsUtils;
59 import org.onap.dmaap.datarouter.provisioning.utils.DRProvCadiFilter;
60 import org.onap.dmaap.datarouter.provisioning.utils.LogfileLoader;
61 import org.onap.dmaap.datarouter.provisioning.utils.Poker;
62 import org.onap.dmaap.datarouter.provisioning.utils.ProvDbUtils;
63 import org.onap.dmaap.datarouter.provisioning.utils.PurgeLogDirTask;
64 import org.onap.dmaap.datarouter.provisioning.utils.SynchronizerTask;
65 import org.onap.dmaap.datarouter.provisioning.utils.ThrottleFilter;
66
67 /**
68  * <p>
69  * A main class which may be used to start the provisioning server with an "embedded" Jetty server. Configuration is
70  * done via the properties file <i>provserver.properties</i>, which should be in the CLASSPATH. The provisioning server
71  * may also be packaged with a web.xml and started as a traditional webapp.
72  * </p>
73  * <p>
74  * Most of the work of the provisioning server is carried out within the eight servlets (configured below) that are used
75  * to handle each of the eight types of requests the server may receive. In addition, there are background threads
76  * started to perform other tasks:
77  * </p>
78  * <ul>
79  * <li>One background Thread runs the {@link LogfileLoader} in order to process incoming logfiles.
80  * This Thread is created as a side effect of the first successful POST to the /internal/logs/ servlet.</li>
81  * <li>One background Thread runs the {@link SynchronizerTask} which is used to periodically
82  * synchronize the database between active and standby servers.</li>
83  * <li>One background Thread runs the {@link Poker} which is used to notify the nodes whenever
84  * provisioning data changes.</li>
85  * <li>One task is run once a day to run {@link PurgeLogDirTask} which purges older logs from the
86  * /opt/app/datartr/logs directory.</li>
87  * </ul>
88  * <p>
89  * The provisioning server is stopped by issuing a GET to the URL http://127.0.0.1/internal/halt using <i>curl</i> or
90  * some other such tool.
91  * </p>
92  *
93  * @author Robert Eby
94  * @version $Id: Main.java,v 1.12 2014/03/12 19:45:41 eby Exp $
95  */
96 public class ProvRunner {
97
98     public static final EELFLogger intlogger = EELFManager.getInstance()
99                                                        .getLogger("org.onap.dmaap.datarouter.provisioning.internal");
100
101     /**
102      * The one and only {@link Server} instance in this JVM.
103      */
104     private static Server server;
105     private static AafPropsUtils aafPropsUtils;
106     private static Properties provProperties;
107
108     /**
109      * Starts the Data Router Provisioning server.
110      *
111      * @param args not used
112      * @throws Exception if Jetty has a problem starting
113      */
114     public static void main(String[] args) throws Exception {
115
116         intlogger.info("PROV0000 **** Data Router Provisioning Server starting....");
117
118         // Check DB is accessible and contains the expected tables
119         if (!ProvDbUtils.getInstance().initProvDB()) {
120             intlogger.error("Data Router Provisioning database init failure. Exiting.");
121             exit(1);
122         }
123
124         int httpPort = Integer.parseInt(
125             getProvProperties().getProperty("org.onap.dmaap.datarouter.provserver.http.port", "8080"));
126         final int httpsPort = Integer.parseInt(
127             getProvProperties().getProperty("org.onap.dmaap.datarouter.provserver.https.port", "8443"));
128
129         Security.setProperty("networkaddress.cache.ttl", "4");
130         // Server's thread pool
131         QueuedThreadPool queuedThreadPool = new QueuedThreadPool();
132         queuedThreadPool.setMinThreads(10);
133         queuedThreadPool.setMaxThreads(200);
134         queuedThreadPool.setDetailedDump(false);
135
136         // The server itself
137         server = new Server(queuedThreadPool);
138         server.setStopAtShutdown(true);
139         server.setStopTimeout(5000);
140         server.setDumpAfterStart(false);
141         server.setDumpBeforeStop(false);
142
143         // Request log configuration
144         NCSARequestLog ncsaRequestLog = new NCSARequestLog();
145         ncsaRequestLog.setFilename(getProvProperties()
146                                            .getProperty("org.onap.dmaap.datarouter.provserver.accesslog.dir")
147                                            + "/request.log.yyyy_mm_dd");
148         ncsaRequestLog.setFilenameDateFormat("yyyyMMdd");
149         ncsaRequestLog.setRetainDays(90);
150         ncsaRequestLog.setAppend(true);
151         ncsaRequestLog.setExtended(false);
152         ncsaRequestLog.setLogCookies(false);
153         ncsaRequestLog.setLogTimeZone("GMT");
154
155         RequestLogHandler requestLogHandler = new RequestLogHandler();
156         requestLogHandler.setRequestLog(ncsaRequestLog);
157         server.setRequestLog(ncsaRequestLog);
158
159         // HTTP configuration
160         HttpConfiguration httpConfiguration = new HttpConfiguration();
161         httpConfiguration.setSecureScheme("https");
162         httpConfiguration.setSecurePort(httpsPort);
163         httpConfiguration.setOutputBufferSize(32768);
164         httpConfiguration.setRequestHeaderSize(8192);
165         httpConfiguration.setResponseHeaderSize(8192);
166         httpConfiguration.setSendServerVersion(true);
167         httpConfiguration.setSendDateHeader(false);
168
169         try {
170             AafPropsUtils.init(new File(getProvProperties().getProperty(
171                 "org.onap.dmaap.datarouter.provserver.aafprops.path",
172                 "/opt/app/osaaf/local/org.onap.dmaap-dr.props")));
173         } catch (IOException e) {
174             intlogger.error("NODE0314 Failed to load AAF props. Exiting", e);
175             exit(1);
176         }
177         aafPropsUtils = AafPropsUtils.getInstance();
178
179         //HTTP Connector
180         HandlerCollection handlerCollection;
181         try (ServerConnector httpServerConnector =
182                      new ServerConnector(server, new HttpConnectionFactory(httpConfiguration))) {
183             httpServerConnector.setPort(httpPort);
184             httpServerConnector.setAcceptQueueSize(2);
185             httpServerConnector.setIdleTimeout(300000);
186
187             // SSL Context
188             SslContextFactory sslContextFactory = new SslContextFactory();
189             sslContextFactory.setKeyStoreType(AafPropsUtils.KEYSTORE_TYPE_PROPERTY);
190             sslContextFactory.setKeyStorePath(getAafPropsUtils().getKeystorePathProperty());
191             sslContextFactory.setKeyStorePassword(getAafPropsUtils().getKeystorePassProperty());
192             sslContextFactory.setKeyManagerPassword(getAafPropsUtils().getKeystorePassProperty());
193
194             String truststorePathProperty = getAafPropsUtils().getTruststorePathProperty();
195             if (truststorePathProperty != null && truststorePathProperty.length() > 0) {
196                 intlogger.info("@@ TS -> " + truststorePathProperty);
197                 sslContextFactory.setTrustStoreType(AafPropsUtils.TRUESTSTORE_TYPE_PROPERTY);
198                 sslContextFactory.setTrustStorePath(truststorePathProperty);
199                 sslContextFactory.setTrustStorePassword(getAafPropsUtils().getTruststorePassProperty());
200             } else {
201                 sslContextFactory.setTrustStorePath(AafPropsUtils.DEFAULT_TRUSTSTORE);
202                 sslContextFactory.setTrustStorePassword("changeit");
203             }
204
205             sslContextFactory.setWantClientAuth(true);
206             sslContextFactory.setExcludeCipherSuites(
207                     "SSL_RSA_WITH_DES_CBC_SHA",
208                     "SSL_DHE_RSA_WITH_DES_CBC_SHA",
209                     "SSL_DHE_DSS_WITH_DES_CBC_SHA",
210                     "SSL_RSA_EXPORT_WITH_RC4_40_MD5",
211                     "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
212                     "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
213                     "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"
214             );
215             sslContextFactory.addExcludeProtocols("SSLv3");
216             sslContextFactory.setIncludeProtocols(getProvProperties().getProperty(
217                     "org.onap.dmaap.datarouter.provserver.https.include.protocols",
218                     "TLSv1.1|TLSv1.2").trim().split("\\|"));
219
220             intlogger.info("Not supported protocols prov server:-"
221                                    + String.join(",", sslContextFactory.getExcludeProtocols()));
222             intlogger.info("Supported protocols prov server:-"
223                                    + String.join(",", sslContextFactory.getIncludeProtocols()));
224             intlogger.info("Not supported ciphers prov server:-"
225                                    + String.join(",", sslContextFactory.getExcludeCipherSuites()));
226             intlogger.info("Supported ciphers prov server:-"
227                                    + String.join(",", sslContextFactory.getIncludeCipherSuites()));
228
229             // HTTPS configuration
230             HttpConfiguration httpsConfiguration = new HttpConfiguration(httpConfiguration);
231             httpsConfiguration.setRequestHeaderSize(8192);
232
233             // HTTPS connector
234             try (ServerConnector httpsServerConnector = new ServerConnector(server,
235                     new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()),
236                     new HttpConnectionFactory(httpsConfiguration))) {
237
238                 httpsServerConnector.setPort(httpsPort);
239                 httpsServerConnector.setIdleTimeout(30000);
240                 httpsServerConnector.setAcceptQueueSize(2);
241
242                 // Servlet and Filter configuration
243                 ServletContextHandler servletContextHandler = new ServletContextHandler(0);
244                 servletContextHandler.setContextPath("/");
245                 servletContextHandler.addServlet(new ServletHolder(new FeedServlet()), "/feed/*");
246                 servletContextHandler.addServlet(new ServletHolder(new FeedLogServlet()), "/feedlog/*");
247                 servletContextHandler.addServlet(new ServletHolder(new PublishServlet()), "/publish/*");
248                 servletContextHandler.addServlet(new ServletHolder(new SubscribeServlet()), "/subscribe/*");
249                 servletContextHandler.addServlet(new ServletHolder(new StatisticsServlet()), "/statistics/*");
250                 servletContextHandler.addServlet(new ServletHolder(new SubLogServlet()), "/sublog/*");
251                 servletContextHandler.addServlet(new ServletHolder(new GroupServlet()), "/group/*");
252                 servletContextHandler.addServlet(new ServletHolder(new SubscriptionServlet()), "/subs/*");
253                 servletContextHandler.addServlet(new ServletHolder(new InternalServlet()), "/internal/*");
254                 servletContextHandler.addServlet(new ServletHolder(new RouteServlet()), "/internal/route/*");
255                 servletContextHandler.addServlet(new ServletHolder(new DRFeedsServlet()), "/");
256                 servletContextHandler.addFilter(new FilterHolder(new ThrottleFilter()),
257                         "/publish/*", EnumSet.of(DispatcherType.REQUEST));
258
259                 //CADI Filter activation check
260                 if (Boolean.parseBoolean(getProvProperties().getProperty(
261                         "org.onap.dmaap.datarouter.provserver.cadi.enabled", "false"))) {
262                     servletContextHandler.addFilter(new FilterHolder(new DRProvCadiFilter(true, getAafPropsUtils().getPropAccess())),
263                             "/*", EnumSet.of(DispatcherType.REQUEST));
264                     intlogger.info("PROV0001 AAF CADI Auth enabled for ");
265                 }
266
267                 ContextHandlerCollection contextHandlerCollection = new ContextHandlerCollection();
268                 contextHandlerCollection.addHandler(servletContextHandler);
269
270                 // Server's Handler collection
271                 handlerCollection = new HandlerCollection();
272                 handlerCollection.setHandlers(new Handler[]{contextHandlerCollection, new DefaultHandler()});
273                 handlerCollection.addHandler(requestLogHandler);
274
275                 server.setConnectors(new Connector[]{httpServerConnector, httpsServerConnector});
276             }
277         }
278         server.setHandler(handlerCollection);
279
280         // Daemon to clean up the log directory on a daily basis
281         Timer rolex = new Timer();
282         rolex.scheduleAtFixedRate(new PurgeLogDirTask(), 0, 86400000L);    // run once per day
283
284         // Start LogfileLoader
285         LogfileLoader.getLoader();
286
287         try {
288             server.start();
289             intlogger.info("Prov Server started-" + server.getState());
290         } catch (Exception e) {
291             intlogger.error("Jetty failed to start. Exiting: " + e.getMessage(), e);
292             exit(1);
293         }
294         server.join();
295         intlogger.info("PROV0001 **** AT&T Data Router Provisioning Server halted.");
296     }
297
298     /**
299      * Stop the Jetty server.
300      */
301     public static void shutdown() {
302         new Thread(() -> {
303             try {
304                 server.stop();
305                 Thread.sleep(5000L);
306                 exit(0);
307             } catch (Exception e) {
308                 intlogger.error("Exception in Main.shutdown(): " + e.getMessage(), e);
309             }
310         });
311     }
312
313     public static Properties getProvProperties() {
314         if (provProperties == null) {
315             try {
316                 provProperties = new Properties();
317                 provProperties.load(new FileInputStream(getProperty(
318                     "org.onap.dmaap.datarouter.provserver.properties",
319                     "/opt/app/datartr/etc/provserver.properties")));
320             } catch (IOException e) {
321                 intlogger.error("Failed to load PROV properties: " + e.getMessage(), e);
322                 exit(1);
323             }
324         }
325         return provProperties;
326     }
327
328     public static AafPropsUtils getAafPropsUtils() {
329         return aafPropsUtils;
330     }
331 }