Merge of new rebased code
[appc.git] / appc-oam / appc-oam-bundle / src / main / java / org / openecomp / appc / oam / AppcOam.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * openECOMP : APP-C
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights
6  *                                              reserved.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  * 
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  * 
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.openecomp.appc.oam;
23
24 import org.openecomp.appc.Constants;
25 import org.openecomp.appc.configuration.Configuration;
26 import org.openecomp.appc.configuration.ConfigurationFactory;
27 import org.openecomp.appc.exceptions.APPCException;
28 import org.openecomp.appc.executor.objects.Params;
29 import org.openecomp.appc.i18n.Msg;
30 import org.openecomp.appc.logging.LoggingConstants;
31 import org.openecomp.appc.logging.LoggingUtils;
32 import org.openecomp.appc.metricservice.MetricRegistry;
33 import org.openecomp.appc.metricservice.MetricService;
34 import org.openecomp.appc.metricservice.metric.Metric;
35 import org.openecomp.appc.requesthandler.LCMStateManager;
36 import org.openecomp.appc.requesthandler.RequestHandler;
37 import com.att.eelf.configuration.EELFLogger;
38 import com.att.eelf.configuration.EELFManager;
39 import com.att.eelf.i18n.EELFResourceManager;
40 import com.google.common.util.concurrent.Futures;
41 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
42 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
43 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
44 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
45 import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.*;
46 import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.common.header.CommonHeader;
47 import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.get.metrics.output.Metrics;
48 import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.get.metrics.output.MetricsBuilder;
49 import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.get.metrics.output.metrics.KpiValues;
50 import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.get.metrics.output.metrics.KpiValuesBuilder;
51 import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.status.Status;
52 import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.status.StatusBuilder;
53 import org.opendaylight.yangtools.yang.common.RpcError;
54 import org.opendaylight.yangtools.yang.common.RpcResult;
55 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
56 import org.osgi.framework.Bundle;
57 import org.osgi.framework.BundleContext;
58 import org.osgi.framework.FrameworkUtil;
59 import org.osgi.framework.ServiceReference;
60 import org.slf4j.MDC;
61
62 import java.net.InetAddress;
63 import java.util.*;
64 import java.util.concurrent.*;
65
66 import org.openecomp.appc.oam.messageadapter.*;
67
68
69 import static com.att.eelf.configuration.Configuration.*;
70
71 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
72 import org.osgi.framework.BundleContext;
73 import org.osgi.framework.FrameworkUtil;
74 import org.osgi.framework.ServiceReference;
75
76 import java.util.ArrayList;
77 import java.util.List;
78 import java.util.Map;
79 import java.util.Properties;
80 import java.util.concurrent.Executors;
81 import java.util.concurrent.Future;
82
83
84 public class AppcOam implements AutoCloseable, AppcOamService {
85
86     private Configuration configuration = ConfigurationFactory.getConfiguration();
87     private final EELFLogger logger = EELFManager.getInstance().getLogger(AppcOam.class);
88
89     private boolean isMetricEnabled = false;
90
91
92     private final ScheduledExecutorService scheduledExecutorService;
93
94     private volatile ScheduledFuture<?> outstandingLCMRequestMonitorSheduledFuture;
95
96
97     private MessageAdapter messageAdapter;
98
99
100     /**
101      * The ODL data store broker. Provides access to a conceptual data tree store and also provides the ability to
102      * subscribe for changes to data under a given branch of the tree.
103      */
104     private DataBroker dataBroker;
105
106     /**
107      * ODL Notification Service that provides publish/subscribe capabilities for YANG modeled notifications.
108      */
109     private NotificationProviderService notificationService;
110
111     /**
112      * Provides a registry for Remote Procedure Call (RPC) service implementations. The RPCs are defined in YANG models.
113      */
114     private RpcProviderRegistry rpcRegistry;
115
116     /**
117      * Represents our RPC implementation registration
118      */
119     private BindingAwareBroker.RpcRegistration<AppcOamService> rpcRegistration;
120
121
122     /**
123      * The yang rpc names
124      */
125     public enum RPC {
126         start,
127         stop,
128         ;
129     }
130
131
132     /**
133      * @param dataBroker
134      * @param notificationProviderService
135      * @param rpcProviderRegistry
136      */
137     @SuppressWarnings({
138             "javadoc", "nls"
139     })
140     public AppcOam(DataBroker dataBroker, NotificationProviderService notificationProviderService,
141                    RpcProviderRegistry rpcProviderRegistry) {
142
143         String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME);
144         logger.info(Msg.COMPONENT_INITIALIZING, appName, "oam");
145
146         this.dataBroker = dataBroker;
147         this.notificationService = notificationProviderService;
148         this.rpcRegistry = rpcProviderRegistry;
149
150         if (this.rpcRegistry != null) {
151             rpcRegistration = rpcRegistry.addRpcImplementation(AppcOamService.class, this);
152         }
153
154         Properties properties = configuration.getProperties();
155         if (properties != null && properties.getProperty("metric.enabled") != null) {
156             isMetricEnabled = Boolean.valueOf(properties.getProperty("metric.enabled"));
157         }
158
159
160         messageAdapter = new MessageAdapter();
161         messageAdapter.init();
162
163
164         scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(
165                 new ThreadFactory(){
166
167                     @Override
168                     public Thread newThread(Runnable runnable) {
169                         Bundle bundle = FrameworkUtil.getBundle(AppcOam.class);
170                         return new Thread(runnable,bundle.getSymbolicName() + " scheduledExecutor");
171                     }
172                 }
173         );
174
175         logger.info(Msg.COMPONENT_INITIALIZED, appName, "oam");
176     }
177
178     /**
179      * Implements the close of the service
180      *
181      * @see AutoCloseable#close()
182      */
183     @SuppressWarnings("nls")
184     @Override
185     public void close() throws Exception {
186         String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME);
187         logger.info(Msg.COMPONENT_TERMINATING, appName, "oam");
188         scheduledExecutorService.shutdown();
189         if (rpcRegistration != null) {
190             rpcRegistration.close();
191         }
192         logger.info(Msg.COMPONENT_TERMINATED, appName, "oam");
193     }
194
195     @Override
196     public Future<RpcResult<GetMetricsOutput>> getMetrics() {
197
198         GetMetricsOutputBuilder outputBuilder = new GetMetricsOutputBuilder();
199
200         if (!isMetricEnabled){
201             logger.error("Metric Service not enabled returning failure");
202             RpcResult<GetMetricsOutput> result = RpcResultBuilder.<GetMetricsOutput> status(false).withError(RpcError.ErrorType.APPLICATION,"Metric Service not enabled").build();
203             return Futures.immediateFuture(result);
204         }
205
206         MetricService metricService = null;
207         try {
208             metricService = getService(MetricService.class);
209         } catch (APPCException e){
210             logger.error("MetricService not found",e);
211             RpcResult<GetMetricsOutput> result = RpcResultBuilder.<GetMetricsOutput> status(false).withError(RpcError.ErrorType.APPLICATION,"Metric Service not found").build();
212             return Futures.immediateFuture(result);
213         }
214         Map<String,MetricRegistry> allMetricRegitry = metricService.getAllRegistry();
215
216         if(allMetricRegitry == null || allMetricRegitry.isEmpty()){
217             logger.error("No metrics registered returning failure");
218             RpcResult<GetMetricsOutput> result = RpcResultBuilder.<GetMetricsOutput> status(false).withError(RpcError.ErrorType.APPLICATION,"No metrics Registered").build();
219             return Futures.immediateFuture(result);
220         }
221         List<Metrics> metricsList = new ArrayList<>();
222
223         logger.debug("Iterating metric registry list");
224         for (MetricRegistry metricRegistry :  allMetricRegitry.values() ) {
225             logger.debug("Iterating metric registry :" + metricRegistry.toString());
226             Metric[] metrics = metricRegistry.metrics() ;
227             if(metrics!= null && metrics.length >0) {
228                 logger.debug("Iterating though metrics in registry");
229                 for (Metric metric : metrics) {
230                     logger.debug("Iterating though metrics: "+ metric.name());
231                     MetricsBuilder metricsBuilder = new MetricsBuilder();
232                     metricsBuilder.setKpiName(metric.name());
233                     metricsBuilder.setLastResetTime(metric.getLastModified());
234                     List<KpiValues> kpiList = new ArrayList<>();
235                     Map<String, String> metricsOutput = metric.getMetricsOutput();
236                     for (Map.Entry<String, String> kpi : metricsOutput.entrySet()) {
237                         KpiValuesBuilder kpiValuesBuilder = new KpiValuesBuilder();
238                         kpiValuesBuilder.setName(kpi.getKey());
239                         kpiValuesBuilder.setValue(kpi.getValue());
240                         kpiList.add(kpiValuesBuilder.build());
241                     }
242                     metricsBuilder.setKpiValues(kpiList);
243                     metricsList.add(metricsBuilder.build());
244                 }
245             }
246         }
247         outputBuilder.setMetrics(metricsList);
248         RpcResult<GetMetricsOutput> result = RpcResultBuilder.<GetMetricsOutput> status(true).withResult(outputBuilder.build()).build();
249         return Futures.immediateFuture(result);
250     }
251
252     @Override
253     public Future<RpcResult<StopOutput>> stop(StopInput stopInput){
254         logger.debug("Input received : " + stopInput);
255         final Date startTime = new Date();
256         Status status = this.buildStatus(OAMCommandStatus.ACCEPTED);
257         final  CommonHeader commonHeader = stopInput.getCommonHeader();
258
259         try {
260             setInitialLogProperties(commonHeader,RPC.stop);
261
262             //Close the gate so that no more new LCM request will be excepted.
263             LCMStateManager lcmStateManager = getService(LCMStateManager.class);
264             lcmStateManager.disableLCMOperations();
265             //Begin monitoring outstanding LCM request
266             scheduleOutstandingLCMRequestMonitor(commonHeader,startTime);
267         } catch(Throwable t) {
268             status = unexpectedOAMError(t,RPC.stop);
269         }
270         finally {
271             LoggingUtils.auditWarn(startTime.toInstant(),
272                     new Date(System.currentTimeMillis()).toInstant(),
273                     String.valueOf(status.getCode()),
274                     status.getMessage(),
275                     this.getClass().getCanonicalName(),
276                     Msg.OAM_OPERATION_STOPPING,
277                     getAppcName()
278             );
279             this.clearRequestLogProperties();
280         }
281
282         StopOutputBuilder stopOutputBuilder = new StopOutputBuilder();
283         stopOutputBuilder.setStatus(status);
284         stopOutputBuilder.setCommonHeader(commonHeader);
285         StopOutput stopOutput = stopOutputBuilder.build();
286         return RpcResultBuilder.success(stopOutput).buildFuture();
287     }
288
289     @Override
290     public Future<RpcResult<StartOutput>> start(StartInput startInput){
291         logger.debug("Input received : " + startInput);
292         final Date startTime = new Date();
293         Status status = this.buildStatus(OAMCommandStatus.ACCEPTED);
294         final CommonHeader commonHeader = startInput.getCommonHeader();
295
296         try {
297
298
299             setInitialLogProperties(commonHeader,RPC.start);
300
301             this.scheduleStartingAPPC(commonHeader,startTime);
302         } catch(Throwable t) {
303             status = unexpectedOAMError(t,RPC.start);
304         }
305         finally {
306             LoggingUtils.auditWarn(startTime.toInstant(),
307                     new Date(System.currentTimeMillis()).toInstant(),
308                     String.valueOf(status.getCode()),
309                     status.getMessage(),
310                     this.getClass().getCanonicalName(),
311                     Msg.OAM_OPERATION_STARTING,
312                     getAppcName()
313             );
314             this.clearRequestLogProperties();
315         }
316
317         StartOutputBuilder startOutputBuilder = new StartOutputBuilder();
318         startOutputBuilder.setStatus(status);
319         startOutputBuilder.setCommonHeader(commonHeader);
320         StartOutput startOutput = startOutputBuilder.build();
321         return RpcResultBuilder.success(startOutput).buildFuture();
322     }
323
324     private <T> T getService(Class<T> _class) throws APPCException {
325         BundleContext bctx = FrameworkUtil.getBundle(_class).getBundleContext();
326         ServiceReference sref = bctx.getServiceReference(_class.getName());
327         if (sref != null) {
328             if(logger.isTraceEnabled()) {
329                 logger.debug("Using the BundleContext to fetched the service reference for " + _class.getName());
330
331             }
332             return (T) bctx.getService(sref);
333         } else {
334             throw new APPCException("Using the BundleContext failed to to fetch service reference for " + _class.getName());
335         }
336     }
337
338     private Status buildStatus(OAMCommandStatus osmCommandStatus){
339         StatusBuilder status = new StatusBuilder();
340         status.setCode(osmCommandStatus.getResponseCode());
341         status.setMessage(osmCommandStatus.getResponseMessage());
342         return status.build();
343     }
344
345     private Status buildStatus(OAMCommandStatus osmCommandStatus,Params params){
346         StatusBuilder status = new StatusBuilder();
347         status.setCode(osmCommandStatus.getResponseCode());
348         status.setMessage(osmCommandStatus.getFormattedMessage(params));
349         return status.build();
350     }
351
352
353
354     private void clearRequestLogProperties() {
355         try {
356             MDC.remove(MDC_KEY_REQUEST_ID);
357             MDC.remove(MDC_SERVICE_INSTANCE_ID);
358             MDC.remove(MDC_SERVICE_NAME);
359             MDC.remove(LoggingConstants.MDCKeys.PARTNER_NAME);
360             MDC.remove(LoggingConstants.MDCKeys.TARGET_VIRTUAL_ENTITY);
361         } catch (Exception e) {
362
363         }
364     }
365
366     private void setInitialLogProperties(CommonHeader commonHeader,RPC action) {
367
368         try {
369             MDC.put(MDC_KEY_REQUEST_ID, commonHeader.getRequestId());
370             MDC.put(LoggingConstants.MDCKeys.PARTNER_NAME, commonHeader.getOriginatorId());
371             MDC.put(MDC_INSTANCE_UUID, ""); // value should be created in the future
372             try {
373                 MDC.put(MDC_SERVER_FQDN, InetAddress.getLocalHost().getCanonicalHostName()); //Don't change it to a .getHostName() again please. It's wrong!
374                 MDC.put(MDC_SERVER_IP_ADDRESS, InetAddress.getLocalHost().getHostAddress());
375                 MDC.put(LoggingConstants.MDCKeys.SERVER_NAME, InetAddress.getLocalHost().getHostName());
376                 MDC.put(MDC_SERVICE_NAME, action.name());
377             } catch (Exception e) {
378                 logger.debug("MDC constant error",e);
379             }
380         } catch (RuntimeException e) {
381             //ignore
382         }
383     }
384
385
386     private void storeErrorMessageToLog(Status status, String additionalMessage) {
387         LoggingUtils.logErrorMessage(
388                 String.valueOf(status.getCode()),
389                 status.getMessage(),
390                 LoggingConstants.TargetNames.APPC,
391                 LoggingConstants.TargetNames.APPC_OAM_PROVIDER,
392                 additionalMessage,
393                 this.getClass().getCanonicalName());
394     }
395
396     private String getAppcName(){
397         return configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME);
398     }
399
400     private Status unexpectedOAMError(Throwable t,RPC action){
401         final String appName = getAppcName();
402
403         String exceptionMessage = t.getMessage() != null ? t.getMessage() : t.toString();
404
405         String errorMessage = EELFResourceManager.format(Msg.OAM_OPERATION_EXCEPTION, t, appName, t.getClass().getSimpleName(), action.name(), exceptionMessage);
406
407         Params params = new Params().addParam("errorMsg", exceptionMessage);
408         Status status = buildStatus(
409                 OAMCommandStatus.UNEXPECTED_ERROR,
410                 params
411         );
412
413         storeErrorMessageToLog(status,errorMessage);
414         return status;
415     }
416
417
418     private int getInprogressLCMRequestCount() throws APPCException {
419         RequestHandler requestHandler = getService(RequestHandler.class);
420
421         if(requestHandler == null) {
422             return 0;
423         }
424
425         int inprogressRequestCount = requestHandler.getInprogressRequestCount();
426         return inprogressRequestCount;
427     }
428
429
430
431     private void scheduleOutstandingLCMRequestMonitor(final CommonHeader commonHeader,final Date startTime){
432
433
434         class MyCommand implements Runnable{
435
436             public ScheduledFuture<?> myScheduledFuture = null;
437
438             @Override
439             public void run() {
440                 try {
441                     setInitialLogProperties(commonHeader, RPC.stop);
442
443
444                     logDebug("Executing stopping task ");
445
446                     ScheduledFuture<?> currentScheduledFuture = AppcOam.this.outstandingLCMRequestMonitorSheduledFuture;
447
448                     //cancel myself if I am not the current outstandingLCMRequestMonitor
449                     if(currentScheduledFuture != myScheduledFuture){
450                         myScheduledFuture.cancel(false);
451                         return;
452                     }
453
454                     Status status = buildStatus(OAMCommandStatus.SUCCESS);
455
456
457                     try {
458
459                         //log status and return if there are still LCM request in progress
460                         int inprogressRequestCount = getInprogressLCMRequestCount();
461                         if (inprogressRequestCount > 0) {
462                             logDebug("The application '%s' has '%s' outstanding LCM request to complete before coming to a complete stop.  ",
463                                                 getAppcName(),
464                                                 inprogressRequestCount
465                                         );
466                             return;
467                         }
468
469                     } catch (Throwable t) {
470                         status = unexpectedOAMError(t, RPC.stop);
471                         myScheduledFuture.cancel(false);
472                     }
473
474                     try {
475                         OAMContext oamContext = new OAMContext();
476                         oamContext.setRpcName(RPC.stop);
477                         oamContext.setCommonHeader(commonHeader);
478                         oamContext.setStatus(status);
479                         messageAdapter.post(oamContext);
480                     } catch(Throwable t) {
481                         status = unexpectedOAMError(t,RPC.stop);
482                     }
483
484                     LoggingUtils.auditWarn(startTime.toInstant(),
485                             new Date(System.currentTimeMillis()).toInstant(),
486                             String.valueOf(status.getCode()),
487                             status.getMessage(),
488                             this.getClass().getCanonicalName(),
489                             Msg.OAM_OPERATION_STOPPED,
490                             getAppcName()
491                     );
492                     myScheduledFuture.cancel(false);
493
494                 } finally {
495                     clearRequestLogProperties();
496                 }
497             }
498         };
499
500         MyCommand command = new MyCommand();
501
502         long initialDelay = 10000;
503         long delay = initialDelay;
504
505
506         command.myScheduledFuture = scheduledExecutorService.scheduleWithFixedDelay(
507                 command,
508                 initialDelay,
509                 delay,
510                 TimeUnit.MILLISECONDS
511         );
512         this.outstandingLCMRequestMonitorSheduledFuture = command.myScheduledFuture;
513     }
514
515
516
517
518     private void scheduleStartingAPPC(final CommonHeader commonHeader,final Date startTime){
519
520
521         class MyCommand implements Runnable{
522
523
524             @Override
525             public void run() {
526                 try {
527                     setInitialLogProperties(commonHeader, RPC.start);
528
529                     logDebug("Executing starting task ");
530
531                     Status status = buildStatus(OAMCommandStatus.SUCCESS);
532
533                     try {
534                         LCMStateManager lcmStateManager = getService(LCMStateManager.class);
535                         lcmStateManager.enableLCMOperations();
536                         //cancel the current outstandingLCMRequestMonitor
537                         outstandingLCMRequestMonitorSheduledFuture = null;
538                     } catch(Throwable t) {
539                         status = unexpectedOAMError(t,RPC.start);
540                     }
541
542                     try {
543                        OAMContext oamContext = new OAMContext();
544                        oamContext.setRpcName(RPC.start);
545                        oamContext.setCommonHeader(commonHeader);
546                        oamContext.setStatus(status);
547                        messageAdapter.post(oamContext);
548                     } catch(Throwable t) {
549                       status = unexpectedOAMError(t,RPC.start);
550                     }
551
552                     LoggingUtils.auditWarn(startTime.toInstant(),
553                             new Date(System.currentTimeMillis()).toInstant(),
554                             String.valueOf(status.getCode()),
555                             status.getMessage(),
556                             this.getClass().getCanonicalName(),
557                             Msg.OAM_OPERATION_STARTED,
558                             getAppcName()
559                     );
560                 } finally {
561                     clearRequestLogProperties();
562                 }
563             }
564         };
565
566         MyCommand command = new MyCommand();
567         long initialDelay = 1000;
568
569         scheduledExecutorService.schedule(
570                 command,
571                 initialDelay,
572                 TimeUnit.MILLISECONDS
573         );
574     }
575
576
577     private void logDebug(String message,Object... args){
578         if (logger.isDebugEnabled()) {
579             logger.debug(String.format(message,args));
580         }
581     }
582 }