diff options
19 files changed, 2687 insertions, 557 deletions
diff --git a/appc-oam/appc-oam-bundle/pom.xml b/appc-oam/appc-oam-bundle/pom.xml index 1da4a7eee..20cfbf819 100644 --- a/appc-oam/appc-oam-bundle/pom.xml +++ b/appc-oam/appc-oam-bundle/pom.xml @@ -1,5 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" +<project + xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> @@ -28,7 +30,7 @@ org.openecomp.appc.adapter.messaging.*, org.openecomp.appc.adapter.message.*, org.openecomp.appc.adapter.factory.*, - org.openecomp.appc.listener.*, + org.openecomp.appc.listener, *;resolution:=optional </Import-Package> <Embed-Dependency> @@ -161,7 +163,21 @@ <artifactId>appc-request-handler-api</artifactId> <version>${project.version}</version> </dependency> - + <dependency> + <groupId>org.openecomp.appc</groupId> + <artifactId>appc-lifecycle-management-api</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.openecomp.appc</groupId> + <artifactId>appc-lifecycle-management-core</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.openecomp.appc</groupId> + <artifactId>state-machine-lib</artifactId> + <version>${project.version}</version> + </dependency> <dependency> <groupId>org.opendaylight.controller</groupId> @@ -207,6 +223,24 @@ <artifactId>junit</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-all</artifactId> + <version>1.10.19</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-api-mockito</artifactId> + <version>1.6.2</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-module-junit4</artifactId> + <version>1.6.2</version> + <scope>test</scope> + </dependency> <!-- TEMP CODE --> <dependency> <groupId>org.json</groupId> @@ -214,30 +248,30 @@ </dependency> - <dependency> - <groupId>org.openecomp.appc</groupId> - <artifactId>appc-message-adapter-api</artifactId> - <version>${project.version}</version> + <dependency> + <groupId>org.openecomp.appc</groupId> + <artifactId>appc-message-adapter-api</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.openecomp.appc</groupId> + <artifactId>appc-message-adapter-factory</artifactId> + <version>${project.version}</version> <scope>provided</scope> - </dependency> - <dependency> - <groupId>org.openecomp.appc</groupId> - <artifactId>appc-message-adapter-factory</artifactId> - <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.openecomp.appc</groupId> + <artifactId>appc-dmaap-adapter-bundle</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.openecomp.appc</groupId> + <artifactId>appc-event-listener-bundle</artifactId> + <version>${project.version}</version> <scope>provided</scope> - </dependency> - <dependency> - <groupId>org.openecomp.appc</groupId> - <artifactId>appc-dmaap-adapter-bundle</artifactId> - <version>${project.version}</version> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>org.openecomp.appc</groupId> - <artifactId>appc-event-listener-bundle</artifactId> - <version>${project.version}</version> - <scope>provided</scope> - </dependency> + </dependency> </dependencies> diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/AppcOam.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/AppcOam.java index 8fd6b2c1a..7ad3b6201 100644 --- a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/AppcOam.java +++ b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/AppcOam.java @@ -24,97 +24,74 @@ package org.openecomp.appc.oam; -import org.openecomp.appc.Constants; -import org.openecomp.appc.configuration.Configuration; -import org.openecomp.appc.configuration.ConfigurationFactory; -import org.openecomp.appc.exceptions.APPCException; -import org.openecomp.appc.executor.objects.Params; -import org.openecomp.appc.i18n.Msg; -import org.openecomp.appc.logging.LoggingConstants; -import org.openecomp.appc.logging.LoggingUtils; -import org.openecomp.appc.metricservice.MetricRegistry; -import org.openecomp.appc.metricservice.MetricService; -import org.openecomp.appc.metricservice.metric.Metric; -import org.openecomp.appc.requesthandler.LCMStateManager; -import org.openecomp.appc.requesthandler.RequestHandler; import com.att.eelf.configuration.EELFLogger; import com.att.eelf.configuration.EELFManager; -import com.att.eelf.i18n.EELFResourceManager; import com.google.common.util.concurrent.Futures; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; import org.opendaylight.controller.sal.binding.api.NotificationProviderService; import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; -import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.*; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.AppcOamService; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.AppcState; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.GetAppcStateOutput; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.GetAppcStateOutputBuilder; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.GetMetricsOutput; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.GetMetricsOutputBuilder; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.MaintenanceModeInput; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.MaintenanceModeOutput; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.MaintenanceModeOutputBuilder; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.RestartInput; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.RestartOutput; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.RestartOutputBuilder; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.StartInput; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.StartOutput; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.StartOutputBuilder; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.StopInput; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.StopOutput; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.StopOutputBuilder; import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.common.header.CommonHeader; import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.get.metrics.output.Metrics; import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.get.metrics.output.MetricsBuilder; import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.get.metrics.output.metrics.KpiValues; import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.get.metrics.output.metrics.KpiValuesBuilder; import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.status.Status; -import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.status.StatusBuilder; import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.common.RpcResultBuilder; -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; -import org.osgi.framework.FrameworkUtil; -import org.osgi.framework.ServiceReference; -import org.slf4j.MDC; - -import java.net.InetAddress; -import java.util.*; -import java.util.concurrent.*; - -import org.openecomp.appc.oam.messageadapter.*; - - -import static com.att.eelf.configuration.Configuration.*; - -import org.opendaylight.yangtools.yang.common.RpcResultBuilder; -import org.osgi.framework.BundleContext; -import org.osgi.framework.FrameworkUtil; -import org.osgi.framework.ServiceReference; +import org.openecomp.appc.exceptions.APPCException; +import org.openecomp.appc.i18n.Msg; +import org.openecomp.appc.metricservice.MetricRegistry; +import org.openecomp.appc.metricservice.MetricService; +import org.openecomp.appc.metricservice.metric.Metric; +import org.openecomp.appc.oam.processor.OamMmodeProcessor; +import org.openecomp.appc.oam.processor.OamRestartProcessor; +import org.openecomp.appc.oam.processor.OamStartProcessor; +import org.openecomp.appc.oam.processor.OamStopProcessor; +import org.openecomp.appc.oam.util.AsyncTaskHelper; +import org.openecomp.appc.oam.util.ConfigurationHelper; +import org.openecomp.appc.oam.util.OperationHelper; +import org.openecomp.appc.oam.util.StateHelper; +import org.openecomp.appc.statemachine.impl.readers.AppcOamMetaDataReader.AppcOperation; import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Properties; -import java.util.concurrent.Executors; import java.util.concurrent.Future; - +/** + * RPC class of APP-C OAM API. + * <p>Implement all the RPCs defined in AppcOamService through yang model definition. + * <p>All RPC methods' JAVADOC are using "inheritDoc" to use the description from the yang model file. + */ public class AppcOam implements AutoCloseable, AppcOamService { - - private Configuration configuration = ConfigurationFactory.getConfiguration(); - private final EELFLogger logger = EELFManager.getInstance().getLogger(AppcOam.class); - - private boolean isMetricEnabled = false; - - - private final ScheduledExecutorService scheduledExecutorService; - - private volatile ScheduledFuture<?> outstandingLCMRequestMonitorSheduledFuture; - - - private MessageAdapter messageAdapter; - - /** - * The ODL data store broker. Provides access to a conceptual data tree store and also provides the ability to - * subscribe for changes to data under a given branch of the tree. + * Invalid state message format with fliexible operation, appc name and state values */ - private DataBroker dataBroker; + public final static String INVALID_STATE_MESSAGE_FORMAT = "%s API is not allowed when %s is in the %s state."; - /** - * ODL Notification Service that provides publish/subscribe capabilities for YANG modeled notifications. - */ - private NotificationProviderService notificationService; + private final EELFLogger logger = EELFManager.getInstance().getLogger(AppcOam.class); - /** - * Provides a registry for Remote Procedure Call (RPC) service implementations. The RPCs are defined in YANG models. - */ - private RpcProviderRegistry rpcRegistry; + private boolean isMetricEnabled = false; /** * Represents our RPC implementation registration @@ -123,62 +100,74 @@ public class AppcOam implements AutoCloseable, AppcOamService { /** - * The yang rpc names + * The yang rpc names with value mapping to AppcOperation */ public enum RPC { - start, - stop, - ; + maintenance_mode(AppcOperation.MaintenanceMode), + start(AppcOperation.Start), + stop(AppcOperation.Stop), + restart(AppcOperation.Restart); + + AppcOperation appcOperation; + + RPC(AppcOperation appcOperation) { + this.appcOperation = appcOperation; + } + + public AppcOperation getAppcOperation() { + return appcOperation; + } } + private AsyncTaskHelper asyncTaskHelper; + private ConfigurationHelper configurationHelper; + private OperationHelper operationHelper; + private StateHelper stateHelper; /** - * @param dataBroker - * @param notificationProviderService - * @param rpcProviderRegistry + * APP-C OAM contructor + * + * @param dataBroker object of The ODL data store broker. Provides access to a conceptual data + * tree store + * and also provides the ability to subscribe for changes to data under a + * given branch + * of the tree. Not used in this class. + * @param notificationProviderService object of ODL Notification Service that provides publish/subscribe + * capabilities for YANG modeled notifications. Not used in this class. + * @param rpcProviderRegistry object of RpcProviderResigstry. Used to register our RPCs. */ - @SuppressWarnings({ - "javadoc", "nls" - }) - public AppcOam(DataBroker dataBroker, NotificationProviderService notificationProviderService, + @SuppressWarnings({"unused", "nls"}) + public AppcOam(DataBroker dataBroker, + NotificationProviderService notificationProviderService, RpcProviderRegistry rpcProviderRegistry) { - String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME); + configurationHelper = new ConfigurationHelper(logger); + String appName = configurationHelper.getAppcName(); logger.info(Msg.COMPONENT_INITIALIZING, appName, "oam"); - this.dataBroker = dataBroker; - this.notificationService = notificationProviderService; - this.rpcRegistry = rpcProviderRegistry; - - if (this.rpcRegistry != null) { - rpcRegistration = rpcRegistry.addRpcImplementation(AppcOamService.class, this); + if (rpcProviderRegistry != null) { + rpcRegistration = rpcProviderRegistry.addRpcImplementation(AppcOamService.class, this); } - Properties properties = configuration.getProperties(); - if (properties != null && properties.getProperty("metric.enabled") != null) { - isMetricEnabled = Boolean.valueOf(properties.getProperty("metric.enabled")); - } - - - messageAdapter = new MessageAdapter(); - messageAdapter.init(); + isMetricEnabled = configurationHelper.isMetricEnabled(); - - scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( - new ThreadFactory(){ - - @Override - public Thread newThread(Runnable runnable) { - Bundle bundle = FrameworkUtil.getBundle(AppcOam.class); - return new Thread(runnable,bundle.getSymbolicName() + " scheduledExecutor"); - } - } - ); + initHelpers(); logger.info(Msg.COMPONENT_INITIALIZED, appName, "oam"); } /** + * Initialize helper classes. + * <p>Note: ConfigurationHelper initializetion is in included here + * because it is needed for extracting the AppName used in the debug logs within the constructor. + */ + private void initHelpers() { + operationHelper = new OperationHelper(); + asyncTaskHelper = new AsyncTaskHelper(logger); + stateHelper = new StateHelper(logger, configurationHelper); + } + + /** * Implements the close of the service * * @see AutoCloseable#close() @@ -186,58 +175,65 @@ public class AppcOam implements AutoCloseable, AppcOamService { @SuppressWarnings("nls") @Override public void close() throws Exception { - String appName = configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME); + String appName = configurationHelper.getAppcName(); logger.info(Msg.COMPONENT_TERMINATING, appName, "oam"); - scheduledExecutorService.shutdown(); + + asyncTaskHelper.close(); + if (rpcRegistration != null) { rpcRegistration.close(); } logger.info(Msg.COMPONENT_TERMINATED, appName, "oam"); } + /** + * {@inheritDoc} + */ @Override public Future<RpcResult<GetMetricsOutput>> getMetrics() { - GetMetricsOutputBuilder outputBuilder = new GetMetricsOutputBuilder(); - - if (!isMetricEnabled){ + if (!isMetricEnabled) { logger.error("Metric Service not enabled returning failure"); - RpcResult<GetMetricsOutput> result = RpcResultBuilder.<GetMetricsOutput> status(false).withError(RpcError.ErrorType.APPLICATION,"Metric Service not enabled").build(); + RpcResult<GetMetricsOutput> result = RpcResultBuilder.<GetMetricsOutput> + status(false).withError(RpcError.ErrorType.APPLICATION, "Metric Service not enabled").build(); return Futures.immediateFuture(result); } - MetricService metricService = null; + MetricService metricService; try { - metricService = getService(MetricService.class); - } catch (APPCException e){ - logger.error("MetricService not found",e); - RpcResult<GetMetricsOutput> result = RpcResultBuilder.<GetMetricsOutput> status(false).withError(RpcError.ErrorType.APPLICATION,"Metric Service not found").build(); + metricService = operationHelper.getService(MetricService.class); + } catch (APPCException e) { + logger.error("MetricService not found", e); + RpcResult<GetMetricsOutput> result = RpcResultBuilder.<GetMetricsOutput> + status(false).withError(RpcError.ErrorType.APPLICATION, "Metric Service not found").build(); return Futures.immediateFuture(result); } - Map<String,MetricRegistry> allMetricRegitry = metricService.getAllRegistry(); - if(allMetricRegitry == null || allMetricRegitry.isEmpty()){ + Map<String, MetricRegistry> allMetricRegitry = metricService.getAllRegistry(); + if (allMetricRegitry == null || allMetricRegitry.isEmpty()) { logger.error("No metrics registered returning failure"); - RpcResult<GetMetricsOutput> result = RpcResultBuilder.<GetMetricsOutput> status(false).withError(RpcError.ErrorType.APPLICATION,"No metrics Registered").build(); + RpcResult<GetMetricsOutput> result = RpcResultBuilder.<GetMetricsOutput> + status(false).withError(RpcError.ErrorType.APPLICATION, "No metrics Registered").build(); return Futures.immediateFuture(result); } + List<Metrics> metricsList = new ArrayList<>(); logger.debug("Iterating metric registry list"); - for (MetricRegistry metricRegistry : allMetricRegitry.values() ) { + for (MetricRegistry metricRegistry : allMetricRegitry.values()) { logger.debug("Iterating metric registry :" + metricRegistry.toString()); - Metric[] metrics = metricRegistry.metrics() ; - if(metrics!= null && metrics.length >0) { + Metric[] metrics = metricRegistry.metrics(); + if (metrics != null && metrics.length > 0) { logger.debug("Iterating though metrics in registry"); for (Metric metric : metrics) { - logger.debug("Iterating though metrics: "+ metric.name()); + logger.debug("Iterating though metrics: " + metric.name()); MetricsBuilder metricsBuilder = new MetricsBuilder(); metricsBuilder.setKpiName(metric.name()); metricsBuilder.setLastResetTime(metric.getLastModified()); List<KpiValues> kpiList = new ArrayList<>(); Map<String, String> metricsOutput = metric.getMetricsOutput(); for (Map.Entry<String, String> kpi : metricsOutput.entrySet()) { - KpiValuesBuilder kpiValuesBuilder = new KpiValuesBuilder(); + KpiValuesBuilder kpiValuesBuilder = new KpiValuesBuilder(); kpiValuesBuilder.setName(kpi.getKey()); kpiValuesBuilder.setValue(kpi.getValue()); kpiList.add(kpiValuesBuilder.build()); @@ -247,339 +243,97 @@ public class AppcOam implements AutoCloseable, AppcOamService { } } } + + GetMetricsOutputBuilder outputBuilder = new GetMetricsOutputBuilder(); outputBuilder.setMetrics(metricsList); - RpcResult<GetMetricsOutput> result = RpcResultBuilder.<GetMetricsOutput> status(true).withResult(outputBuilder.build()).build(); + RpcResult<GetMetricsOutput> result = RpcResultBuilder.<GetMetricsOutput> + status(true).withResult(outputBuilder.build()).build(); return Futures.immediateFuture(result); } + /** + * {@inheritDoc} + */ @Override - public Future<RpcResult<StopOutput>> stop(StopInput stopInput){ - logger.debug("Input received : " + stopInput); - final Date startTime = new Date(); - Status status = this.buildStatus(OAMCommandStatus.ACCEPTED); - final CommonHeader commonHeader = stopInput.getCommonHeader(); + public Future<RpcResult<StopOutput>> stop(StopInput stopInput) { + logger.debug("Entering Stop with Input : " + stopInput); + final CommonHeader commonHeader = stopInput.getCommonHeader(); - try { - setInitialLogProperties(commonHeader,RPC.stop); - - //Close the gate so that no more new LCM request will be excepted. - LCMStateManager lcmStateManager = getService(LCMStateManager.class); - lcmStateManager.disableLCMOperations(); - //Begin monitoring outstanding LCM request - scheduleOutstandingLCMRequestMonitor(commonHeader,startTime); - } catch(Throwable t) { - status = unexpectedOAMError(t,RPC.stop); - } - finally { - LoggingUtils.auditWarn(startTime.toInstant(), - new Date(System.currentTimeMillis()).toInstant(), - String.valueOf(status.getCode()), - status.getMessage(), - this.getClass().getCanonicalName(), - Msg.OAM_OPERATION_STOPPING, - getAppcName() - ); - this.clearRequestLogProperties(); - } + OamStopProcessor oamStopProcessor = + new OamStopProcessor(logger, configurationHelper, stateHelper, asyncTaskHelper, operationHelper); + Status status = oamStopProcessor.processRequest(stopInput); StopOutputBuilder stopOutputBuilder = new StopOutputBuilder(); stopOutputBuilder.setStatus(status); stopOutputBuilder.setCommonHeader(commonHeader); - StopOutput stopOutput = stopOutputBuilder.build(); - return RpcResultBuilder.success(stopOutput).buildFuture(); + return RpcResultBuilder.success(stopOutputBuilder.build()).buildFuture(); } + /** + * {@inheritDoc} + */ @Override - public Future<RpcResult<StartOutput>> start(StartInput startInput){ - logger.debug("Input received : " + startInput); - final Date startTime = new Date(); - Status status = this.buildStatus(OAMCommandStatus.ACCEPTED); - final CommonHeader commonHeader = startInput.getCommonHeader(); - - try { - - - setInitialLogProperties(commonHeader,RPC.start); - - this.scheduleStartingAPPC(commonHeader,startTime); - } catch(Throwable t) { - status = unexpectedOAMError(t,RPC.start); - } - finally { - LoggingUtils.auditWarn(startTime.toInstant(), - new Date(System.currentTimeMillis()).toInstant(), - String.valueOf(status.getCode()), - status.getMessage(), - this.getClass().getCanonicalName(), - Msg.OAM_OPERATION_STARTING, - getAppcName() - ); - this.clearRequestLogProperties(); - } - - StartOutputBuilder startOutputBuilder = new StartOutputBuilder(); - startOutputBuilder.setStatus(status); - startOutputBuilder.setCommonHeader(commonHeader); - StartOutput startOutput = startOutputBuilder.build(); - return RpcResultBuilder.success(startOutput).buildFuture(); - } + public Future<RpcResult<RestartOutput>> restart(RestartInput input) { + logger.debug("Entering restart with Input : " + input); + final CommonHeader commonHeader = input.getCommonHeader(); - private <T> T getService(Class<T> _class) throws APPCException { - BundleContext bctx = FrameworkUtil.getBundle(_class).getBundleContext(); - ServiceReference sref = bctx.getServiceReference(_class.getName()); - if (sref != null) { - if(logger.isTraceEnabled()) { - logger.debug("Using the BundleContext to fetched the service reference for " + _class.getName()); + OamRestartProcessor oamRestartProcessor = + new OamRestartProcessor(logger, configurationHelper, stateHelper, asyncTaskHelper, operationHelper); + Status status = oamRestartProcessor.processRequest(input); - } - return (T) bctx.getService(sref); - } else { - throw new APPCException("Using the BundleContext failed to to fetch service reference for " + _class.getName()); - } - } - - private Status buildStatus(OAMCommandStatus osmCommandStatus){ - StatusBuilder status = new StatusBuilder(); - status.setCode(osmCommandStatus.getResponseCode()); - status.setMessage(osmCommandStatus.getResponseMessage()); - return status.build(); - } + RestartOutputBuilder restartOutputBuilder = new RestartOutputBuilder(); + restartOutputBuilder.setStatus(status); + restartOutputBuilder.setCommonHeader(commonHeader); - private Status buildStatus(OAMCommandStatus osmCommandStatus,Params params){ - StatusBuilder status = new StatusBuilder(); - status.setCode(osmCommandStatus.getResponseCode()); - status.setMessage(osmCommandStatus.getFormattedMessage(params)); - return status.build(); + return RpcResultBuilder.success(restartOutputBuilder.build()).buildFuture(); } - - - private void clearRequestLogProperties() { - try { - MDC.remove(MDC_KEY_REQUEST_ID); - MDC.remove(MDC_SERVICE_INSTANCE_ID); - MDC.remove(MDC_SERVICE_NAME); - MDC.remove(LoggingConstants.MDCKeys.PARTNER_NAME); - MDC.remove(LoggingConstants.MDCKeys.TARGET_VIRTUAL_ENTITY); - } catch (Exception e) { - - } - } - - private void setInitialLogProperties(CommonHeader commonHeader,RPC action) { - - try { - MDC.put(MDC_KEY_REQUEST_ID, commonHeader.getRequestId()); - MDC.put(LoggingConstants.MDCKeys.PARTNER_NAME, commonHeader.getOriginatorId()); - MDC.put(MDC_INSTANCE_UUID, ""); // value should be created in the future - try { - MDC.put(MDC_SERVER_FQDN, InetAddress.getLocalHost().getCanonicalHostName()); //Don't change it to a .getHostName() again please. It's wrong! - MDC.put(MDC_SERVER_IP_ADDRESS, InetAddress.getLocalHost().getHostAddress()); - MDC.put(LoggingConstants.MDCKeys.SERVER_NAME, InetAddress.getLocalHost().getHostName()); - MDC.put(MDC_SERVICE_NAME, action.name()); - } catch (Exception e) { - logger.debug("MDC constant error",e); - } - } catch (RuntimeException e) { - //ignore - } - } - - - private void storeErrorMessageToLog(Status status, String additionalMessage) { - LoggingUtils.logErrorMessage( - String.valueOf(status.getCode()), - status.getMessage(), - LoggingConstants.TargetNames.APPC, - LoggingConstants.TargetNames.APPC_OAM_PROVIDER, - additionalMessage, - this.getClass().getCanonicalName()); - } - - private String getAppcName(){ - return configuration.getProperty(Constants.PROPERTY_APPLICATION_NAME); - } - - private Status unexpectedOAMError(Throwable t,RPC action){ - final String appName = getAppcName(); - - String exceptionMessage = t.getMessage() != null ? t.getMessage() : t.toString(); - - String errorMessage = EELFResourceManager.format(Msg.OAM_OPERATION_EXCEPTION, t, appName, t.getClass().getSimpleName(), action.name(), exceptionMessage); - - Params params = new Params().addParam("errorMsg", exceptionMessage); - Status status = buildStatus( - OAMCommandStatus.UNEXPECTED_ERROR, - params - ); - - storeErrorMessageToLog(status,errorMessage); - return status; - } - - - private int getInprogressLCMRequestCount() throws APPCException { - RequestHandler requestHandler = getService(RequestHandler.class); - - if(requestHandler == null) { - return 0; - } - - int inprogressRequestCount = requestHandler.getInprogressRequestCount(); - return inprogressRequestCount; + /** + * {@inheritDoc} + */ + @Override + public Future<RpcResult<MaintenanceModeOutput>> maintenanceMode(MaintenanceModeInput maintenanceModeInput) { + logger.debug("Entering MaintenanceMode with Input : " + maintenanceModeInput); + final CommonHeader commonHeader = maintenanceModeInput.getCommonHeader(); + + OamMmodeProcessor oamMmodeProcessor = + new OamMmodeProcessor(logger, configurationHelper, stateHelper, asyncTaskHelper, operationHelper); + Status status = oamMmodeProcessor.processRequest(maintenanceModeInput); + + MaintenanceModeOutputBuilder maintenanceModeOutputBuilder = new MaintenanceModeOutputBuilder(); + maintenanceModeOutputBuilder.setStatus(status); + maintenanceModeOutputBuilder.setCommonHeader(commonHeader); + return RpcResultBuilder.success(maintenanceModeOutputBuilder.build()).buildFuture(); } + /** + * {@inheritDoc} + */ + @Override + public Future<RpcResult<GetAppcStateOutput>> getAppcState() { + AppcState appcState = stateHelper.getCurrentOamYangState(); - - private void scheduleOutstandingLCMRequestMonitor(final CommonHeader commonHeader,final Date startTime){ - - - class MyCommand implements Runnable{ - - public ScheduledFuture<?> myScheduledFuture = null; - - @Override - public void run() { - try { - setInitialLogProperties(commonHeader, RPC.stop); - - - logDebug("Executing stopping task "); - - ScheduledFuture<?> currentScheduledFuture = AppcOam.this.outstandingLCMRequestMonitorSheduledFuture; - - //cancel myself if I am not the current outstandingLCMRequestMonitor - if(currentScheduledFuture != myScheduledFuture){ - myScheduledFuture.cancel(false); - return; - } - - Status status = buildStatus(OAMCommandStatus.SUCCESS); - - - try { - - //log status and return if there are still LCM request in progress - int inprogressRequestCount = getInprogressLCMRequestCount(); - if (inprogressRequestCount > 0) { - logDebug("The application '%s' has '%s' outstanding LCM request to complete before coming to a complete stop. ", - getAppcName(), - inprogressRequestCount - ); - return; - } - - } catch (Throwable t) { - status = unexpectedOAMError(t, RPC.stop); - myScheduledFuture.cancel(false); - } - - try { - OAMContext oamContext = new OAMContext(); - oamContext.setRpcName(RPC.stop); - oamContext.setCommonHeader(commonHeader); - oamContext.setStatus(status); - messageAdapter.post(oamContext); - } catch(Throwable t) { - status = unexpectedOAMError(t,RPC.stop); - } - - LoggingUtils.auditWarn(startTime.toInstant(), - new Date(System.currentTimeMillis()).toInstant(), - String.valueOf(status.getCode()), - status.getMessage(), - this.getClass().getCanonicalName(), - Msg.OAM_OPERATION_STOPPED, - getAppcName() - ); - myScheduledFuture.cancel(false); - - } finally { - clearRequestLogProperties(); - } - } - }; - - MyCommand command = new MyCommand(); - - long initialDelay = 10000; - long delay = initialDelay; - - - command.myScheduledFuture = scheduledExecutorService.scheduleWithFixedDelay( - command, - initialDelay, - delay, - TimeUnit.MILLISECONDS - ); - this.outstandingLCMRequestMonitorSheduledFuture = command.myScheduledFuture; + GetAppcStateOutputBuilder builder = new GetAppcStateOutputBuilder(); + builder.setState(appcState); + return RpcResultBuilder.success(builder.build()).buildFuture(); } + /** + * {@inheritDoc} + */ + @Override + public Future<RpcResult<StartOutput>> start(StartInput startInput) { + logger.debug("Input received : " + startInput); + final CommonHeader commonHeader = startInput.getCommonHeader(); + OamStartProcessor oamStartProcessor = + new OamStartProcessor(logger, configurationHelper, stateHelper, asyncTaskHelper, operationHelper); + Status status = oamStartProcessor.processRequest(startInput); - - private void scheduleStartingAPPC(final CommonHeader commonHeader,final Date startTime){ - - - class MyCommand implements Runnable{ - - - @Override - public void run() { - try { - setInitialLogProperties(commonHeader, RPC.start); - - logDebug("Executing starting task "); - - Status status = buildStatus(OAMCommandStatus.SUCCESS); - - try { - LCMStateManager lcmStateManager = getService(LCMStateManager.class); - lcmStateManager.enableLCMOperations(); - //cancel the current outstandingLCMRequestMonitor - outstandingLCMRequestMonitorSheduledFuture = null; - } catch(Throwable t) { - status = unexpectedOAMError(t,RPC.start); - } - - try { - OAMContext oamContext = new OAMContext(); - oamContext.setRpcName(RPC.start); - oamContext.setCommonHeader(commonHeader); - oamContext.setStatus(status); - messageAdapter.post(oamContext); - } catch(Throwable t) { - status = unexpectedOAMError(t,RPC.start); - } - - LoggingUtils.auditWarn(startTime.toInstant(), - new Date(System.currentTimeMillis()).toInstant(), - String.valueOf(status.getCode()), - status.getMessage(), - this.getClass().getCanonicalName(), - Msg.OAM_OPERATION_STARTED, - getAppcName() - ); - } finally { - clearRequestLogProperties(); - } - } - }; - - MyCommand command = new MyCommand(); - long initialDelay = 1000; - - scheduledExecutorService.schedule( - command, - initialDelay, - TimeUnit.MILLISECONDS - ); - } - - - private void logDebug(String message,Object... args){ - if (logger.isDebugEnabled()) { - logger.debug(String.format(message,args)); - } + StartOutputBuilder startOutputBuilder = new StartOutputBuilder(); + startOutputBuilder.setStatus(status); + startOutputBuilder.setCommonHeader(commonHeader); + StartOutput startOutput = startOutputBuilder.build(); + return RpcResultBuilder.success(startOutput).buildFuture(); } } diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/OAMCommandStatus.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/OAMCommandStatus.java index cef242cf5..378fa032d 100644 --- a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/OAMCommandStatus.java +++ b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/OAMCommandStatus.java @@ -34,17 +34,18 @@ public enum OAMCommandStatus { ACCEPTED(100,"ACCEPTED - request accepted"), - //ERROR(2xx) – request can’t be handled due to some technical error + //ERROR(2xx) - request can't be handled due to some technical error UNEXPECTED_ERROR(200,"UNEXPECTED ERROR - ${errorMsg}"), - SUCCESS(400,"SUCCESS - request has been processed successfully"), - ; - + REJECTED(300,"REJECTED - ${errorMsg}"), + INVALID_PARAMETER(302,"INVALID PARAMETER - ${errorMsg}" ), + TIMEOUT(303, "OPERATION TIMEOUT REACHED - ${errorMsg}"), - public static final String errorDgMessageParamName = "errorDgMessage"; + SUCCESS(400,"SUCCESS - request has been processed successfully"), + ; - private int responseCode; - private String responseMessage; + private int responseCode; + private String responseMessage; @@ -52,31 +53,25 @@ public enum OAMCommandStatus { OAMCommandStatus(int responseCode, String responseMessage) { this.responseCode = responseCode; this.responseMessage = responseMessage; - } + } public String getResponseMessage() { - return responseMessage; - } + return responseMessage; + } - public int getResponseCode() { - return responseCode; - } + public int getResponseCode() { + return responseCode; + } - /** + /** * * @return messageTemplate */ - - public String getFormattedMessage(Params params){ - Map<String,Object> paramsMap = params != null ? params.getParams() : null; - return MessageFormatter.format(getResponseMessage(),paramsMap); + Map<String,Object> paramsMap = params != null ? params.getParams() : null; + return MessageFormatter.format(getResponseMessage(),paramsMap); - } - - public String getFormattedMessageWithCode(Params params){ - return getResponseCode()+"-" + getFormattedMessage(params); } @Override @@ -87,4 +82,3 @@ public enum OAMCommandStatus { '}'; } } - diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/messageadapter/Converter.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/messageadapter/Converter.java index e9ccfdd2d..a70d12042 100644 --- a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/messageadapter/Converter.java +++ b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/messageadapter/Converter.java @@ -1,4 +1,4 @@ -/*- +/*-/*- * ============LICENSE_START======================================================= * ONAP : APPC * ================================================================================ @@ -24,9 +24,6 @@ package org.openecomp.appc.oam.messageadapter; -import org.openecomp.appc.oam.AppcOam; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; @@ -35,12 +32,15 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectWriter; -import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.*; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.MaintenanceModeOutputBuilder; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.RestartOutputBuilder; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.StartOutputBuilder; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.StopOutputBuilder; import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.common.header.CommonHeader; import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.status.Status; import org.opendaylight.yangtools.concepts.Builder; import org.opendaylight.yangtools.yang.binding.DataContainer; - +import org.openecomp.appc.oam.AppcOam; import java.text.SimpleDateFormat; import java.util.TimeZone; @@ -48,61 +48,81 @@ import java.util.TimeZone; public class Converter { private static final String ISO_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; private static final SimpleDateFormat isoFormatter = new SimpleDateFormat(ISO_FORMAT); - private static final EELFLogger logger = EELFManager.getInstance().getLogger(Converter.class); + static { isoFormatter.setTimeZone(TimeZone.getTimeZone("UTC")); } - private static Builder<?> convAsyncResponseToBuilder1(AppcOam.RPC rpcName, CommonHeader commonHeader, Status status) { - Builder<?> outObj = null; - if(rpcName == null){ + private static Builder<?> convAsyncResponseToBuilder1(AppcOam.RPC rpcName, + CommonHeader commonHeader, + Status status) { + Builder<?> outObj; + if (rpcName == null) { throw new IllegalArgumentException("empty asyncResponse.rpcName"); } - if(commonHeader == null){ + if (commonHeader == null) { throw new IllegalArgumentException("empty asyncResponse.commonHeader"); } - if(status == null){ + if (status == null) { throw new IllegalArgumentException("empty asyncResponse.status"); } - switch (rpcName){ - case stop: - outObj = new StopOutputBuilder(); - ((StopOutputBuilder)outObj).setCommonHeader(commonHeader); - ((StopOutputBuilder)outObj).setStatus(status); + switch (rpcName) { + case maintenance_mode: + outObj = new MaintenanceModeOutputBuilder(); + ((MaintenanceModeOutputBuilder) outObj).setCommonHeader(commonHeader); + ((MaintenanceModeOutputBuilder) outObj).setStatus(status); return outObj; case start: outObj = new StartOutputBuilder(); - ((StartOutputBuilder)outObj).setCommonHeader(commonHeader); - ((StartOutputBuilder)outObj).setStatus(status); + ((StartOutputBuilder) outObj).setCommonHeader(commonHeader); + ((StartOutputBuilder) outObj).setStatus(status); + return outObj; + + case stop: + outObj = new StopOutputBuilder(); + ((StopOutputBuilder) outObj).setCommonHeader(commonHeader); + ((StopOutputBuilder) outObj).setStatus(status); + return outObj; + + case restart: + outObj = new RestartOutputBuilder(); + ((RestartOutputBuilder) outObj).setCommonHeader(commonHeader); + ((RestartOutputBuilder) outObj).setStatus(status); return outObj; + default: - throw new IllegalArgumentException(rpcName+" action is not supported"); + throw new IllegalArgumentException(rpcName + " action is not supported"); } } - public static String convAsyncResponseToUebOutgoingMessageJsonString(OAMContext oamContext) throws JsonProcessingException { + static String convAsyncResponseToUebOutgoingMessageJsonString(OAMContext oamContext) throws + JsonProcessingException { AppcOam.RPC rpcName = oamContext.getRpcName(); CommonHeader commonHeader = oamContext.getCommonHeader(); Status status = oamContext.getStatus(); - DmaapOutgoingMessage dmaapOutgoingMessage = convAsyncResponseToUebOutgoingMessage(rpcName,commonHeader,status); + DmaapOutgoingMessage dmaapOutgoingMessage = convAsyncResponseToUebOutgoingMessage(rpcName, commonHeader, + status); ObjectMapper objectMapper = new ObjectMapper(); - objectMapper.addMixInAnnotations(dmaapOutgoingMessage.getBody().getOutput().getClass(), MixInFlagsMessage.class); + objectMapper.addMixInAnnotations(dmaapOutgoingMessage.getBody().getOutput().getClass(), + MixInFlagsMessage.class); objectMapper.addMixInAnnotations(Status.class, MixIn.class); objectMapper.addMixInAnnotations(CommonHeader.class, MixInCommonHeader.class); - ObjectWriter writer = objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL).configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY,true).writer(); + ObjectWriter writer = objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL).configure + (MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true).writer(); return writer.writeValueAsString(dmaapOutgoingMessage); } - private static DmaapOutgoingMessage convAsyncResponseToUebOutgoingMessage(AppcOam.RPC rpcName, CommonHeader commonHeader, Status status) throws JsonProcessingException { + private static DmaapOutgoingMessage convAsyncResponseToUebOutgoingMessage(AppcOam.RPC rpcName, CommonHeader + commonHeader, Status status) throws JsonProcessingException { DmaapOutgoingMessage outObj = new DmaapOutgoingMessage(); String correlationID = commonHeader.getRequestId(); outObj.setCorrelationID(correlationID); outObj.setType("response"); outObj.setRpcName(rpcName.name()); - Builder<?> builder = Converter.convAsyncResponseToBuilder1(rpcName,commonHeader,status); + Builder<?> builder = Converter.convAsyncResponseToBuilder1(rpcName, commonHeader, status); Object messageBody = builder.build(); DmaapOutgoingMessage.Body body = new DmaapOutgoingMessage.Body(messageBody); @@ -112,12 +132,14 @@ public class Converter { abstract class MixIn { + // to be removed during serialization @JsonIgnore - abstract Class<? extends DataContainer> getImplementedInterface(); // to be removed during serialization + abstract Class<? extends DataContainer> getImplementedInterface(); @JsonValue abstract java.lang.String getValue(); } + abstract class MixInCommonHeader extends MixIn { @JsonProperty("request-id") abstract java.lang.String getRequestId(); @@ -126,11 +148,9 @@ public class Converter { abstract java.lang.String getOriginatorId(); } + abstract class MixInFlagsMessage extends MixIn { @JsonProperty("common-header") - abstract CommonHeader getCommonHeader(); + abstract CommonHeader getCommonHeader(); } - - - } diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/messageadapter/MessageAdapter.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/messageadapter/MessageAdapter.java index 21f096678..d93feabe4 100644 --- a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/messageadapter/MessageAdapter.java +++ b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/messageadapter/MessageAdapter.java @@ -32,7 +32,6 @@ import org.openecomp.appc.adapter.message.MessageAdapterFactory; import org.openecomp.appc.adapter.message.Producer; import org.openecomp.appc.configuration.Configuration; import org.openecomp.appc.configuration.ConfigurationFactory; -import org.openecomp.appc.listener.impl.EventHandlerImpl; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.ServiceReference; @@ -42,56 +41,84 @@ import java.util.Properties; public class MessageAdapter { + private final EELFLogger logger = EELFManager.getInstance().getLogger(MessageAdapter.class); + + private final String PROP_APPC_OAM_DISABLED = "appc.OAM.disabled"; + private final String PROP_APPC_OAM_TOPIC_WRITE = "appc.OAM.topic.write"; + private String PROP_APPC_OAM_CLIENT_KEY = "appc.OAM.client.key"; + private String PROP_APPC_OAM_CLIENT_SECRET = "appc.OAM.client.secret"; + private String PROP_APPC_OAM_POOLMEMBERS = "appc.OAM.poolMembers"; + private Producer producer; - private String partition ; + private String partition; private Configuration configuration; private HashSet<String> pool; private String writeTopic; private String apiKey; private String apiSecret; - - private static final EELFLogger logger = EELFManager.getInstance().getLogger(MessageAdapter.class); + private boolean isDisabled; /** - * Initialize producer client to post messages using configuration properties + * Initialize producer client to post messages using configuration properties. */ - public void init(){ - this.producer = getProducer(); - } - - private Producer getProducer() { + public void init() { configuration = ConfigurationFactory.getConfiguration(); - Properties properties=configuration.getProperties(); + Properties properties = configuration.getProperties(); updateProperties(properties); - Producer localProducer = null; - + + if (isAppcOamPropsListenerEnabled()) { + createProducer(); + } else { + logger.warn(String.format("The listener %s is disabled and will not be run", "appc.OAM")); + } + } + + /** + * Create producer using MessageAdapterFactory which is found through bundle context. + */ + void createProducer() { BundleContext ctx = FrameworkUtil.getBundle(MessageAdapter.class).getBundleContext(); - if (ctx != null) { - ServiceReference svcRef = ctx.getServiceReference(MessageAdapterFactory.class.getName()); - if (svcRef != null) { - localProducer = ((MessageAdapterFactory) ctx.getService(svcRef)).createProducer(pool, writeTopic, apiKey, apiSecret); - for (String url : pool) { - if (url.contains("3905") || url.contains("https")) { - localProducer.useHttps(true); - break; - } - } - } + if (ctx == null) { + logger.warn("MessageAdapter cannot create producer due to no bundle context."); + return; } - return localProducer; + ServiceReference svcRef = ctx.getServiceReference(MessageAdapterFactory.class.getName()); + if (svcRef == null) { + logger.warn("MessageAdapter cannot create producer due to no MessageAdapterFactory service reference."); + return; + } + + Producer localProducer = ((MessageAdapterFactory) ctx.getService(svcRef)).createProducer(pool, writeTopic, + apiKey, apiSecret); + + for (String url : pool) { + if (url.contains("3905") || url.contains("https")) { + localProducer.useHttps(true); + break; + } + } + + producer = localProducer; + + logger.debug("MessageAdapter created producer."); } + /** + * Read property value to set writeTopic, apiKey, apiSecret and pool. + * + * @param props of configuration + */ private void updateProperties(Properties props) { - if (logger.isTraceEnabled()) { - logger.trace("Entering to updateProperties with Properties = "+ ObjectUtils.toString(props)); - } + logger.trace("Entering to updateProperties with Properties = " + ObjectUtils.toString(props)); + pool = new HashSet<>(); if (props != null) { - writeTopic = props.getProperty("appc.OAM.topic.write"); - apiKey = props.getProperty("appc.OAM.client.key"); - apiSecret = props.getProperty("appc.OAM.client.secret"); - String hostnames = props.getProperty("appc.OAM.poolMembers"); + isDisabled = Boolean.parseBoolean(props.getProperty(PROP_APPC_OAM_DISABLED)); + writeTopic = props.getProperty(PROP_APPC_OAM_TOPIC_WRITE); + apiKey = props.getProperty(PROP_APPC_OAM_CLIENT_KEY); + apiSecret = props.getProperty(PROP_APPC_OAM_CLIENT_SECRET); + String hostnames = props.getProperty(PROP_APPC_OAM_POOLMEMBERS); if (hostnames != null && !hostnames.isEmpty()) { for (String name : hostnames.split(",")) { pool.add(name); @@ -101,33 +128,56 @@ public class MessageAdapter { } /** - * Posts message to UEB. As UEB accepts only json messages this method first convert uebMessage to json format and post it to UEB. - * @param oamContext response data that based on it a message will be send to UEB (the format of the message that will be sent to UEB based on the action and its YANG domainmodel). - * @return True if message is postes successfully else False + * Get producer. If it is null, call createProducer to create it again. + * + * @return Producer */ - public boolean post(OAMContext oamContext){ - boolean success; + Producer getProducer() { + if (producer == null) { + // In case, producer was not properly set yet, set it again. + logger.info("Calling createProducer as producer is null."); + createProducer(); + } + + return producer; + } + + /** + * Posts message to UEB. As UEB accepts only json messages this method first convert uebMessage to json format + * and post it to UEB. + * + * @param oamContext response data that based on it a message will be send to UEB (the format of the message that + * will be sent to UEB based on the action and its YANG domainmodel). + */ + public void post(OAMContext oamContext) { if (logger.isTraceEnabled()) { logger.trace("Entering to post with AsyncResponse = " + ObjectUtils.toString(oamContext)); } + boolean success; String jsonMessage; try { jsonMessage = Converter.convAsyncResponseToUebOutgoingMessageJsonString(oamContext); if (logger.isDebugEnabled()) { logger.debug("UEB Response = " + jsonMessage); } - success = producer.post(this.partition, jsonMessage); + + Producer myProducer = getProducer(); + success = myProducer != null && myProducer.post(this.partition, jsonMessage); } catch (JsonProcessingException e1) { - logger.error("Error generating Jason from UEB message "+ e1.getMessage()); - success= false; - }catch (Exception e){ - logger.error("Error sending message to UEB "+e.getMessage()); - success= false; + logger.error("Error generating Json from UEB message " + e1.getMessage()); + success = false; + } catch (Exception e) { + logger.error("Error sending message to UEB " + e.getMessage(), e); + success = false; } + if (logger.isTraceEnabled()) { - logger.trace("Exiting from post with (success = "+ ObjectUtils.toString(success)+")"); + logger.trace("Exiting from post with (success = " + ObjectUtils.toString(success) + ")"); } - return success; + } + + private boolean isAppcOamPropsListenerEnabled() { + return !isDisabled; } } diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/BaseActionRunnable.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/BaseActionRunnable.java new file mode 100644 index 000000000..5df2c805e --- /dev/null +++ b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/BaseActionRunnable.java @@ -0,0 +1,207 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.appc.oam.processor; + +import org.openecomp.appc.i18n.Msg; +import org.openecomp.appc.oam.OAMCommandStatus; +import org.openecomp.appc.statemachine.impl.readers.AppcOamStates; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Future; + +/** + * Base runnable actions for OAM APIs, such as maintenance mode, restart, start and stop API. + * + * <p>This class holds the general action async handling methods for all OAM APIs. + * <p>Specific API action runnable will overwrite the general methods to add specific behaviors. + * + * <p>Subclass constructor must set the following class variables: + * <br> - actionName + * <br> - auditMsg + * <br> - finalState + */ +abstract class BaseActionRunnable extends BaseCommon implements Runnable { + final String OAM_OPERATION_TIMEOUT_SECOND = "appc.OAM.api.timeout"; + /** Default operation tiemout set to 1 minute */ + final int DEFAULT_OAM_OPERATION_TIMEOUT = 60; + /** Abort message format with flexible operation name */ + final String ABORT_MESSAGE_FORMAT = "Aborting %s operation."; + /** Timeout message format with flexible operation name */ + final String TIMEOUT_MESSAGE_FORMAT = "%s operation has reached timeout %d milliseconds."; + + private boolean isWaiting = false; + private AppcOamStates currentState; + long startTimeMs = 0; + long timeoutMs = 0; + boolean doTimeoutChecking = false; + + String actionName = "Need to be reset"; + Msg auditMsg; + AppcOamStates finalState; + + BaseProcessor myParent; + Map<String, Future<?>> bundleNameToFuture = new HashMap<>(); + + BaseActionRunnable(BaseProcessor parent) { + super(parent.logger, parent.configurationHelper, parent.stateHelper, parent.operationHelper); + + rpc = parent.rpc; + commonHeader = parent.commonHeader; + startTime = parent.startTime; + myParent = parent; + + setTimeoutValues(); + } + + void setTimeoutValues() { + Integer timeoutSeconds = myParent.timeoutSeconds; + if (timeoutSeconds == null) { + timeoutMs = configurationHelper.getConfig().getIntegerProperty( + OAM_OPERATION_TIMEOUT_SECOND, DEFAULT_OAM_OPERATION_TIMEOUT) * 1000; + } else { + timeoutMs = timeoutSeconds.longValue() * 1000; + } + + doTimeoutChecking = timeoutMs != 0; + if (doTimeoutChecking) { + startTimeMs = startTime.getTime(); + } + logDebug("%s action runnable check timeout (%s) with timeout (%d)ms, and startMs (%d)", + rpc.name(), Boolean.toString(doTimeoutChecking), timeoutMs, startTimeMs); + } + + @Override + public void run() { + try { + setInitialLogProperties(); + logDebug(String.format("===========in %s run (waiting: %s)=======", + actionName, Boolean.toString(isWaiting))); + + if (isWaiting) { + if (!checkState()) { + keepWaiting(); + } + } else { + if (doAction()) { + isWaiting = !checkState(); + } else { + postDoAction(false); + } + } + } catch (Exception e) { + logDebug(String.format("%s got exception %s", actionName, e.getMessage())); + logger.error(actionName + " exception", e); + + } finally { + clearRequestLogProperties(); + } + } + + void keepWaiting() { + logDebug(String.format("%s runnable waiting, current state is %s.", + actionName, currentState == null ? "null" : currentState.toString())); + + isTimeout("keepWaiting"); + } + + boolean isTimeout(String parentName) { + logDebug(String.format("%s task isTimeout called from %s", actionName, parentName)); + if (doTimeoutChecking + && System.currentTimeMillis() - startTimeMs > timeoutMs) { + logger.error(String.format("%s operation timeout (%d) ms has reached, abort with error state.", + actionName, timeoutMs)); + + setStatus(OAMCommandStatus.TIMEOUT, String.format(TIMEOUT_MESSAGE_FORMAT, rpc.name(), timeoutMs)); + postAction(AppcOamStates.Error); + return true; + } + return false; + } + + /** + * Set class <b>status</b> to REJECTED with abort message. + */ + void setAbortStatus() { + setStatus(OAMCommandStatus.REJECTED, String.format(ABORT_MESSAGE_FORMAT, rpc.name())); + } + + /** + * Final handling. The thread is cancelled. + * @param setState boolean to indicate if set OAM state or not + */ + void postDoAction(boolean setState) { + logDebug(String.format("Finished %s task", actionName)); + } + + /** + * Handling for after doAction. does post notification, issue audit log and set OAM state based on input + * @param state of AppcOamState to be set as OAM state when it is not null. + */ + void postAction(AppcOamStates state) { + operationHelper.sendNotificationMessage(rpc, commonHeader, status); + + if (state != null) { + stateHelper.setState(state); + } + + auditInfoLog(auditMsg); + + myParent.cancelAsyncTask(); + } + + /** + * Check state + * @return true if final state reached, otherwise return false + */ + boolean checkState() { + if (isTimeout("checkState")) { + myParent.bundleHelper.cancelUnfinished(bundleNameToFuture); + return true; + } + + if (!myParent.bundleHelper.isAllTaskDone(bundleNameToFuture)) { + return false; + } + + long failedTask = myParent.bundleHelper.getFailedMetrics(bundleNameToFuture); + if (failedTask != 0) { + String errorMsg = failedTask + " bundle(s) failed, see logs for details."; + setStatus(OAMCommandStatus.UNEXPECTED_ERROR, errorMsg); + postAction(AppcOamStates.Error); + return true; + } + + currentState = stateHelper.getBundlesState(); + if (currentState == finalState) { + setStatus(OAMCommandStatus.SUCCESS); + postDoAction(true); + return true; + } + return false; + } + + abstract boolean doAction(); +} diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/BaseCommon.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/BaseCommon.java new file mode 100644 index 000000000..cc725e7b9 --- /dev/null +++ b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/BaseCommon.java @@ -0,0 +1,216 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.appc.oam.processor; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.i18n.EELFResourceManager; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.common.header.CommonHeader; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.status.Status; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.status.StatusBuilder; +import org.openecomp.appc.exceptions.InvalidInputException; +import org.openecomp.appc.exceptions.InvalidStateException; +import org.openecomp.appc.executor.objects.Params; +import org.openecomp.appc.i18n.Msg; +import org.openecomp.appc.logging.LoggingConstants; +import org.openecomp.appc.logging.LoggingUtils; +import org.openecomp.appc.oam.AppcOam; +import org.openecomp.appc.oam.OAMCommandStatus; +import org.openecomp.appc.oam.util.ConfigurationHelper; +import org.openecomp.appc.oam.util.OperationHelper; +import org.openecomp.appc.oam.util.StateHelper; +import org.slf4j.MDC; + +import java.net.InetAddress; +import java.util.Date; + +import static com.att.eelf.configuration.Configuration.MDC_INSTANCE_UUID; +import static com.att.eelf.configuration.Configuration.MDC_KEY_REQUEST_ID; +import static com.att.eelf.configuration.Configuration.MDC_SERVER_FQDN; +import static com.att.eelf.configuration.Configuration.MDC_SERVER_IP_ADDRESS; +import static com.att.eelf.configuration.Configuration.MDC_SERVICE_INSTANCE_ID; +import static com.att.eelf.configuration.Configuration.MDC_SERVICE_NAME; + +/** + * Common handling methods of <br> + * - BaseProcessor (for REST sync handling) <br> + * - BaseActionRunnable (for REST async handling) + */ +abstract class BaseCommon { + final EELFLogger logger; + final ConfigurationHelper configurationHelper; + final StateHelper stateHelper; + final OperationHelper operationHelper; + + Status status; + Date startTime; + + AppcOam.RPC rpc; + CommonHeader commonHeader; + + /** + * Constructor + * + * @param eelfLogger for logging + * @param configurationHelperIn for property reading + * @param stateHelperIn for APP-C OAM state checking + * @param operationHelperIn for operational helper + */ + BaseCommon(EELFLogger eelfLogger, + ConfigurationHelper configurationHelperIn, + StateHelper stateHelperIn, + OperationHelper operationHelperIn) { + logger = eelfLogger; + configurationHelper = configurationHelperIn; + stateHelper = stateHelperIn; + operationHelper = operationHelperIn; + } + + /** + * Audit log the passed in message at INFO level. + * @param msg the Msg to be audit logged. + */ + void auditInfoLog(Msg msg) { + LoggingUtils.auditInfo(startTime.toInstant(), + new Date(System.currentTimeMillis()).toInstant(), + String.valueOf(status.getCode()), + status.getMessage(), + getClass().getCanonicalName(), + msg, + configurationHelper.getAppcName(), + stateHelper.getCurrentOamState().toString() + ); + } + + /** + * Set MDC properties. + */ + void setInitialLogProperties() { + MDC.put(MDC_KEY_REQUEST_ID, commonHeader.getRequestId()); + MDC.put(LoggingConstants.MDCKeys.PARTNER_NAME, commonHeader.getOriginatorId()); + MDC.put(MDC_INSTANCE_UUID, ""); // value should be created in the future + MDC.put(MDC_SERVICE_NAME, rpc.name()); + try { + //!!!Don't change the following to a .getHostName() again please. It's wrong!MDC.put(MDC_SERVER_FQDN, + // InetAddress.getLocalHost().getCanonicalHostName()); + MDC.put(MDC_SERVER_FQDN, InetAddress.getLocalHost().getCanonicalHostName()); + MDC.put(MDC_SERVER_IP_ADDRESS, InetAddress.getLocalHost().getHostAddress()); + MDC.put(LoggingConstants.MDCKeys.SERVER_NAME, InetAddress.getLocalHost().getHostName()); + } catch (Exception e) { + logger.error("MDC constant error", e); + } + } + + /** + * Clear MDC properties. + */ + void clearRequestLogProperties() { + try { + MDC.remove(MDC_KEY_REQUEST_ID); + MDC.remove(MDC_SERVICE_INSTANCE_ID); + MDC.remove(MDC_SERVICE_NAME); + MDC.remove(LoggingConstants.MDCKeys.PARTNER_NAME); + MDC.remove(LoggingConstants.MDCKeys.TARGET_VIRTUAL_ENTITY); + } catch (Exception e) { + logger.error("Unable to clear the Request Log properties" + e.getMessage()); + } + } + + /** + * Set class <b>status</b> by calling setStatus(OAMCommandStatus, Params) with null paramter. + * @see #setStatus(OAMCommandStatus, String) + * + * @param oamCommandStatus of the to be set new state + */ + void setStatus(OAMCommandStatus oamCommandStatus) { + setStatus(oamCommandStatus, null); + } + + /** + * Create Status based on the passed in parameter, then set the class <b>status</b> with it. + * + * @param oamCommandStatus of the current OAM command status + * @param message to be set in the new status + */ + void setStatus(OAMCommandStatus oamCommandStatus, String message) { + Params params = new Params().addParam("errorMsg", message); + + StatusBuilder statusBuilder = new StatusBuilder(); + statusBuilder.setCode(oamCommandStatus.getResponseCode()); + if (params != null) { + statusBuilder.setMessage(oamCommandStatus.getFormattedMessage(params)); + } else { + statusBuilder.setMessage(oamCommandStatus.getResponseMessage()); + } + + status = statusBuilder.build(); + } + + /** + * Set class <b>status</b> with error status calculated from the passed in paremeter + * and audit log the error message. + * @param t of the erro Throwable. + */ + void setErrorStatus(Throwable t) { + final String appName = configurationHelper.getAppcName(); + String exceptionMessage = t.getMessage() != null ? t.getMessage() : t.toString(); + + OAMCommandStatus oamCommandStatus; + String errorMessage; + if (t instanceof InvalidInputException) { + oamCommandStatus = OAMCommandStatus.INVALID_PARAMETER; + errorMessage = EELFResourceManager.format(Msg.OAM_OPERATION_INVALID_INPUT, t.getMessage()); + } else if (t instanceof InvalidStateException) { + exceptionMessage = String.format(AppcOam.INVALID_STATE_MESSAGE_FORMAT, + rpc.getAppcOperation(), appName, stateHelper.getCurrentOamState()); + oamCommandStatus = OAMCommandStatus.REJECTED; + errorMessage = EELFResourceManager.format(Msg.INVALID_STATE_TRANSITION, exceptionMessage); + } else { + oamCommandStatus = OAMCommandStatus.UNEXPECTED_ERROR; + errorMessage = EELFResourceManager.format(Msg.OAM_OPERATION_EXCEPTION, t, + appName, t.getClass().getSimpleName(), rpc.name(), exceptionMessage); + } + + setStatus(oamCommandStatus, exceptionMessage); + + LoggingUtils.logErrorMessage( + String.valueOf(status.getCode()), + status.getMessage(), + LoggingConstants.TargetNames.APPC, + LoggingConstants.TargetNames.APPC_OAM_PROVIDER, + errorMessage, + AppcOam.class.getCanonicalName()); + } + + /** + * Genral debug log when debug logging level is enabled. + * @param message of the log message format + * @param args of the objects listed in the message format + */ + void logDebug(String message, Object... args) { + if (logger.isDebugEnabled()) { + logger.debug(String.format(message, args)); + } + } +} diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/BaseProcessor.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/BaseProcessor.java new file mode 100644 index 000000000..6c7011111 --- /dev/null +++ b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/BaseProcessor.java @@ -0,0 +1,166 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.appc.oam.processor; + +import com.att.eelf.configuration.EELFLogger; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.status.Status; +import org.openecomp.appc.exceptions.APPCException; +import org.openecomp.appc.exceptions.InvalidInputException; +import org.openecomp.appc.exceptions.InvalidStateException; +import org.openecomp.appc.i18n.Msg; +import org.openecomp.appc.oam.OAMCommandStatus; +import org.openecomp.appc.oam.util.AsyncTaskHelper; +import org.openecomp.appc.oam.util.BundleHelper; +import org.openecomp.appc.oam.util.ConfigurationHelper; +import org.openecomp.appc.oam.util.OperationHelper; +import org.openecomp.appc.oam.util.StateHelper; +import org.openecomp.appc.statemachine.impl.readers.AppcOamStates; + +import java.util.Date; +import java.util.concurrent.Future; + +/** + * Base processor for OAM APIs, such as maintenance mode, restart, start and stop API. + * + * <p>This class holds the general API request sync handling methods for all OAM APIs. + * <p>Specific API processor will overwrite the general methods to add specific behaviors. + */ +public abstract class BaseProcessor extends BaseCommon { + final AsyncTaskHelper asyncTaskHelper; + final BundleHelper bundleHelper; + + + Integer timeoutSeconds; + Msg auditMsg; + Runnable runnable; + private Future<?> scheduledRunnable = null; + + /** + * Constructor + * + * @param eelfLogger for logging + * @param configurationHelperIn for property reading + * @param stateHelperIn for APP-C OAM state checking + * @param asyncTaskHelperIn for scheduling async task + * @param operationHelperIn for operational helper + */ + BaseProcessor(EELFLogger eelfLogger, + ConfigurationHelper configurationHelperIn, + StateHelper stateHelperIn, + AsyncTaskHelper asyncTaskHelperIn, + OperationHelper operationHelperIn) { + super(eelfLogger, configurationHelperIn, stateHelperIn, operationHelperIn); + + asyncTaskHelper = asyncTaskHelperIn; + bundleHelper = new BundleHelper(eelfLogger, configurationHelper, stateHelper); + } + + /** + * Process synch handling and schedule asynch task + * + * @param requestInput of REST API request + * @return Status of new APP-C OAM state + */ + public Status processRequest(final Object requestInput) { + startTime = new Date(); + commonHeader = operationHelper.getCommonHeader(requestInput); + setStatus(OAMCommandStatus.ACCEPTED); + + try { + preProcess(requestInput); + timeoutSeconds = operationHelper.getParamRequestTimeout(requestInput); + scheduleAsyncTask(); + } catch (Throwable t) { + setErrorStatus(t); + } finally { + postProcess(); + } + + return status; + } + + /** + * Preprocess before actual handling of the REST API call. Does: + * <p> - commonHeader validation + * <p> - get NextState as well as validate if next state is valid + * <p> - set logging properties + * <p> - set appcCurrentState to next state + * + * @throws InvalidInputException when commonHeader validation failed + * @throws APPCException when state validation failed + */ + protected void preProcess(final Object requestInput) + throws InvalidInputException, APPCException, InvalidStateException { + operationHelper.isInputValid(requestInput); + + AppcOamStates nextState = operationHelper.getNextState( + rpc.getAppcOperation(), stateHelper.getCurrentOamState()); + setInitialLogProperties(); + stateHelper.setState(nextState); + } + + /** + * Post process includes audit logging as well as clear MDC properties. + */ + private void postProcess() { + auditInfoLog(auditMsg); + clearRequestLogProperties(); + } + + /** + * Schedule async task through AsyncTaskHelper. + */ + protected void scheduleAsyncTask() { + if (runnable == null) { + logger.error(String.format( + "Skipped schedule async task for rpc(%s) due to runnable is null", rpc.name())); + return; + } + + scheduledRunnable = asyncTaskHelper.scheduleAsyncTask(rpc, runnable); + } + + /** + * Check if current running task is the same as schedule task + * @return true if they are the same, otherwise false. + */ + boolean isSameAsyncTask() { + return asyncTaskHelper.getCurrentAsyncTask() == scheduledRunnable; + } + + /** + * Cancel schedueled async task through AsyncTaskHelper + */ + void cancelAsyncTask() { + if (scheduledRunnable == null) { + logger.error(String.format( + "Skipped cancel schedule async task for rpc(%s) due to scheduledRunnable is null", rpc.name())); + return; + } + + asyncTaskHelper.cancelAsyncTask(scheduledRunnable); + scheduledRunnable = null; + } +} diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/OamMmodeProcessor.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/OamMmodeProcessor.java new file mode 100644 index 000000000..d0d946aed --- /dev/null +++ b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/OamMmodeProcessor.java @@ -0,0 +1,163 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.appc.oam.processor; + +import com.att.eelf.configuration.EELFLogger; +import org.openecomp.appc.exceptions.APPCException; +import org.openecomp.appc.exceptions.InvalidInputException; +import org.openecomp.appc.exceptions.InvalidStateException; +import org.openecomp.appc.i18n.Msg; +import org.openecomp.appc.oam.AppcOam; +import org.openecomp.appc.oam.OAMCommandStatus; +import org.openecomp.appc.oam.util.AsyncTaskHelper; +import org.openecomp.appc.oam.util.ConfigurationHelper; +import org.openecomp.appc.oam.util.OperationHelper; +import org.openecomp.appc.oam.util.StateHelper; +import org.openecomp.appc.requesthandler.LCMStateManager; +import org.openecomp.appc.requesthandler.RequestHandler; +import org.openecomp.appc.statemachine.impl.readers.AppcOamStates; + +/** + * Processor to handle maintenance mode OAM API. + */ +public class OamMmodeProcessor extends BaseProcessor { + /** + * Constructor + * + * @param eelfLogger for logging + * @param configurationHelper for property reading + * @param stateHelper for APP-C OAM state checking + * @param asyncTaskHelper for scheduling async task + * @param operationHelper for operational helper + */ + public OamMmodeProcessor(EELFLogger eelfLogger, + ConfigurationHelper configurationHelper, + StateHelper stateHelper, + AsyncTaskHelper asyncTaskHelper, + OperationHelper operationHelper) { + super(eelfLogger, configurationHelper, stateHelper, asyncTaskHelper, operationHelper); + + rpc = AppcOam.RPC.maintenance_mode; + auditMsg = Msg.OAM_OPERATION_ENTERING_MAINTENANCE_MODE; + } + + @Override + protected void preProcess(final Object requestInput) + throws InvalidInputException, InvalidStateException, APPCException { + super.preProcess(requestInput); + + //Close the gate so that no more new LCM request will be excepted. + LCMStateManager lcmStateManager = operationHelper.getService(LCMStateManager.class); + lcmStateManager.disableLCMOperations(); + } + + @Override + protected void scheduleAsyncTask() { + runnable = new MyRunnable(this); + super.scheduleAsyncTask(); + } + + /** + * This runnable does the async handling for the maintenance mode REST API, and will be scheduled to run + * until terminating condition reaches. + * + * <p>The runnable will conintue run if: <br> + * - the runnable is not canceled outside <br> + * - the in progress LCM request count is not zero<br> + * <p> When LCM request count reaches to zero, this runnable will: <br> + * - post message through operatonHelper <br> + * - set APP-C OAM state to maintenance mode <br> + * - audit log the state <br> + * - terminate this runnable itself <br> + */ + class MyRunnable extends BaseActionRunnable { + private int inprogressRequestCount; + + MyRunnable(BaseProcessor parent) { + super(parent); + + actionName = "OAM Maintanence mode"; + auditMsg = Msg.OAM_OPERATION_MAINTENANCE_MODE; + finalState = AppcOamStates.MaintenanceMode; + } + + @Override + boolean doAction() { + // always return true, so that we can check the LCM request count + return true; + } + + @Override + boolean checkState() { + logDebug(String.format("Executing %s task", actionName)); + + if (!myParent.isSameAsyncTask()) { + // cancel myself if I am not the current backgroundOamTask + myParent.cancelAsyncTask(); + logDebug(String.format("Finished %s task due to task removed", actionName)); + return true; + } + + boolean hasError = false; + try { + inprogressRequestCount = getInprogressLCMRequestCount(); + if (inprogressRequestCount > 0) { + // if there are still LCM request in progress, keep waiting + return false; + } + + setStatus(OAMCommandStatus.SUCCESS); + } catch (Throwable t) { + setErrorStatus(t); + hasError = true; + } + + postAction(hasError ? AppcOamStates.Error : finalState); + return true; + } + + /** + * Get in progress LCM request count through RequestHandler. + * @return thecount of in progress LCM request + * @throws APPCException if RequestHandler throws it. + */ + private int getInprogressLCMRequestCount() throws APPCException { + RequestHandler requestHandler = operationHelper.getService(RequestHandler.class); + + if (requestHandler == null) { + return 0; + } + + return requestHandler.getInprogressRequestCount(); + } + + @Override + void keepWaiting() { + logDebug("The application '%s' has '%s' outstanding LCM request to complete" + + " before coming to a complete maintenance_mode.", + configurationHelper.getAppcName(), inprogressRequestCount); + } + } +} diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/OamRestartProcessor.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/OamRestartProcessor.java new file mode 100644 index 000000000..529d25004 --- /dev/null +++ b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/OamRestartProcessor.java @@ -0,0 +1,207 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.appc.oam.processor; + +import com.att.eelf.configuration.EELFLogger; +import org.openecomp.appc.exceptions.APPCException; +import org.openecomp.appc.i18n.Msg; +import org.openecomp.appc.oam.AppcOam; +import org.openecomp.appc.oam.util.AsyncTaskHelper; +import org.openecomp.appc.oam.util.ConfigurationHelper; +import org.openecomp.appc.oam.util.OperationHelper; +import org.openecomp.appc.oam.util.StateHelper; +import org.openecomp.appc.requesthandler.LCMStateManager; +import org.openecomp.appc.statemachine.impl.readers.AppcOamStates; + +/** + * Processor to handle restart OAM API. + */ +public class OamRestartProcessor extends BaseProcessor { + /** + * Action phases: + * <br> -ToStop: call bundles stop + * <br> -Stopped: check if all bundle state reached stopped + * <br> -ToStart: call bundles start + * <br> -Started: action is full completed + * <br> -Timeout: indication of timeout reached + */ + private enum ActionPhases { + ToStop, + Stopped, + ToStart, + Started, + Timeout + } + + /** + * Constructor + * + * @param eelfLogger for logging + * @param configurationHelper for property reading + * @param stateHelper for APP-C OAM state checking + * @param asyncTaskHelper for scheduling async task + * @param operationHelper for operational helper + */ + public OamRestartProcessor(EELFLogger eelfLogger, + ConfigurationHelper configurationHelper, + StateHelper stateHelper, + AsyncTaskHelper asyncTaskHelper, + OperationHelper operationHelper) { + super(eelfLogger, configurationHelper, stateHelper, asyncTaskHelper, operationHelper); + + rpc = AppcOam.RPC.restart; + auditMsg = Msg.OAM_OPERATION_RESTARTING; + } + + @Override + protected void scheduleAsyncTask() { + runnable = new MyRunnable(this); + super.scheduleAsyncTask(); + } + + /** + * This runnable does the async handling for the restart REST API. And it will be scheduled to run one time. + * + * <p>This runnable will the following operations: <br> + * - do APP-C OAM bundle stop and then start through BundlerHelper<br> + * - and always enable LCM operation handling (which can be disabled through maintenance mode API).<br> + * <p>Once above operations are done, the runnale will <br> + * - post message through operatonHelper <br> + * - set APP-C OAM state to started <br> + * - audit log the state <br> + */ + class MyRunnable extends BaseActionRunnable { + + ActionPhases currentPhase = ActionPhases.ToStop; + private LCMStateManager lcmStateManager; + + MyRunnable(BaseProcessor parent) { + super(parent); + + actionName = "OAM Restart"; + auditMsg = Msg.OAM_OPERATION_RESTARTED; + finalState = AppcOamStates.Started; + } + + /** + * Do restart action, include stop then start and always enable LCM operation. + * @return true if action is successful, false when aciton is failed or aborted + */ + @Override + boolean doAction() { + logDebug(String.format("Executing %s task at phase (%s)", + actionName, currentPhase == null ? "null" : currentPhase.name())); + + boolean isBundleOperationCompleted = true; + try { + switch (currentPhase) { + case ToStop: + isBundleOperationCompleted = bundleHelper.bundleOperations( + AppcOam.RPC.stop, bundleNameToFuture, myParent.asyncTaskHelper); + currentPhase = ActionPhases.Stopped; + break; + case Stopped: + // check state + AppcOamStates currentState = stateHelper.getBundlesState(); + if (currentState == AppcOamStates.Stopped) { + currentPhase = ActionPhases.ToStart; + } else { + logDebug(String.format("%s task is waiting in stopped phase, current state is %s", + actionName, currentState)); + } + break; + case ToStart: + isBundleOperationCompleted = bundleHelper.bundleOperations( + AppcOam.RPC.start, bundleNameToFuture, myParent.asyncTaskHelper); + currentPhase = ActionPhases.Started; + break; + case Timeout: + // do nothing + break; + default: + // Should not reach log it and return false; + logger.error("%s task doAction reached %s phase. not supported. return false.", + actionName, currentPhase.name()); + stateHelper.setState(AppcOamStates.Error); + return false; + } + + if (isTimeout("restart doAction")) { + currentPhase = ActionPhases.Timeout; + return true; + } + if (isBundleOperationCompleted) { + return true; + } + + setAbortStatus(); + } catch (APPCException e) { + setErrorStatus(e); + stateHelper.setState(AppcOamStates.Error); + } + + return false; + } + + /** + * With additional to get the LCMStateManager service + * @see BaseActionRunnable#checkState() + */ + @Override + boolean checkState() { + switch (currentPhase) { + case Started: + try { + lcmStateManager = operationHelper.getService(LCMStateManager.class); + return super.checkState(); + } catch (APPCException e) { + logDebug("LCMStateManager is not available."); + } + break; + default: + // in all the other ActionPhase, we want the run go back to doAction + return true; + } + return false; + } + + /** + * Final handling. The thread is cancelled. + * @param setState boolean to indicate if set OAM state or not + */ + @Override + void postDoAction(boolean setState) { + AppcOamStates newState = null; + if (setState) { + logDebug("Always enable LCM operation"); + lcmStateManager.enableLCMOperations(); + newState = finalState; + } + postAction(newState); + super.postDoAction(setState); + } + + } +} diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/OamStartProcessor.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/OamStartProcessor.java new file mode 100644 index 000000000..0060bfcae --- /dev/null +++ b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/OamStartProcessor.java @@ -0,0 +1,151 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.appc.oam.processor; + +import com.att.eelf.configuration.EELFLogger; +import org.openecomp.appc.exceptions.APPCException; +import org.openecomp.appc.i18n.Msg; +import org.openecomp.appc.oam.AppcOam; +import org.openecomp.appc.oam.util.AsyncTaskHelper; +import org.openecomp.appc.oam.util.ConfigurationHelper; +import org.openecomp.appc.oam.util.OperationHelper; +import org.openecomp.appc.oam.util.StateHelper; +import org.openecomp.appc.requesthandler.LCMStateManager; +import org.openecomp.appc.statemachine.impl.readers.AppcOamStates; + +/** + * Processor to handle start OAM API. + */ +public class OamStartProcessor extends BaseProcessor { + + /** + * Constructor + * + * @param eelfLogger for logging + * @param configurationHelper for property reading + * @param stateHelper for APP-C OAM state checking + * @param asyncTaskHelper for scheduling async task + * @param operationHelper for operational helper + */ + public OamStartProcessor(EELFLogger eelfLogger, + ConfigurationHelper configurationHelper, + StateHelper stateHelper, + AsyncTaskHelper asyncTaskHelper, + OperationHelper operationHelper) { + super(eelfLogger, configurationHelper, stateHelper, asyncTaskHelper, operationHelper); + + rpc = AppcOam.RPC.start; + auditMsg = Msg.OAM_OPERATION_STARTING; + } + + @Override + protected void scheduleAsyncTask() { + runnable = new MyRunnable(this); + super.scheduleAsyncTask(); + } + + /** + * This runnable does the async handling for the start REST API. And it will be scheduled to run one time. + * + * <p>This runnable will the following operations: <br> + * - do APP-C OAM bundle start through BundlerHelper<br> + * - and always enable LCM operation handling (which can be disabled through maintenance mode API).<br> + * <p>Once above operations are done, the runnale will <br> + * - post message through operatonHelper <br> + * - set APP-C OAM state to started <br> + * - audit log the state <br> + */ + class MyRunnable extends BaseActionRunnable { + + private LCMStateManager lcmStateManager; + + MyRunnable(BaseProcessor parent) { + super(parent); + actionName = "OAM Start"; + auditMsg = Msg.OAM_OPERATION_STARTED; + finalState = AppcOamStates.Started; + } + + /** + * Do start action, include start bundle if needed and always enable LCM operation. + * @return true if action is successful, false when aciton is failed or aborted + */ + @Override + boolean doAction() { + logDebug(String.format("Executing %s task", actionName)); + + boolean isBundleOperationCompleted = true; + try { + if (stateHelper.getState() != AppcOamStates.Started) { + logDebug("Start - APPC OAM state is not started, start the bundles"); + isBundleOperationCompleted = bundleHelper.bundleOperations( + rpc, bundleNameToFuture, myParent.asyncTaskHelper); + } + + if (isBundleOperationCompleted) { + return true; + } + + setAbortStatus(); + } catch (APPCException e) { + setErrorStatus(e); + stateHelper.setState(AppcOamStates.Error); + } + + return false; + } + + /** + * With additional to get the LCMStateManager service + * @see BaseActionRunnable#checkState() + */ + @Override + boolean checkState() { + try { + lcmStateManager = operationHelper.getService(LCMStateManager.class); + return super.checkState(); + } catch (APPCException e) { + logDebug("LCMStateManager is not available."); + return false; + } + } + + /** + * Final handling + * @param setState boolean to indicate if set OAM state or not + */ + @Override + void postDoAction(boolean setState) { + AppcOamStates newState = null; + if (setState) { + logDebug("Always enable LCM operation"); + lcmStateManager.enableLCMOperations(); + newState = finalState; + } + postAction(newState); + super.postDoAction(setState); + } + } +} diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/OamStopProcessor.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/OamStopProcessor.java new file mode 100644 index 000000000..d81901638 --- /dev/null +++ b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/processor/OamStopProcessor.java @@ -0,0 +1,120 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.appc.oam.processor; + +import com.att.eelf.configuration.EELFLogger; +import org.openecomp.appc.exceptions.APPCException; +import org.openecomp.appc.i18n.Msg; +import org.openecomp.appc.oam.AppcOam; +import org.openecomp.appc.oam.util.AsyncTaskHelper; +import org.openecomp.appc.oam.util.ConfigurationHelper; +import org.openecomp.appc.oam.util.OperationHelper; +import org.openecomp.appc.oam.util.StateHelper; +import org.openecomp.appc.statemachine.impl.readers.AppcOamStates; + +/** + * Processor to handle stop OAM API. + */ +public class OamStopProcessor extends BaseProcessor { + /** + * Constructor + * + * @param eelfLogger for logging + * @param configurationHelper for property reading + * @param stateHelper for APP-C OAM state checking + * @param asyncTaskHelper for scheduling async task + * @param operationHelper for operational helper + */ + public OamStopProcessor(EELFLogger eelfLogger, + ConfigurationHelper configurationHelper, + StateHelper stateHelper, + AsyncTaskHelper asyncTaskHelper, + OperationHelper operationHelper) { + super(eelfLogger, configurationHelper, stateHelper, asyncTaskHelper, operationHelper); + + rpc = AppcOam.RPC.stop; + auditMsg = Msg.OAM_OPERATION_STOPPING; + } + + + @Override + protected void scheduleAsyncTask() { + runnable = new MyRunnable(this); + super.scheduleAsyncTask(); + } + + /** + * This runnable does the async handling for the stop REST API. And it will be scheduled to run one time. + * + * <p>This runnable will the following operations: <br> + * - do APP-C OAM bundle stop and then refresh through BundlerHelper<br> + * <p>Once above operations are done, the runnale will <br> + * - post message through operatonHelper <br> + * - set APP-C OAM state to started <br> + * - audit log the state <br> + */ + class MyRunnable extends BaseActionRunnable { + + MyRunnable(BaseProcessor parent) { + super(parent); + actionName = "OAM Stop"; + auditMsg = Msg.OAM_OPERATION_STOPPED; + finalState = AppcOamStates.Stopped; + } + + /** + * Do stop action, include stop bundle . + * @return true if action is successful, false when aciton is failed. + */ + @Override + boolean doAction() { + logDebug(String.format("Executing %s task", actionName)); + + try { + boolean isBundleOperationCompleted = bundleHelper.bundleOperations( + rpc, bundleNameToFuture, myParent.asyncTaskHelper); + if (isBundleOperationCompleted) { + return true; + } + + setAbortStatus(); + } catch (APPCException e) { + setErrorStatus(e); + stateHelper.setState(AppcOamStates.Error); + } + return false; + } + + /** + * Final handling + * @param setState boolean to indicate if set OAM state or not + */ + @Override + void postDoAction(boolean setState) { + postAction(setState ? finalState : null); + super.postDoAction(setState); + } + } +} diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/AsyncTaskHelper.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/AsyncTaskHelper.java new file mode 100644 index 000000000..ff28e995a --- /dev/null +++ b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/AsyncTaskHelper.java @@ -0,0 +1,165 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.appc.oam.util; + +import com.att.eelf.configuration.EELFLogger; +import org.openecomp.appc.oam.AppcOam; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; + +import java.util.concurrent.Callable; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * Utility class provides general async task related help. + */ +@SuppressWarnings("unchecked") +public class AsyncTaskHelper { + final int MMODE_TASK_DELAY = 10000; + final int COMMON_INITIAL_DELAY = 0; + final int COMMON_INTERVAL = 1000; + + private final EELFLogger logger; + private final ScheduledExecutorService scheduledExecutorService; + private final ThreadPoolExecutor bundleOperationService; + + /** Reference to the Async task */ + private volatile Future<?> backgroundOamTask; + + /** + * Constructor + * @param eelfLogger of the logger + */ + public AsyncTaskHelper(EELFLogger eelfLogger) { + logger = eelfLogger; + + scheduledExecutorService = Executors.newSingleThreadScheduledExecutor( + (runnable) -> { + Bundle bundle = FrameworkUtil.getBundle(AppcOam.class); + return new Thread(runnable, bundle.getSymbolicName() + " scheduledExecutor"); + } + ); + + bundleOperationService = new ThreadPoolExecutor( + 0, + 10, + 10, + TimeUnit.SECONDS, + new LinkedBlockingQueue(),// BlockingQueue<Runnable> workQueue + (runnable) -> new Thread(runnable, "OAM bundler operation executor")//ThreadFactory + ); + } + + void addThreadsToPool() { + bundleOperationService.setCorePoolSize(bundleOperationService.getMaximumPoolSize()); + } + + void removeThreadsFromPoolWhenDone() { + bundleOperationService.setCorePoolSize(0); + } + + /** + * Terminate the class <bS>ScheduledExecutorService</b> + */ + public void close() { + logDebug("Start shutdown scheduleExcutorService."); + scheduledExecutorService.shutdown(); + bundleOperationService.shutdown(); + logDebug("Completed shutdown scheduleExcutorService."); + } + + /** + * Get current async task refernce + * @return the class <b>backgroundOamTask</b> + */ + public Future<?> getCurrentAsyncTask() { + return backgroundOamTask; + } + + /** + * Schedule a service for async task with the passed in parameters + * @param rpc of the REST API call, decides how to schedule the service + * @param runnable of the to be scheduled service. + * @return the refernce of the scheduled task + */ + public Future<?> scheduleAsyncTask(final AppcOam.RPC rpc, final Runnable runnable) { + int initialDelay, interval; + switch (rpc) { + case maintenance_mode: + initialDelay = interval =MMODE_TASK_DELAY; + break; + case start: + case stop: + case restart: + initialDelay = COMMON_INITIAL_DELAY; + interval = COMMON_INTERVAL; + break; + default: + // should not get here. Log it and return null + logDebug(String.format("Cannot scheudle task for unsupported RPC(%s).", rpc.name())); + return null; + } + + // Always cancel existing async task + if (backgroundOamTask != null) { + backgroundOamTask.cancel(true); + } + backgroundOamTask = scheduledExecutorService.scheduleWithFixedDelay( + runnable, initialDelay, interval, TimeUnit.MILLISECONDS); + + return backgroundOamTask; + } + + Future<?> submitBundleLcOperation(final Callable callable) { + return bundleOperationService.submit(callable); + } + + /** + * Cancle a previously schedule task. If the task is the same as backgroundOamTask, set it to null. + * @param task to be canceled + */ + public void cancelAsyncTask(Future<?> task) { + task.cancel(false); + if (task == backgroundOamTask) { + backgroundOamTask = null; + } + } + + /** + * Genral debug log when debug logging level is enabled. + * @param message of the log message format + * @param args of the objects listed in the message format + */ + private void logDebug(String message, Object... args) { + if (logger.isDebugEnabled()) { + logger.debug(String.format(message, args)); + } + } +} diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/BundleFilter.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/BundleFilter.java new file mode 100644 index 000000000..1e9f9b6a1 --- /dev/null +++ b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/BundleFilter.java @@ -0,0 +1,128 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.appc.oam.util; + +import org.osgi.framework.Bundle; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; + + + +/** + * + * Utility Class that splits a given bundleSet into two sets: bundleToStopSet and + * bundleToNotStopSet + * + * The bundleToStopSet is defined as: all bundles which match at least one of + * the stopRegexes but exceptRegexes none of the + * + * The bundleToNotStopSet is defined as all bundles which are not a member of + * the bundleToStopSet + * + */ +class BundleFilter { + + private final Map<String, Bundle> bundleToStopSet; + private final Map<String, Bundle> bundleToNotStopSet; + + + /** + * BundleFilter a bundle filter + * @param stopRegexes - An array of regular expression used to pick out which bundles are candidates for stopping + * @param exceptRegexes - An array of regular expression used to override which bundles are candidates for stopping + * @param bundles - An array of the bundle to be split into {@link #getBundlesToStop()} {@link #getBundlesToNotStop()} + */ + BundleFilter(String[] stopRegexes, String[] exceptRegexes, Bundle[] bundles) { + + Pattern[] stopPatterns = toPattern(stopRegexes); + Pattern[] exceptPatterns = toPattern(exceptRegexes); + + Map<String, Bundle> bundleToStop = new HashMap<>(); + Map<String, Bundle> bundleToNotStop = new HashMap<>(); + + for (Bundle bundle : bundles) { + String symbolicName = bundle.getSymbolicName(); + if (isMatch(symbolicName,stopPatterns) && !isMatch(symbolicName,exceptPatterns)) { + bundleToStop.put(symbolicName, bundle); + } else { + bundleToNotStop.put(symbolicName, bundle); + } + } + + this.bundleToStopSet = Collections.unmodifiableMap(bundleToStop); + this.bundleToNotStopSet = Collections.unmodifiableMap(bundleToNotStop); + } + + /** + * Determines if the value matches any of the regular expressions. + * + * @param value + * - the value that is to be matched + * @param patterns + * - the array of {@link Pattern} to match the value against + * @return boolean true if there is a match + */ + private boolean isMatch(String value,Pattern[] patterns) { + for (Pattern pattern : patterns) { + if (pattern.matcher(value).matches()) { + return true; + } + } + return false; + } + + /** + * This method converts an Array of regular expression in String form into a + * Array of {@link Pattern} + * + * @param regex + * - A string array of regular expressions + * @return Pattern Array of compiled regular expressions + */ + private Pattern[] toPattern(String[] regex) { + Pattern[] pattern = new Pattern[regex.length]; + for (int i = 0; i < regex.length; i++ ) { + pattern[i] = Pattern.compile(regex[i]); + } + return pattern; + } + + + /**@return Map of bundles that are to be stopped */ + Map<String, Bundle> getBundlesToStop(){ + return bundleToStopSet; + } + + /** + * + * @return Map of bundles that are not to be stopped + */ + Map<String, Bundle> getBundlesToNotStop() { + return bundleToNotStopSet; + } +} diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/BundleHelper.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/BundleHelper.java new file mode 100644 index 000000000..7fbb3c453 --- /dev/null +++ b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/BundleHelper.java @@ -0,0 +1,265 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.appc.oam.util; + +import com.att.eelf.configuration.EELFLogger; +import org.apache.commons.lang3.ArrayUtils; +import org.openecomp.appc.exceptions.APPCException; +import org.openecomp.appc.oam.AppcOam; +import org.openecomp.appc.statemachine.impl.readers.AppcOamStates; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; +import org.osgi.framework.FrameworkUtil; + +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; + +/** + * Utility class provides general bundle operational helps. + */ +public class BundleHelper { + private final static String PROP_BUNDLE_TO_STOP = "appc.OAM.ToStop.properties"; + private final static String PROP_BUNDLES_TO_NOT_STOP = "appc.OAM.ToNotStop.properties"; + + private final EELFLogger logger; + private final StateHelper stateHelper; + private final ConfigurationHelper configurationHelper; + + /** + * Constructor + * + * @param eelfLogger of the logger + * @param configurationHelperIn of ConfigurationHelper instance + * @param stateHelperIn of StateHelper instance + */ + public BundleHelper(EELFLogger eelfLogger, + ConfigurationHelper configurationHelperIn, + StateHelper stateHelperIn) { + logger = eelfLogger; + configurationHelper = configurationHelperIn; + stateHelper = stateHelperIn; + } + + /** + * Handle bundle operations, such as stop or start bundle. + * + * @param rpc enum indicate if the operation is to stop, start or restart + * @return boolean to indicate if the operation is successful (true) or failed (false) + * @throws APPCException when error occurs + */ + public boolean bundleOperations(AppcOam.RPC rpc, + Map<String, Future<?>> threads, + AsyncTaskHelper taskHelper) + throws APPCException { + long mStartTime = System.currentTimeMillis(); + logDebug(String.format("Entering OAM bundleOperations with rpc (%s).", rpc.name())); + + String action = rpc.getAppcOperation().toString(); + if (rpc != AppcOam.RPC.stop && rpc != AppcOam.RPC.start) { + throw new APPCException("rpc(" + rpc + ") is not supported by bundleOperation."); + } + + AppcOamStates originalState = stateHelper.getState(); + + boolean isBundleOperationComplete = true; + + Map<String, Bundle> appcLcmBundles = getAppcLcmBundles(); + taskHelper.addThreadsToPool(); + for (Map.Entry<String, Bundle> bundleEntry : appcLcmBundles.entrySet()) { + String bundleName = bundleEntry.getKey(); + Bundle bundle = bundleEntry.getValue(); + + logDebug("OAM launch thread for %s bundle %s", action, bundleName); + if (rpc == AppcOam.RPC.start) { + // Abort in the interruption case. + // such as when a Stop request is receive while APPC is still trying to Start Up. + if (!stateHelper.isSameState(originalState)) { + logger.warn("OAM %s bundle operation aborted since OAM state is no longer %s!", + originalState.name()); + isBundleOperationComplete = false; + break; + } + } + + threads.put(bundleName, + taskHelper.submitBundleLcOperation(new BundleTask(rpc, bundle))); + } + taskHelper.removeThreadsFromPoolWhenDone(); + + logDebug(String.format("Leaving OAM bundleOperations with rpc (%s) with complete(%s), elasped (%d) ms.", + rpc.name(), Boolean.toString(isBundleOperationComplete), getElaspeTimeMs(mStartTime))); + + return isBundleOperationComplete; + } + + private long getElaspeTimeMs(long mStartTime) { + return System.currentTimeMillis() - mStartTime; + } + + /** + * Check if all BundleTasks are completed + * @param bundleNameFutureMap with bundler name and BundleTask Future object + * @return true if all are done, otherwise, false + */ + public boolean isAllTaskDone(Map<String, Future<?>> bundleNameFutureMap) { + boolean anyNotDone = bundleNameFutureMap.values().stream().anyMatch((f) -> !f.isDone()); + return !anyNotDone; + } + + /** + * Cancel BunldeTasks which are not finished + * @param bundleNameFutureMap with bundler name and BundleTask Future object + */ + public void cancelUnfinished(Map<String, Future<?>> bundleNameFutureMap) { + bundleNameFutureMap.values().stream().filter((f) -> !f.isDone()).forEach((f) -> f.cancel(true)); + } + + /** + * Get number of failed BundleTasks + * @param bundleNameFurtureMap with bundler name and BundleTask Future object + * @return number(long) of the failed BundleTasks + */ + public long getFailedMetrics(Map<String, Future<?>> bundleNameFurtureMap) { + return bundleNameFurtureMap.values().stream().map((f) -> { + try { + return f.get(); + } catch (Exception e) { + // should not get here + throw new RuntimeException(e); + } + }).filter((b) -> ((BundleTask)b).failException != null).count(); + } + + /** + * Gets the list of Appc-bundles to be stopped/started + * + * @return Map of bundle symbolic name and bundle instance + */ + Map<String, Bundle> getAppcLcmBundles() { + logDebug("In getAppcLcmBundles"); + + String[] bundlesToStop = readPropsFromPropListName(PROP_BUNDLE_TO_STOP); + String[] regExBundleNotStop = readPropsFromPropListName(PROP_BUNDLES_TO_NOT_STOP); + + BundleFilter bundleList = new BundleFilter(bundlesToStop, regExBundleNotStop, getBundleList()); + + logger.info(String.format("(%d) APPC bundles to Stop/Start: %s.", bundleList.getBundlesToStop().size(), + bundleList.getBundlesToStop().toString())); + + logger.debug(String.format("(%d) APPC bundles that won't be Stopped/Started: %s.", + bundleList.getBundlesToNotStop().size(), bundleList.getBundlesToNotStop().toString())); + + return bundleList.getBundlesToStop(); + } + + /** + * Gets a list of all user desired bundles that should be stopped/Started as part of + * OAM Stop and Start API + * + * @param propListKey String of the properties list property name + * @return properties values of the related + */ + String[] readPropsFromPropListName(String propListKey) { + // get properties list by properties list name + String[] propNames = configurationHelper.readProperty(propListKey); + // go through each property to get the property values + String[] propValue = ArrayUtils.EMPTY_STRING_ARRAY; + if (propNames != null) { + for (String aPropName : propNames) { + propValue = ArrayUtils.addAll(propValue, configurationHelper.readProperty(aPropName)); + } + } + return propValue; + } + + /** + * Get all bundle list of APP-C + * @return Array of Bundle + */ + Bundle[] getBundleList() { + BundleContext myBundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext(); + if (myBundleContext != null) { + return myBundleContext.getBundles(); + } + return null; + } + + /** + * Genral debug log when debug logging level is enabled. + * @param message of the log message format + * @param args of the objects listed in the message format + */ + private void logDebug(String message, Object... args) { + if (logger.isDebugEnabled()) { + logger.debug(String.format(message, args)); + } + } + + /** + * Runnable to execute bundle operations: start or stop + */ + class BundleTask implements Callable<BundleTask> { + Exception failException; + + private AppcOam.RPC rpc; + private Bundle bundle; + private String bundleName; + private String actionName; + + BundleTask(AppcOam.RPC rpcIn, Bundle bundleIn) { + rpc = rpcIn; + actionName = rpc.getAppcOperation().toString(); + bundle = bundleIn; + bundleName = bundle.getSymbolicName(); + } + + @Override + public BundleTask call() throws Exception { + try { + long bundleOperStartTime = System.currentTimeMillis(); + logDebug(String.format("OAM %s bundle %s ===>", actionName, bundleName)); + switch (rpc) { + case start: + bundle.start(); + break; + case stop: + bundle.stop(); + break; + default: + // should do nothing + } + logDebug(String.format("OAM %s bundle %s completed <=== elasped %d", + actionName, bundleName, getElaspeTimeMs(bundleOperStartTime))); + } catch (BundleException e) { + logger.error(String.format("Exception encountered when OAM %s bundle %s ", + actionName, bundleName), e); + failException = e; + } + return this; + } + } +} diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/ConfigurationHelper.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/ConfigurationHelper.java new file mode 100644 index 000000000..c465b9b10 --- /dev/null +++ b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/ConfigurationHelper.java @@ -0,0 +1,80 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.appc.oam.util; + +import com.att.eelf.configuration.EELFLogger; +import org.apache.commons.lang3.ArrayUtils; +import org.openecomp.appc.Constants; +import org.openecomp.appc.configuration.Configuration; +import org.openecomp.appc.configuration.ConfigurationFactory; + +/** + * Utility class provides general configuration helps + */ +public class ConfigurationHelper { + final static String PROP_KEY_APPC_NAME = Constants.PROPERTY_APPLICATION_NAME; + final static String PROP_KEY_METRIC_STATE = "metric.enabled"; + + private final EELFLogger logger; + private Configuration configuration = ConfigurationFactory.getConfiguration(); + + public ConfigurationHelper(EELFLogger eelfLogger) { + logger = eelfLogger; + } + + public String getAppcName() { + return configuration.getProperty(PROP_KEY_APPC_NAME); + } + + public boolean isMetricEnabled() { + return configuration.getBooleanProperty(PROP_KEY_METRIC_STATE, false); + } + + public Configuration getConfig() { + return configuration; + } + + /** + * Read property value of a specified proeprty key + * + * @param propertyKey string of the property key + * @return String[] of the property values associated with the propertyKey + */ + String[] readProperty(String propertyKey) { + String propertyValue = configuration.getProperty(propertyKey); + if (propertyValue == null) { + return ArrayUtils.EMPTY_STRING_ARRAY; + } + + if (logger.isDebugEnabled()) { + logger.debug(String.format("Property[%s] has value (%s).", propertyKey, propertyValue)); + } + + if (propertyValue.contains(",")) { + return propertyValue.split("\\s*,\\s*"); + } + return new String[]{propertyValue}; + } +} diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/OperationHelper.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/OperationHelper.java new file mode 100644 index 000000000..0b20104f4 --- /dev/null +++ b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/OperationHelper.java @@ -0,0 +1,205 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.appc.oam.util; + +import com.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.MaintenanceModeInput; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.RestartInput; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.StartInput; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.StopInput; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.common.header.CommonHeader; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.common.header.common.header.Flags; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.status.Status; +import org.openecomp.appc.exceptions.APPCException; +import org.openecomp.appc.exceptions.InvalidInputException; +import org.openecomp.appc.exceptions.InvalidStateException; +import org.openecomp.appc.lifecyclemanager.LifecycleManager; +import org.openecomp.appc.lifecyclemanager.objects.LifecycleException; +import org.openecomp.appc.lifecyclemanager.objects.NoTransitionDefinedException; +import org.openecomp.appc.oam.AppcOam; +import org.openecomp.appc.oam.messageadapter.MessageAdapter; +import org.openecomp.appc.oam.messageadapter.OAMContext; +import org.openecomp.appc.statemachine.impl.readers.AppcOamMetaDataReader; +import org.openecomp.appc.statemachine.impl.readers.AppcOamStates; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.ServiceReference; + +/** + * Utility class provides general operational helps. + */ +@SuppressWarnings("unchecked") +public class OperationHelper { + final String MISSING_COMMON_HEADER_MESSAGE = "Missing common header"; + final String MISSING_FIELD_MESSAGE = "Common header must have both originatorId and requestId"; + final String NOT_SUPPORT_FLAG = "Flags is not supported by this operation"; + final String NO_SERVICE_REF_FORMAT = "Using the BundleContext failed to get service reference for %s"; + + private final EELFLogger logger = EELFManager.getInstance().getLogger(OperationHelper.class); + private LifecycleManager lifecycleMgr; + private MessageAdapter messageAdapter; + + public OperationHelper() { + // do nothing + } + + /** + * This method is used to validate OAM REST API input due to the following ODL bugs results no validation : </tt> + * <p> - <a href="https://bugs.opendaylight.org/show_bug.cgi?id=8088"> + * Bug 8088 - Mandatory attributes in RPC input are not honoured</a> + * <p> - <a href="https://bugs.opendaylight.org/show_bug.cgi?id=5830"> + * Bug 5830 - Mandatory leaf enforcement is not correct with presence container</a> + * + * @param inputObject object from the OAM REST API input object + * @throws InvalidInputException is thrown when the commonHeader is invalid + */ + public void isInputValid(final Object inputObject) throws InvalidInputException { + CommonHeader commonHeader = getCommonHeader(inputObject); + if (commonHeader == null) { + throw new InvalidInputException(MISSING_COMMON_HEADER_MESSAGE); + } + + if (commonHeader.getOriginatorId() == null + || commonHeader.getRequestId() == null) { + throw new InvalidInputException(MISSING_FIELD_MESSAGE); + } + + // check Flags + if (inputObject instanceof MaintenanceModeInput + && commonHeader.getFlags() != null) { + throw new InvalidInputException(NOT_SUPPORT_FLAG); + } + } + + /** + * Get commonHead of the inputObject (expecting the inputObject of OAM REST API) + * @param inputObject the OAM REST API input object + * @return CommonHeader of the inputObject. If the inputObject is not a OAM REST API input, null is returned. + */ + public CommonHeader getCommonHeader(final Object inputObject) { + if (inputObject instanceof StartInput) { + return ((StartInput)inputObject).getCommonHeader(); + } + if (inputObject instanceof StopInput) { + return ((StopInput)inputObject).getCommonHeader(); + } + if (inputObject instanceof MaintenanceModeInput) { + return ((MaintenanceModeInput)inputObject).getCommonHeader(); + } + if (inputObject instanceof RestartInput) { + return ((RestartInput)inputObject).getCommonHeader(); + } + return null; + } + + public Integer getParamRequestTimeout(final Object inputObject) { + if (inputObject instanceof MaintenanceModeInput) { + // maintanence mode, we do not support request timeout + return 0; + } + + CommonHeader commonHeader = getCommonHeader(inputObject); + if (commonHeader == null) { + return 0; + } + + Flags inputFlags = commonHeader.getFlags(); + if (inputFlags == null) { + return null; + } + return inputFlags.getRequestTimeout(); + } + /** + * Get service instance using bundle context. + * + * @param _class of the expected service instance + * @param <T> of the expected service instance + * @return service instance of the expected + * @throws APPCException when cannot find service reference or service isntance + */ + public <T> T getService(Class<T> _class) throws APPCException { + BundleContext bctx = FrameworkUtil.getBundle(_class).getBundleContext(); + if (bctx != null) { + ServiceReference sref = bctx.getServiceReference(_class.getName()); + if (sref != null) { + if (logger.isTraceEnabled()) { + logger.debug("Using the BundleContext got the service reference for " + _class.getName()); + } + return (T) bctx.getService(sref); + } + } + + throw new APPCException(String.format(NO_SERVICE_REF_FORMAT, _class.getName())); + } + + /** + * Get next valid state from life cycle manager. + * + * @param operation of the AppcOperation for the state changes + * @param currentState of AppcOamStates + * @return next AppcOamStates based on the currentState and operation + * @throws APPCException If life cycle manager instance cannot be retrieved + * @throws InvalidStateException when the operation is not supported on the currentState + */ + public AppcOamStates getNextState(AppcOamMetaDataReader.AppcOperation operation, AppcOamStates currentState) + throws APPCException, InvalidStateException { + if (lifecycleMgr == null) { + lifecycleMgr = getService(LifecycleManager.class); + } + + try { + String nextState = lifecycleMgr.getNextState("APPC", currentState.name(), operation.toString()); + if (nextState != null) { + return AppcOamStates.valueOf(nextState); + } + } catch (LifecycleException |NoTransitionDefinedException ex) { + logger.error("Invalid next state based on the current state and attempted Operation " + ex.getMessage()); + } + + throw new InvalidStateException(String.format(AppcOam.INVALID_STATE_MESSAGE_FORMAT, operation, "APPC", currentState)); + } + + /** + * Post notification through MessageAdapter. + * + * @param rpc of REST API RPC + * @param commonHeader of REST API request common header + * @param status of the to be post message + */ + public void sendNotificationMessage(AppcOam.RPC rpc, CommonHeader commonHeader, Status status) { + if (messageAdapter == null) { + messageAdapter = new MessageAdapter(); + messageAdapter.init(); + + } + + OAMContext oamContext = new OAMContext(); + oamContext.setRpcName(rpc); + oamContext.setCommonHeader(commonHeader); + oamContext.setStatus(status); + messageAdapter.post(oamContext); + } +} diff --git a/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/StateHelper.java b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/StateHelper.java new file mode 100644 index 000000000..a9ccc26d0 --- /dev/null +++ b/appc-oam/appc-oam-bundle/src/main/java/org/openecomp/appc/oam/util/StateHelper.java @@ -0,0 +1,144 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + * ============LICENSE_END========================================================= + */ + +package org.openecomp.appc.oam.util; + +import com.att.eelf.configuration.EELFLogger; +import org.opendaylight.yang.gen.v1.org.openecomp.appc.oam.rev170303.AppcState; +import org.openecomp.appc.statemachine.impl.readers.AppcOamStates; +import org.osgi.framework.Bundle; + +import java.util.Map; + +/* + * Utility class provides general state helps + */ +public class StateHelper { + /** logger inherited from AppcOam */ + private final EELFLogger logger; + private ConfigurationHelper configurationHelper; + /** APP-C OAM current state in AppcOamStates value */ + private volatile AppcOamStates appcOamCurrentState; + + /** + * Constructor + * + * @param eelfLogger of the logger + */ + public StateHelper(EELFLogger eelfLogger, ConfigurationHelper cHelper) { + logger = eelfLogger; + configurationHelper = cHelper; + appcOamCurrentState = AppcOamStates.Unknown; + } + + /** + * Set the passed in state to the class <b>appOamCurrentState</b>. + * + * @param appcOamStates of the new state + */ + public void setState(AppcOamStates appcOamStates) { + appcOamCurrentState = appcOamStates; + } + + /** + * Get the state + * @return the class <b>appOamCurrentState</b> + */ + public AppcOamStates getState() { + return appcOamCurrentState; + } + + /** + * Validate if the passed in state is the same as the class <b>appOamCurrentState</b>. + * + * @param appcOamStates of the to be compared state + * @return true if they are the same, otherwise false + */ + boolean isSameState(AppcOamStates appcOamStates) { + return appcOamCurrentState == appcOamStates; + } + + /** + * Get APP-C OAM current state + * + * <p>When appcOamCurrentState is null or unknown, reset it with APPC LCM bundle state. + * + * @return AppcOamStates of the current APP-C OAM state + */ + public AppcOamStates getCurrentOamState() { + if (appcOamCurrentState == null || appcOamCurrentState.equals(AppcOamStates.Unknown)) { + appcOamCurrentState = getBundlesState(); + } + return appcOamCurrentState; + } + + /** + * Use getCurrentOamState to get current OAM AppcOamStates and then convert to AppcState of Yang. + * + * @return AppcState of current OAM state + */ + public AppcState getCurrentOamYangState() { + try { + AppcOamStates appcOamStates = getCurrentOamState(); + return AppcState.valueOf(appcOamStates.name()); + } catch (Exception ex) { + logger.error(String.format("Unable to determine the current APP-C OAM state due to %s.", ex.getMessage())); + } + return AppcState.Unknown; + } + + /** + * Get APPC state from the state of the set of APPC LCM bundles. + * <p>The state of each bundle will be checked and the lowest state will be uses as the returning AppcOamStates. + * <p>The bundle state order are defined in OSGI bundle (@see org.osgi.framework.Bundle) class + * as the int value assigned to each state as the following: <br> + * - UNINSTALLED (1) <br> + * - INSTALLED (2) <br> + * - RESOLVED (4) <br> + * - STARTING (8) <br> + * - STOPPING (16) <br> + * - ACTIVE (32) <br> + * + * @return AppcOamStates + */ + public AppcOamStates getBundlesState() { + BundleHelper bundleHelper = new BundleHelper(logger, configurationHelper, this); + Map<String, Bundle> lcmBundleMap = bundleHelper.getAppcLcmBundles(); + if (lcmBundleMap == null || lcmBundleMap.isEmpty()) { + return AppcOamStates.Unknown; + } + + // As we are picking up the lowest bundle state as general APP-C state, we will start with ACTIVE + int currentState = Bundle.ACTIVE; + for (Bundle bundle : lcmBundleMap.values()) { + int bundleState = bundle.getState(); + logger.trace(String.format("getBundlesState: [%s] has state (%d)", bundle.getSymbolicName(), bundleState)); + if (bundleState < currentState) { + currentState = bundleState; + } + } + return AppcOamStates.getOamStateFromBundleState(currentState); + } + +} diff --git a/appc-oam/appc-oam-model/src/main/yang/appc-oam.yang b/appc-oam/appc-oam-model/src/main/yang/appc-oam.yang index d84d8ce79..03675c8f2 100644 --- a/appc-oam/appc-oam-model/src/main/yang/appc-oam.yang +++ b/appc-oam/appc-oam-model/src/main/yang/appc-oam.yang @@ -77,6 +77,17 @@ module appc-oam { mandatory true; } + container flags { + leaf request-timeout { + description "The allowed time in seconds to perform the request. If the request cannot + be completed in this amount of time, the request is aborted with OAM state set + to Error. If set to zero, no timeout exists and the request will be handled + continue until operation completes or fails. If omitted, the default value of + 20 is used."; + type uint16; + mandatory false; + } + } } } @@ -103,6 +114,23 @@ module appc-oam { } } + typedef appc-state { + type enumeration { + enum "Error"; + enum "Unknown"; + enum "Not_Instantiated"; // Equivalent to Bundle's UNINSTALL + enum "Instantiated"; // Equivalent to Bundle's INSTALL + enum "Starting"; + enum "Started"; + enum "EnteringMaintenanceMode"; + enum "MaintenanceMode"; + enum "Stopping"; + enum "Stopped"; + enum "Restarting"; + } + description "Refers to the various states an APP-C instance can be in"; + } + rpc get-metrics { description "An operation to get list of registered Metrics in APP-C"; output { @@ -135,10 +163,10 @@ module appc-oam { } } - rpc stop { + rpc maintenance-mode { description "An operation that disables appc-provider-lcm so that it no longer accepts LCM request. This operation has no impact on queued and currently executing LCM request. A notification will be - sent out indicating the APP-C is idle once all LCM request have completed execution. "; + sent out indicating the APP-C is idle once all LCM request have completed execution."; input { uses common-header; } @@ -149,13 +177,46 @@ module appc-oam { } rpc start { - description "An operation that enables appc-provider-lcm so that it can begin to accepts LCM request. "; + description "An operation that enables appc-provider-lcm so that it can begin to accepts LCM request. This + includes starting any appc bundles which are stopped."; input { - uses common-header; + uses common-header; } output { uses common-header; uses status; } } + + rpc get-appc-state { + description "Returns the current state of the running APPC LCM instance"; + output { + leaf state { + type appc-state; + } + } + } + + rpc stop { + description "Force stops the APPC bundles that accept LCM requests"; + // Note: OAM feature bundles and it's dependencies (Appc-common and LifeCycle Manager) would continue to run + input { + uses common-header; + } + output { + uses common-header; + uses status; + } + } + + rpc restart { + description "An operation that restarts APPC by invoking the stop rpc followed by the start rpc."; + input { + uses common-header; + } + output { + uses common-header; + uses status; + } + } } |