2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
22 package org.openecomp.appc.oam;
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;
62 import java.net.InetAddress;
64 import java.util.concurrent.*;
66 import org.openecomp.appc.oam.messageadapter.*;
69 import static com.att.eelf.configuration.Configuration.*;
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;
76 import java.util.ArrayList;
77 import java.util.List;
79 import java.util.Properties;
80 import java.util.concurrent.Executors;
81 import java.util.concurrent.Future;
84 public class AppcOam implements AutoCloseable, AppcOamService {
86 private Configuration configuration = ConfigurationFactory.getConfiguration();
87 private final EELFLogger logger = EELFManager.getInstance().getLogger(AppcOam.class);
89 private boolean isMetricEnabled = false;
92 private final ScheduledExecutorService scheduledExecutorService;
94 private volatile ScheduledFuture<?> outstandingLCMRequestMonitorSheduledFuture;
97 private MessageAdapter messageAdapter;
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.
104 private DataBroker dataBroker;
107 * ODL Notification Service that provides publish/subscribe capabilities for YANG modeled notifications.
109 private NotificationProviderService notificationService;
112 * Provides a registry for Remote Procedure Call (RPC) service implementations. The RPCs are defined in YANG models.
114 private RpcProviderRegistry rpcRegistry;
117 * Represents our RPC implementation registration
119 private BindingAwareBroker.RpcRegistration<AppcOamService> rpcRegistration;
134 * @param notificationProviderService
135 * @param rpcProviderRegistry
140 public AppcOam(DataBroker dataBroker, NotificationProviderService notificationProviderService,
141 RpcProviderRegistry rpcProviderRegistry) {
143 String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME);
144 logger.info(Msg.COMPONENT_INITIALIZING, appName, "oam");
146 this.dataBroker = dataBroker;
147 this.notificationService = notificationProviderService;
148 this.rpcRegistry = rpcProviderRegistry;
150 if (this.rpcRegistry != null) {
151 rpcRegistration = rpcRegistry.addRpcImplementation(AppcOamService.class, this);
154 Properties properties = configuration.getProperties();
155 if (properties != null && properties.getProperty("metric.enabled") != null) {
156 isMetricEnabled = Boolean.valueOf(properties.getProperty("metric.enabled"));
160 messageAdapter = new MessageAdapter();
161 messageAdapter.init();
164 scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(
168 public Thread newThread(Runnable runnable) {
169 Bundle bundle = FrameworkUtil.getBundle(AppcOam.class);
170 return new Thread(runnable,bundle.getSymbolicName() + " scheduledExecutor");
175 logger.info(Msg.COMPONENT_INITIALIZED, appName, "oam");
179 * Implements the close of the service
181 * @see AutoCloseable#close()
183 @SuppressWarnings("nls")
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();
192 logger.info(Msg.COMPONENT_TERMINATED, appName, "oam");
196 public Future<RpcResult<GetMetricsOutput>> getMetrics() {
198 GetMetricsOutputBuilder outputBuilder = new GetMetricsOutputBuilder();
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);
206 MetricService metricService = null;
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);
214 Map<String,MetricRegistry> allMetricRegitry = metricService.getAllRegistry();
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);
221 List<Metrics> metricsList = new ArrayList<>();
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());
242 metricsBuilder.setKpiValues(kpiList);
243 metricsList.add(metricsBuilder.build());
247 outputBuilder.setMetrics(metricsList);
248 RpcResult<GetMetricsOutput> result = RpcResultBuilder.<GetMetricsOutput> status(true).withResult(outputBuilder.build()).build();
249 return Futures.immediateFuture(result);
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();
260 setInitialLogProperties(commonHeader,RPC.stop);
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);
271 LoggingUtils.auditWarn(startTime.toInstant(),
272 new Date(System.currentTimeMillis()).toInstant(),
273 String.valueOf(status.getCode()),
275 this.getClass().getCanonicalName(),
276 Msg.OAM_OPERATION_STOPPING,
279 this.clearRequestLogProperties();
282 StopOutputBuilder stopOutputBuilder = new StopOutputBuilder();
283 stopOutputBuilder.setStatus(status);
284 stopOutputBuilder.setCommonHeader(commonHeader);
285 StopOutput stopOutput = stopOutputBuilder.build();
286 return RpcResultBuilder.success(stopOutput).buildFuture();
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();
299 setInitialLogProperties(commonHeader,RPC.start);
301 this.scheduleStartingAPPC(commonHeader,startTime);
302 } catch(Throwable t) {
303 status = unexpectedOAMError(t,RPC.start);
306 LoggingUtils.auditWarn(startTime.toInstant(),
307 new Date(System.currentTimeMillis()).toInstant(),
308 String.valueOf(status.getCode()),
310 this.getClass().getCanonicalName(),
311 Msg.OAM_OPERATION_STARTING,
314 this.clearRequestLogProperties();
317 StartOutputBuilder startOutputBuilder = new StartOutputBuilder();
318 startOutputBuilder.setStatus(status);
319 startOutputBuilder.setCommonHeader(commonHeader);
320 StartOutput startOutput = startOutputBuilder.build();
321 return RpcResultBuilder.success(startOutput).buildFuture();
324 private <T> T getService(Class<T> _class) throws APPCException {
325 BundleContext bctx = FrameworkUtil.getBundle(_class).getBundleContext();
326 ServiceReference sref = bctx.getServiceReference(_class.getName());
328 if(logger.isTraceEnabled()) {
329 logger.debug("Using the BundleContext to fetched the service reference for " + _class.getName());
332 return (T) bctx.getService(sref);
334 throw new APPCException("Using the BundleContext failed to to fetch service reference for " + _class.getName());
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();
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();
354 private void clearRequestLogProperties() {
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) {
366 private void setInitialLogProperties(CommonHeader commonHeader,RPC action) {
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
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);
380 } catch (RuntimeException e) {
386 private void storeErrorMessageToLog(Status status, String additionalMessage) {
387 LoggingUtils.logErrorMessage(
388 String.valueOf(status.getCode()),
390 LoggingConstants.TargetNames.APPC,
391 LoggingConstants.TargetNames.APPC_OAM_PROVIDER,
393 this.getClass().getCanonicalName());
396 private String getAppcName(){
397 return configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME);
400 private Status unexpectedOAMError(Throwable t,RPC action){
401 final String appName = getAppcName();
403 String exceptionMessage = t.getMessage() != null ? t.getMessage() : t.toString();
405 String errorMessage = EELFResourceManager.format(Msg.OAM_OPERATION_EXCEPTION, t, appName, t.getClass().getSimpleName(), action.name(), exceptionMessage);
407 Params params = new Params().addParam("errorMsg", exceptionMessage);
408 Status status = buildStatus(
409 OAMCommandStatus.UNEXPECTED_ERROR,
413 storeErrorMessageToLog(status,errorMessage);
418 private int getInprogressLCMRequestCount() throws APPCException {
419 RequestHandler requestHandler = getService(RequestHandler.class);
421 if(requestHandler == null) {
425 int inprogressRequestCount = requestHandler.getInprogressRequestCount();
426 return inprogressRequestCount;
431 private void scheduleOutstandingLCMRequestMonitor(final CommonHeader commonHeader,final Date startTime){
434 class MyCommand implements Runnable{
436 public ScheduledFuture<?> myScheduledFuture = null;
441 setInitialLogProperties(commonHeader, RPC.stop);
444 logDebug("Executing stopping task ");
446 ScheduledFuture<?> currentScheduledFuture = AppcOam.this.outstandingLCMRequestMonitorSheduledFuture;
448 //cancel myself if I am not the current outstandingLCMRequestMonitor
449 if(currentScheduledFuture != myScheduledFuture){
450 myScheduledFuture.cancel(false);
454 Status status = buildStatus(OAMCommandStatus.SUCCESS);
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. ",
464 inprogressRequestCount
469 } catch (Throwable t) {
470 status = unexpectedOAMError(t, RPC.stop);
471 myScheduledFuture.cancel(false);
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);
484 LoggingUtils.auditWarn(startTime.toInstant(),
485 new Date(System.currentTimeMillis()).toInstant(),
486 String.valueOf(status.getCode()),
488 this.getClass().getCanonicalName(),
489 Msg.OAM_OPERATION_STOPPED,
492 myScheduledFuture.cancel(false);
495 clearRequestLogProperties();
500 MyCommand command = new MyCommand();
502 long initialDelay = 10000;
503 long delay = initialDelay;
506 command.myScheduledFuture = scheduledExecutorService.scheduleWithFixedDelay(
510 TimeUnit.MILLISECONDS
512 this.outstandingLCMRequestMonitorSheduledFuture = command.myScheduledFuture;
518 private void scheduleStartingAPPC(final CommonHeader commonHeader,final Date startTime){
521 class MyCommand implements Runnable{
527 setInitialLogProperties(commonHeader, RPC.start);
529 logDebug("Executing starting task ");
531 Status status = buildStatus(OAMCommandStatus.SUCCESS);
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);
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);
552 LoggingUtils.auditWarn(startTime.toInstant(),
553 new Date(System.currentTimeMillis()).toInstant(),
554 String.valueOf(status.getCode()),
556 this.getClass().getCanonicalName(),
557 Msg.OAM_OPERATION_STARTED,
561 clearRequestLogProperties();
566 MyCommand command = new MyCommand();
567 long initialDelay = 1000;
569 scheduledExecutorService.schedule(
572 TimeUnit.MILLISECONDS
577 private void logDebug(String message,Object... args){
578 if (logger.isDebugEnabled()) {
579 logger.debug(String.format(message,args));