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