added mcsla core

parent 171353a7
/classes/
*.class
*.lst
# Created by .ignore support plugin (hsz.mobi)
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
*.iml
# User-specific stuff:
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/dictionaries
# Sensitive or high-churn files:
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.xml
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
# Gradle:
.idea/**/gradle.xml
.idea/**/libraries
# CMake
cmake-build-debug/
# Mongo Explorer plugin:
.idea/**/mongoSettings.xml
## File-based project format:
*.iws
## Plugin-specific files:
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
### Maven template
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
pom.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# Avoid ignoring Maven wrapper jar file (.jar files are usually ignored)
!/.mvn/wrapper/maven-wrapper.jar
### Eclipse template
.project
.classpath
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
.recommenders
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# PyDev specific (Python IDE for Eclipse)
*.pydevproject
# CDT-specific (C/C++ Development Tooling)
.cproject
# Java annotation processor (APT)
.factorypath
# PDT-specific (PHP Development Tools)
.buildpath
# sbteclipse plugin
.target
# Tern plugin
.tern-project
# TeXlipse plugin
.texlipse
# STS (Spring Tool Suite)
.springBeans
# Code Recommenders
.recommenders/
# Scala IDE specific (Scala & Java development for Eclipse)
.cache-main
.scala_dependencies
.worksheet
#Windows specific
*~
image: maven:alpine
variables:
MAVEN_CLI_OPTS: "--batch-mode"
before_script:
- apk update && apk upgrade && apk add git
- git config --global user.email "$GITLAB_USER_EMAIL"
- git config --global user.name "$GITLAB_USER_NAME"
- git checkout -B "$CI_BUILD_REF_NAME"
- git pull origin "$CI_BUILD_REF_NAME"
deploy_snapshot:
stage: deploy
only:
- master
script:
- mvn $MAVEN_CLI_OPTS clean deploy -Dmaven.test.skip=true
deploy_release:
stage: deploy
only:
- release
script:
- mvn $MAVEN_CLI_OPTS -Darguments="-DskipTests" -DscmCommentPrefix="[ci skip] - " release:clean release:prepare -B release:perform
This diff is collapsed.
# MCSLA Core Library
The MCSLA Core Library provides
## Table of Contents
1. [Features](#features)
1. [Installation](#installation)
1. [Getting started](#getting-started)
1. [The Interface](#the-interface)
1. [License](#license)
## Features
* Support for different aggregation expressions
* Aggregation of cloud service SLAs
* Evaluation of a single cloud service SLA metric
* Evaluation of aggregated cloud services SLA metrics
## Building from Source
The project is available via Git repository. If you have access, do the following steps:
```shell
$> git clone https://gitlab.fokus.fraunhofer.de/DECIDE/mcsla-core.git
$> cd mcsla-core
```
The project uses Maven as build tool. After build you will find the jar and a fat jar in the target directory. To build use the follwoing command:
```shell
$> mvn clean package
```
## Installation
For non-Maven based projects you can take the build jar file located in the target directory after executing the build command and put it in the classpath of your application. There is also a fat jar provided containing all dependencies if required.
For Maven based projects you need to install it in a Maven repository which your application can access. E.g. to put it in your local maven repository, you can simply call
`$> mvn install`
Finally, your application pom.xml requires the following dependency:
```xml
<dependency>
<groupId>eu.DECIDEh2020</groupId>
<artifactId>mcsla-core</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
```
## Getting started
A small example how to create a metrics context and evaluate a cloud service objective:
```java
// create context
MetricsContext context = MetricsContext.create(appDescription);
// get sla service objective metrics for a apecific cloud service
Map<String, ServiceObjectiveMetrics> metrics = context.getCsMetrics(csId);
// get the service objectove metrics for a specific term name, e.g. "Availability"
ServiceObjeciveMetrics availabilityMetrics = metrics.get("Availability");
// now evaluate against a concrete monitoring result
EvaluationResult<Double> evaluationResult = availabilityMetrics.evaluate(monitoringResult);
if (!evaluationResult.isError()) {
log.info("condition met: {}, result: {}", evaluationResult.isConditionMet(), evaluationResult.getMeasurementResultValue());
} else {
log.error(evaluationResult.getErrorMessage());
}
```
For further examples please take a look at the test cases.
## The Interface
In general there are three main classes:
* [MetricsContext](#metricscontext)
* [ServiceObjectiveMetrics](#serviceobjectivemetrics)
* [EvaluationResult\<T\>](#evaluationresultt)
### MetricsContext
This class provides a static methods for creating context objects. Created context can be used to get service objective metrics of
each SLA as a map. Furthermore, it contains a memory for cloud service evaluation results, so specific aggregation
expressions can be implicitly applied. And finally, it allows the aggregation of service objectives or raw values.
#### Aggregation
The easiest way to use the MetricsContext is to aggregate some raw values:
```
List<Double> values = Arrays.asList(99.9, 99.8, 99.95);
Double value = MetricsContext.aggregate(values, Predefined.AVAILABILITY_AGGREGATION_SUMTYPE);
```
See [Predefined](#predefined-aggregation-expressions) for available aggregation expressions.
To start working with the library in the context of an application description you need to create a MetricsContext object:
```java
AppDescription appDescription = ...
MetricsContext context = MetricsContext.create(appDescription);
```
You can now aggregate all agreement values of all cloud services for a specific term name:
```java
Double value = MetricsContext.aggregate(Predefined.AVAILABILITY_AGGREGATION_SUMTYPE, "Availability");
```
The return type depends on the predefined aggregation expression to be used.
#### Evaluation
The MetricsContext object has two methods for retrieving [ServiceObjectiveMetrics](#serviceobjectivemetrics) which are needed for evaluation:
```java
Map<String, ServiceObjectiveMetrics> appMetrics = context.getAppMetrics();
Map<String, ServiceObjectiveMetrics> cloudserviceMetrics = context.getCsMetrics(csId);
```
The return value is a map of term names and corresponding metrics of either a specific cloud service or the application.
Now you can get the [ServiceObjectiveMetrics](#serviceobjectivemetrics) object for a specific term name:
```java
ServiceObjectiveMetrics objectiveMetrics = appMetrics.get("Availability");
```
### ServiceObjectiveMetrics
You need objects s of this class to evaluate the metrics. The class has the following evaluation functions:
* evaluate()
* evaluate(double[] measuredValues)
* evaluate(int[] measuredValues)
* evaluate(List\<Integer\> measuredValues)
* evaluate(Map\<String, List\<Long\>\> measuredValues)
* evaluate(double measuredValue)
They all return a [EvaluationResult\<T\>](#evaluationresultt) object.
The first one without passing any monitoring results utilizes the memory function of the metrics context. It therefore requires that each monitoring result to be aggregate must be evaluated beforehand.
This makes sense where you have to evaluate first each cloud service metrics and then the aggregated application metric:
```java
Map<String, ServiceObjectiveMetrics> cloudserviceOneMetrics = context.getCsMetrics("1");
ServiceObjectiveMetrics oneMetrics = cloudserviceOneMetrics.get("Availability");
EvaluationResult<Double> resultOne = OneMetrics.evaluate(99.9);
...
Map<String, ServiceObjectiveMetrics> cloudserviceTwoMetrics = context.getCsMetrics("1");
ServiceObjectiveMetrics twoMetrics = cloudserviceTwoMetrics.get("Availability");
EvaluationResult<Double> resultTwo = twoMetrics.evaluate(99.9);
...
Map<String, ServiceObjectiveMetrics> appMetrics = context.getAppMetrics();
ServiceObjectiveMetrics availabilityMetrics = appMetrics.get("Availability");
EvaluationResult<Double> resultApp = availabilityMetrics.evaluate();
```
### EvaluationResult\<T\>
The first thing you should do is to check if the evaluation was successful:
```java
EvaluationResult<Doube> result = ...
if (result.isError()) {
log.error(result.getErrorMesssge());
} else {
...
}
```
A successful evaluation result contains the following information:
* The evaluation date and time
* The underlying term name
* The measurement result value
* The used condition statement
* And finally if the condition is met (see [Statement](#condition-statements))
```java
EvaluationResult<T> result = ...
Date time = result.getMeasurementTime();
String termName = result.getTermName();
T measurementValue = result.getMeasurementResultValue();
Statement conditionStatement ? result.getConditionStatement();
assert result.isConditionMet() : "Condition is not met.";
```
### Predefined Aggregation Expressions
| Expression | |
|----------------------------------|-------------------------------------------------------------------------------------|
| EMPTY | The empty aggregation returns always null. |
| AVAILABILITY_UPTIME_BC | Evaluation of downtimes in seconds to an percentage uptime during a billing cycle. |
| AVAILABILITY_MTBFMTTR | Evaluation based on meantime between failure and meantime between recovery. |
| AVAILABILITY_AGGREGATION_SUMTYPE | An aggregation that summarizes percentage values |
| AGGREGATION_MINTYPE | Returns the min value. |
| AGGREGATION_MAXTYPE | Returns the max value |
| AGGREGATION_SUMTYPE | Returns the sum up of values. |
### Condition Statements
* greater
* greaterOrEqual
* less
* lessOrEqual
* equal
## License
[Eclipse Public License version 2.0.](LICENSE.txt)
\ No newline at end of file
<?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"
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>
<groupId>eu.DECIDEh2020</groupId>
<artifactId>mcsla-core</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<distributionManagement>
<repository>
<id>paca-releases</id>
<name>Paca Releases Repo</name>
<url>https://paca.fokus.fraunhofer.de/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>paca-snapshots</id>
<url>https://paca.fokus.fraunhofer.de/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
<scm>
<connection>
scm:git:https://${GITLAB_USER_LDAP}:${GITLAB_USER_PASSWORD}@gitlab.fokus.fraunhofer.de/${CI_PROJECT_PATH}
</connection>
<url>https://${GITLAB_USER_LDAP}:${GITLAB_USER_PASSWORD}@gitlab.fokus.fraunhofer.de/${CI_PROJECT_PATH}</url>
<developerConnection>
scm:git:https://${GITLAB_USER_LDAP}:${GITLAB_USER_PASSWORD}@gitlab.fokus.fraunhofer.de/${CI_PROJECT_PATH}
</developerConnection>
<tag>HEAD</tag>
</scm>
<repositories>
<repository>
<id>jgit-repository</id>
<url>https://repo.eclipse.org/content/groups/releases/</url>
</repository>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>eu.DECIDEh2020</groupId>
<artifactId>app-controller</artifactId>
<version>0.0.15-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.14.3</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>true</minimizeJar>
<shadedArtifactAttached>true</shadedArtifactAttached>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
/*
* Copyright (c) 2018 Fraunhofer FOKUS.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the
* Eclipse Public License version 2.0 which accompanies
* this distribution, and is available at
* https://opensource.org/licenses/EPL-2.0
*
* Contributors:
*
* Simon Dutkowski (Fraunhofer FOKUS)
*
* Initially developed in the context of DECIDE EU project www.DECIDE-h2020.eu
*/
package eu.DECIDEh2020.mcsla.core.metrics;
import eu.DECIDEh2020.appManager.models.Parameter;
import java.util.Comparator;
import java.util.List;
class AggregationMaxType<T extends Comparable<T>> implements PredefinedExpression<T, T> {
@Override
public T calculate(List<T> input, List<Parameter> parameters) {
return input.stream().max(Comparator.naturalOrder()).orElse(input.get(0));
}
@Override
public T calculateFromStrings(List<String> input, List<Parameter> parameters) {
return (T)input.stream().map(Double::valueOf).max(Comparator.naturalOrder()).orElse(Double.valueOf(input.get(0)));
}
}
/*
* Copyright (c) 2018 Fraunhofer FOKUS.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the
* Eclipse Public License version 2.0 which accompanies
* this distribution, and is available at
* https://opensource.org/licenses/EPL-2.0
*
* Contributors:
*
* Simon Dutkowski (Fraunhofer FOKUS)
*
* Initially developed in the context of DECIDE EU project www.DECIDE-h2020.eu
*/
package eu.DECIDEh2020.mcsla.core.metrics;
import eu.DECIDEh2020.appManager.models.Parameter;
import java.util.Comparator;
import java.util.List;
class AggregationMinType<T extends Comparable<T>> implements PredefinedExpression<T, T> {
@Override
public T calculate(List<T> input, List<Parameter> parameters) {
return input.stream().min(Comparator.naturalOrder()).orElse(input.get(0));
}
@Override
public T calculateFromStrings(List<String> input, List<Parameter> parameters) {
return (T)input.stream().map(Double::valueOf).min(Comparator.naturalOrder()).orElse(Double.valueOf(input.get(0)));
}
}
/*
* Copyright (c) 2018 Fraunhofer FOKUS.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the
* Eclipse Public License version 2.0 which accompanies
* this distribution, and is available at
* https://opensource.org/licenses/EPL-2.0
*
* Contributors:
*
* Simon Dutkowski (Fraunhofer FOKUS)
*
* Initially developed in the context of DECIDE EU project www.DECIDE-h2020.eu
*/
package eu.DECIDEh2020.mcsla.core.metrics;
import eu.DECIDEh2020.appManager.models.Parameter;
import java.util.List;
class AggregationSumType<T extends Number> implements PredefinedExpression<T, T> {
@Override
public T calculate(List<T> input, List<Parameter> parameters) {
Number res;
T example = input.get(0);
if (example instanceof Double) {
res = input.stream().mapToDouble(T::doubleValue).sum();
} else if (example instanceof Integer) {
res = input.stream().mapToInt(T::intValue).sum();
} else if (example instanceof Long) {
res = input.stream().mapToLong(T::longValue).sum();
} else {
res = example;
}
return (T)res;
}
@Override
public T calculateFromStrings(List<String> input, List<Parameter> parameters) {
return (T)(Number)input.stream().mapToDouble(Double::valueOf).sum();
}
}
/*
* Copyright (c) 2018 Fraunhofer FOKUS.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the
* Eclipse Public License version 2.0 which accompanies
* this distribution, and is available at
* https://opensource.org/licenses/EPL-2.0
*
* Contributors:
*
* Simon Dutkowski (Fraunhofer FOKUS)
*
* Initially developed in the context of DECIDE EU project www.DECIDE-h2020.eu
*/
package eu.DECIDEh2020.mcsla.core.metrics;
import eu.DECIDEh2020.appManager.models.Parameter;
import java.util.List;
import java.util.stream.Collectors;
class AvailabilityAggregationSumType implements PredefinedExpression<Double, Double> {
@Override
public Double calculate(List<Double> input, List<Parameter> parameters) {
return input.stream().reduce(100.0, this::calculateSumtype);
}
@Override
public Double calculateFromStrings(List<String> input, List<Parameter> parameters) {
List<Double> values = input.stream().map(Double::valueOf).collect(Collectors.toList());
return calculate(values, parameters);
}
private double calculateSumtype(double a, double b) {
double downtime = 100.0 - a;
return b - downtime;
}
}
/*
* Copyright (c) 2018 Fraunhofer FOKUS.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the
* Eclipse Public License version 2.0 which accompanies
* this distribution, and is available at
* https://opensource.org/licenses/EPL-2.0
*
* Contributors:
*
* Simon Dutkowski (Fraunhofer FOKUS)
*
* Initially developed in the context of DECIDE EU project www.DECIDE-h2020.eu
*/
package eu.DECIDEh2020.mcsla.core.metrics;
import eu.DECIDEh2020.appManager.models.Parameter;
import java.util.List;
import java.util.stream.Collectors;
class AvailabilityMTBFMTTR implements PredefinedExpression<Double, Long> {
@Override
public Double calculate(List<Long> input, List<Parameter> parameters) {
Double uptimeBegin;
Double downtimeBegin;
Double uptimeAgain;
if (input.size() == 3) {
uptimeBegin = input.get(0).doubleValue();
downtimeBegin = input.get(1).doubleValue();
uptimeAgain = input.get(2).doubleValue();
} else {
uptimeBegin = 0.0; // or restore it
downtimeBegin = input.get(0).doubleValue();
uptimeAgain = input.get(1).doubleValue();
}
Double mtbf = downtimeBegin - uptimeBegin;
Double mttr = uptimeAgain - downtimeBegin;
return 100.0 * (mtbf/(mtbf + mttr));
}
@Override
public Double calculateFromStrings(List<String> input, List<Parameter> parameters) {
return calculate(input.stream().map(Long::valueOf).collect(Collectors.toList()), parameters);
}
}
/*
* Copyright (c) 2018 Fraunhofer FOKUS.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the
* Eclipse Public License version 2.0 which accompanies
* this distribution, and is available at
* https://opensource.org/licenses/EPL-2.0
*
* Contributors:
*
* Simon Dutkowski (Fraunhofer FOKUS)
*
* Initially developed in the context of DECIDE EU project www.DECIDE-h2020.eu
*/
package eu.DECIDEh2020.mcsla.core.metrics;
import eu.DECIDEh2020.appManager.models.Parameter;
import java.util.List;
import java.util.stream.Collectors;
class AvailabilityUptimeBillingCycle implements PredefinedExpression<Double, Long> {
@Override
public Double calculate(List<Long> input, List<Parameter> parameters) {
Long totalDowntime = input.stream().reduce(0L, Long::sum);
Double billingCycle = 2.592 * 625.92 * 60;
for (Parameter p : parameters) {
if (p.getId().contains("PARAM_BC") && p.getUnit().equals("second")) {
billingCycle = Double.valueOf(p.getParameterStatement());
}
}
double tmp = billingCycle - totalDowntime.doubleValue();
return 100.0 - tmp/billingCycle;
}
@Override
public Double calculateFromStrings(List<String> input, List<Parameter> parameters) {
return calculate(input.stream().map(Long::valueOf).collect(Collectors.toList()), parameters);
}
}
/*
* Copyright (c) 2018 Fraunhofer FOKUS.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the
* Eclipse Public License version 2.0 which accompanies
* this distribution, and is available at