Cleanup
Removing java API Moving python package from monasca to monasca_events_api
This commit is contained in:
parent
7c07276fc8
commit
1017120c9d
@ -1,29 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -x
|
||||
ME=`whoami`
|
||||
echo "Running as user: $ME"
|
||||
MVN=$1
|
||||
VERSION=$2
|
||||
|
||||
check_user() {
|
||||
ME=$1
|
||||
if [ "${ME}" != "jenkins" ]; then
|
||||
echo "\nERROR: Download monasca-common and do a mvn install to install the monasca-commom jars\n" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
BUILD_COMMON=false
|
||||
POM_FILE=~/.m2/repository/monasca-common/monasca-common/${VERSION}/monasca-common-${VERSION}.pom
|
||||
if [ ! -r "${POM_FILE}" ]; then
|
||||
check_user ${ME}
|
||||
BUILD_COMMON=true
|
||||
fi
|
||||
|
||||
# This should only be done on the stack forge system
|
||||
if [ "${BUILD_COMMON}" = "true" ]; then
|
||||
git clone https://github.com/stackforge/monasca-common
|
||||
cd monasca-common
|
||||
${MVN} clean
|
||||
${MVN} install
|
||||
fi
|
422
java/pom.xml
422
java/pom.xml
@ -1,422 +0,0 @@
|
||||
<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>monasca-api</groupId>
|
||||
<artifactId>monasca-api</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<url>http://github.com/stackforge/monasca-api</url>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<prerequisites>
|
||||
<maven>3.0</maven>
|
||||
</prerequisites>
|
||||
|
||||
<properties>
|
||||
<gitRevision></gitRevision>
|
||||
<timestamp>${maven.build.timestamp}</timestamp>
|
||||
<maven.build.timestamp.format>yyyy-MM-dd'T'HH:mm:ss</maven.build.timestamp.format>
|
||||
<computedVersion>${project.version}-${timestamp}-${gitRevision}</computedVersion>
|
||||
<computedName>${project.artifactId}-${computedVersion}</computedName>
|
||||
<mon.common.version>1.0.0-SNAPSHOT</mon.common.version>
|
||||
<dropwizard.version>0.7.0</dropwizard.version>
|
||||
|
||||
<skipITs>false</skipITs>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<shadedJarName>${project.artifactId}-${project.version}-shaded
|
||||
</shadedJarName>
|
||||
</properties>
|
||||
|
||||
<scm>
|
||||
<connection>scm:git:git@github.com:stackforge/monasca-api</connection>
|
||||
<developerConnection>scm:git:git@github.com:stackforge/monasca-api</developerConnection>
|
||||
</scm>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>release-deploy-url-override</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>BUILD_NUM</name>
|
||||
</property>
|
||||
</activation>
|
||||
<properties>
|
||||
<computedVersion>${versionNumber}.${BUILD_NUM}</computedVersion>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>monasca-common</groupId>
|
||||
<artifactId>monasca-common-influxdb</artifactId>
|
||||
<version>${mon.common.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>monasca-common</groupId>
|
||||
<artifactId>monasca-common-model</artifactId>
|
||||
<version>${mon.common.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>monasca-common</groupId>
|
||||
<artifactId>monasca-common-persistence</artifactId>
|
||||
<version>${mon.common.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>monasca-common</groupId>
|
||||
<artifactId>monasca-common-util</artifactId>
|
||||
<version>${mon.common.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-validator</groupId>
|
||||
<artifactId>commons-validator</artifactId>
|
||||
<version>1.4.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>monasca-common</groupId>
|
||||
<artifactId>monasca-common-kafka</artifactId>
|
||||
<version>${mon.common.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>monasca-common</groupId>
|
||||
<artifactId>monasca-common-middleware</artifactId>
|
||||
<version>${mon.common.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dropwizard</groupId>
|
||||
<artifactId>dropwizard-core</artifactId>
|
||||
<version>${dropwizard.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dropwizard</groupId>
|
||||
<artifactId>dropwizard-db</artifactId>
|
||||
<version>${dropwizard.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dropwizard</groupId>
|
||||
<artifactId>dropwizard-jdbi</artifactId>
|
||||
<version>${dropwizard.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dropwizard</groupId>
|
||||
<artifactId>dropwizard-assets</artifactId>
|
||||
<version>${dropwizard.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dropwizard</groupId>
|
||||
<artifactId>dropwizard-jersey</artifactId>
|
||||
<version>${dropwizard.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.26</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>jsr305</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.curator</groupId>
|
||||
<artifactId>curator-recipes</artifactId>
|
||||
<version>2.2.0-incubating</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.kafka</groupId>
|
||||
<artifactId>kafka_2.9.2</artifactId>
|
||||
<version>0.8.0</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.sun.jdmk</groupId>
|
||||
<artifactId>jmxtools</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.sun.jmx</groupId>
|
||||
<artifactId>jmxri</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.influxdb</groupId>
|
||||
<artifactId>influxdb-java</artifactId>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Test dependencies -->
|
||||
<dependency>
|
||||
<groupId>monasca-common</groupId>
|
||||
<artifactId>monasca-common-testing</artifactId>
|
||||
<version>${mon.common.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>monasca-common</groupId>
|
||||
<artifactId>monasca-common-dropwizard</artifactId>
|
||||
<version>${mon.common.version}</version>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.dropwizard</groupId>
|
||||
<artifactId>dropwizard-testing</artifactId>
|
||||
<version>${dropwizard.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<version>1.9.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.docker-java</groupId>
|
||||
<artifactId>docker-java</artifactId>
|
||||
<version>0.9.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jayway.restassured</groupId>
|
||||
<artifactId>rest-assured</artifactId>
|
||||
<version>2.3.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testng</groupId>
|
||||
<artifactId>testng</artifactId>
|
||||
<version>6.8.8</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.4</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>2.5</version>
|
||||
<configuration>
|
||||
<filesets>
|
||||
<fileset>
|
||||
<directory>${project.basedir}/debs</directory>
|
||||
</fileset>
|
||||
</filesets>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>buildnumber-maven-plugin</artifactId>
|
||||
<version>1.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>validate</phase>
|
||||
<goals>
|
||||
<goal>create</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<doCheck>false</doCheck>
|
||||
<shortRevisionLength>6</shortRevisionLength>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.17</version>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.surefire</groupId>
|
||||
<artifactId>surefire-testng</artifactId>
|
||||
<version>2.17</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<configuration>
|
||||
<excludedGroups>performance,functional,integration,database,slow
|
||||
</excludedGroups>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<version>2.17</version>
|
||||
<configuration>
|
||||
<groups>performance,functional,integration,database,slow</groups>
|
||||
<skipTests>${skipITs}</skipTests>
|
||||
<parallel>methods</parallel>
|
||||
<threadCount>4</threadCount>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>integration-test</goal>
|
||||
<goal>verify</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>1.2</version>
|
||||
<configuration>
|
||||
<finalName>${computedName}</finalName>
|
||||
<createDependencyReducedPom>true</createDependencyReducedPom>
|
||||
<filters>
|
||||
<filter>
|
||||
<!-- *:* can't be used for artifact because we are using an older shade plugin -->
|
||||
<artifact>org.eclipse.jetty.orbit:javax.servlet</artifact>
|
||||
<excludes>
|
||||
<exclude>META-INF/*.SF</exclude>
|
||||
<exclude>META-INF/*.DSA</exclude>
|
||||
<exclude>META-INF/*.RSA</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
</filters>
|
||||
<artifactSet>
|
||||
<excludes>
|
||||
<exclude>org.hamcrest:hamcrest-core</exclude>
|
||||
<exclude>org.hamcrest:hamcrest-library</exclude>
|
||||
</excludes>
|
||||
</artifactSet>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<transformers>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<mainClass>monasca.api.MonApiApplication</mainClass>
|
||||
</transformer>
|
||||
</transformers>
|
||||
<shadedArtifactAttached>true</shadedArtifactAttached>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<packageName>monasca.api</packageName>
|
||||
</manifest>
|
||||
<manifestEntries>
|
||||
<Implementation-Version>${project.artifactId}-${computedVersion}</Implementation-Version>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>2.4.1</version>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>src/assembly/tar.xml</descriptor>
|
||||
</descriptors>
|
||||
<finalName>${artifactNamedVersion}</finalName>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>jdeb</artifactId>
|
||||
<groupId>org.vafer</groupId>
|
||||
<version>1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>jdeb</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<deb>${project.basedir}/debs/binaries/${computedName}.deb</deb>
|
||||
<dataSet>
|
||||
<data>
|
||||
<type>file</type>
|
||||
<src>${project.build.directory}/${shadedJarName}.jar</src>
|
||||
<dst>/opt/monasca/monasca-api.jar</dst>
|
||||
</data>
|
||||
<data>
|
||||
<type>file</type>
|
||||
<src>${project.basedir}/src/deb/etc/api-config.yml-sample
|
||||
</src>
|
||||
<dst>/etc/monasca/api-config.yml-sample</dst>
|
||||
</data>
|
||||
</dataSet>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>2.3</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-scm-plugin</artifactId>
|
||||
<version>1.9.2</version>
|
||||
<configuration>
|
||||
<tag>${project.version}</tag>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@ -1,29 +0,0 @@
|
||||
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
|
||||
<id>tar</id>
|
||||
<formats>
|
||||
<format>tar.gz</format>
|
||||
</formats>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>${project.basedir}</directory>
|
||||
<outputDirectory>/</outputDirectory>
|
||||
<includes>
|
||||
<include>README*</include>
|
||||
<include>LICENSE*</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
<files>
|
||||
<file>
|
||||
<source>${project.build.directory}/${shadedJarName}.jar</source>
|
||||
<outputDirectory>/</outputDirectory>
|
||||
<destName>monasca-api.jar</destName>
|
||||
</file>
|
||||
<file>
|
||||
<source>${project.basedir}/src/deb/etc/api-config.yml-sample</source>
|
||||
<outputDirectory>examples</outputDirectory>
|
||||
</file>
|
||||
</files>
|
||||
</assembly>
|
@ -1,9 +0,0 @@
|
||||
Package: [[name]]
|
||||
Section: misc
|
||||
Priority: optional
|
||||
Architecture: all
|
||||
Depends: openjdk-7-jre-headless | openjdk-7-jre
|
||||
Version: [[version]]-[[timestamp]]-[[buildNumber]]
|
||||
Maintainer: Monasca Team <monasca@lists.launchpad.net>
|
||||
Description: Monasca-API
|
||||
RESTful API for all Monasca data.
|
@ -1,9 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
case "$1" in
|
||||
remove)
|
||||
stop monasca-api
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
@ -1,135 +0,0 @@
|
||||
# The region for which all metrics passing through this server will be persisted
|
||||
region: region-a
|
||||
|
||||
# Maximum rows (Mysql) or points (Influxdb) to return when listing elements
|
||||
maxQueryLimit: 10000
|
||||
|
||||
# Whether this server is running on a secure port
|
||||
accessedViaHttps: false
|
||||
|
||||
# Topic for publishing metrics to
|
||||
metricsTopic: metrics
|
||||
|
||||
# Topic for publishing domain events to
|
||||
eventsTopic: events
|
||||
|
||||
kafka:
|
||||
brokerUris:
|
||||
- 192.168.10.4:9092
|
||||
zookeeperUris:
|
||||
- 192.168.10.4:2181
|
||||
healthCheckTopic: healthcheck
|
||||
|
||||
mysql:
|
||||
driverClass: com.mysql.jdbc.Driver
|
||||
url: jdbc:mysql://192.168.10.4:3306/mon?connectTimeout=5000&autoReconnect=true&useLegacyDatetimeCode=false
|
||||
user: monapi
|
||||
password: password
|
||||
maxWaitForConnection: 1s
|
||||
validationQuery: "/* MyService Health Check */ SELECT 1"
|
||||
minSize: 8
|
||||
maxSize: 32
|
||||
checkConnectionWhileIdle: false
|
||||
checkConnectionOnBorrow: true
|
||||
|
||||
databaseConfiguration:
|
||||
databaseType: influxdb
|
||||
|
||||
influxDB:
|
||||
version: V9
|
||||
maxHttpConnections: 100
|
||||
# Retention policy may be left blank to indicate default policy.
|
||||
retentionPolicy:
|
||||
name: mon
|
||||
url: http://192.168.10.4:8086
|
||||
user: mon_api
|
||||
password: password
|
||||
|
||||
vertica:
|
||||
driverClass: com.vertica.jdbc.Driver
|
||||
url: jdbc:vertica://192.168.10.8/mon
|
||||
user: dbadmin
|
||||
password: password
|
||||
maxWaitForConnection: 1s
|
||||
validationQuery: "/* MyService Health Check */ SELECT 1"
|
||||
minSize: 4
|
||||
maxSize: 32
|
||||
checkConnectionWhileIdle: false
|
||||
|
||||
middleware:
|
||||
enabled: true
|
||||
serverVIP: identity.example.com
|
||||
serverPort: 9543
|
||||
useHttps: true
|
||||
truststore: etc/monasca/truststore.jks
|
||||
truststorePass: changeit
|
||||
connTimeout: 500
|
||||
connSSLClientAuth: true
|
||||
keystore: etc/monasca/keystore.jks
|
||||
keystorePass: changeit
|
||||
connPoolMaxActive: 3
|
||||
connPoolMaxIdle: 3
|
||||
connPoolEvictPeriod: 600000
|
||||
connPoolMinIdleTime: 600000
|
||||
connRetryTimes: 2
|
||||
connRetryInterval: 50
|
||||
defaultAuthorizedRoles: [user, domainuser, domainadmin, monasca-user]
|
||||
agentAuthorizedRoles: [monasca-agent]
|
||||
adminAuthMethod: password
|
||||
adminUser: admin
|
||||
adminPassword: admin
|
||||
adminProjectId:
|
||||
adminProjectName:
|
||||
adminToken:
|
||||
timeToCacheToken: 600
|
||||
maxTokenCacheSize: 1048576
|
||||
|
||||
server:
|
||||
applicationConnectors:
|
||||
- type: http
|
||||
port: 8080
|
||||
maxRequestHeaderSize: 16KiB # Allow large headers used by keystone tokens
|
||||
requestLog:
|
||||
timeZone: UTC
|
||||
appenders:
|
||||
- type: file
|
||||
currentLogFilename: /var/log/monasca/api/request.log
|
||||
threshold: ALL
|
||||
archive: true
|
||||
archivedLogFilenamePattern: /var/log/monasca/api/request-%d.log.gz
|
||||
archivedFileCount: 5
|
||||
|
||||
# Logging settings.
|
||||
logging:
|
||||
|
||||
# The default level of all loggers. Can be OFF, ERROR, WARN, INFO, DEBUG, TRACE, or ALL.
|
||||
level: WARN
|
||||
|
||||
# Logger-specific levels.
|
||||
loggers:
|
||||
|
||||
# Sets the level for 'com.example.app' to DEBUG.
|
||||
com.example.app: DEBUG
|
||||
|
||||
appenders:
|
||||
- type: console
|
||||
threshold: ALL
|
||||
timeZone: UTC
|
||||
target: stdout
|
||||
logFormat: # TODO
|
||||
|
||||
- type: file
|
||||
currentLogFilename: /var/log/monasca/api/monasca-api.log
|
||||
threshold: ALL
|
||||
archive: true
|
||||
archivedLogFilenamePattern: /var/log/monasca/api/monasca-api-%d.log.gz
|
||||
archivedFileCount: 5
|
||||
timeZone: UTC
|
||||
logFormat: # TODO
|
||||
|
||||
- type: syslog
|
||||
host: localhost
|
||||
port: 514
|
||||
facility: local0
|
||||
threshold: ALL
|
||||
logFormat: # TODO
|
@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import monasca.common.messaging.kafka.KafkaConfiguration;
|
||||
import monasca.api.infrastructure.middleware.MiddlewareConfiguration;
|
||||
import monasca.common.configuration.DatabaseConfiguration;
|
||||
|
||||
import monasca.common.configuration.InfluxDbConfiguration;
|
||||
import io.dropwizard.Configuration;
|
||||
import io.dropwizard.db.DataSourceFactory;
|
||||
|
||||
import org.hibernate.validator.constraints.NotEmpty;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
|
||||
public class ApiConfig extends Configuration {
|
||||
@NotEmpty
|
||||
public String region;
|
||||
@NotNull
|
||||
public Boolean accessedViaHttps;
|
||||
@NotEmpty
|
||||
public String metricsTopic = "metrics";
|
||||
@NotEmpty
|
||||
public String eventsTopic = "events";
|
||||
@NotNull
|
||||
public int maxQueryLimit;
|
||||
@NotEmpty
|
||||
public String alarmStateTransitionsTopic = "alarm-state-transitions";
|
||||
|
||||
@Valid
|
||||
@NotNull
|
||||
public DataSourceFactory mysql;
|
||||
@Valid
|
||||
@NotNull
|
||||
public DataSourceFactory vertica;
|
||||
@Valid
|
||||
@NotNull
|
||||
public KafkaConfiguration kafka;
|
||||
@Valid
|
||||
@NotNull
|
||||
public MiddlewareConfiguration middleware;
|
||||
@Valid
|
||||
public InfluxDbConfiguration influxDB;
|
||||
@Valid
|
||||
@JsonProperty
|
||||
public DatabaseConfiguration databaseConfiguration;
|
||||
|
||||
}
|
@ -1,245 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
|
||||
import org.eclipse.jetty.servlets.CrossOriginFilter;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.FilterRegistration.Dynamic;
|
||||
import javax.ws.rs.ext.ExceptionMapper;
|
||||
|
||||
import io.dropwizard.Application;
|
||||
import io.dropwizard.jdbi.bundles.DBIExceptionsBundle;
|
||||
import io.dropwizard.setup.Bootstrap;
|
||||
import io.dropwizard.setup.Environment;
|
||||
import monasca.api.infrastructure.servlet.MockAuthenticationFilter;
|
||||
import monasca.api.infrastructure.servlet.PostAuthenticationFilter;
|
||||
import monasca.api.infrastructure.servlet.PreAuthenticationFilter;
|
||||
import monasca.api.infrastructure.servlet.RoleAuthorizationFilter;
|
||||
import monasca.api.resource.AlarmDefinitionResource;
|
||||
import monasca.api.resource.AlarmResource;
|
||||
import monasca.api.resource.MeasurementResource;
|
||||
import monasca.api.resource.MetricResource;
|
||||
import monasca.api.resource.NotificationMethodResource;
|
||||
import monasca.api.resource.StatisticResource;
|
||||
import monasca.api.resource.VersionResource;
|
||||
import monasca.api.resource.exception.ConstraintViolationExceptionMapper;
|
||||
import monasca.api.resource.exception.EntityExistsExceptionMapper;
|
||||
import monasca.api.resource.exception.EntityNotFoundExceptionMapper;
|
||||
import monasca.api.resource.exception.IllegalArgumentExceptionMapper;
|
||||
import monasca.api.resource.exception.InvalidEntityExceptionMapper;
|
||||
import monasca.api.resource.exception.JsonMappingExceptionManager;
|
||||
import monasca.api.resource.exception.JsonProcessingExceptionMapper;
|
||||
import monasca.api.resource.exception.MultipleMetricsExceptionMapper;
|
||||
import monasca.api.resource.exception.ThrowableExceptionMapper;
|
||||
import monasca.api.resource.serialization.SubAlarmExpressionSerializer;
|
||||
import monasca.common.middleware.AuthConstants;
|
||||
import monasca.common.middleware.TokenAuth;
|
||||
import monasca.common.util.Injector;
|
||||
|
||||
/**
|
||||
* Monitoring API application.
|
||||
*/
|
||||
public class MonApiApplication extends Application<ApiConfig> {
|
||||
public static void main(String[] args) throws Exception {
|
||||
/*
|
||||
* This should allow command line options to show the current version
|
||||
* java -jar monasca-api.jar --version
|
||||
* java -jar monasca-api.jar -version
|
||||
* java -jar monasca-api.jar version
|
||||
* Really anything with the word version in it will show the
|
||||
* version as long as there is only one argument
|
||||
* */
|
||||
if (args.length == 1 && args[0].toLowerCase().contains("version")) {
|
||||
showVersion();
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
new MonApiApplication().run(args);
|
||||
}
|
||||
|
||||
private static void showVersion() {
|
||||
Package pkg;
|
||||
pkg = Package.getPackage("monasca.api");
|
||||
|
||||
System.out.println("-------- Version Information --------");
|
||||
System.out.println(pkg.getImplementationVersion());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(Bootstrap<ApiConfig> bootstrap) {
|
||||
/** Configure bundles */
|
||||
bootstrap.addBundle(new DBIExceptionsBundle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "HP Cloud Monitoring";
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void run(ApiConfig config, Environment environment) throws Exception {
|
||||
/** Wire services */
|
||||
Injector.registerModules(new MonApiModule(environment, config));
|
||||
|
||||
/** Configure resources */
|
||||
environment.jersey().register(Injector.getInstance(VersionResource.class));
|
||||
environment.jersey().register(Injector.getInstance(AlarmDefinitionResource.class));
|
||||
environment.jersey().register(Injector.getInstance(AlarmResource.class));
|
||||
environment.jersey().register(Injector.getInstance(MetricResource.class));
|
||||
environment.jersey().register(Injector.getInstance(MeasurementResource.class));
|
||||
environment.jersey().register(Injector.getInstance(StatisticResource.class));
|
||||
environment.jersey().register(Injector.getInstance(NotificationMethodResource.class));
|
||||
|
||||
/** Configure providers */
|
||||
removeExceptionMappers(environment.jersey().getResourceConfig().getSingletons());
|
||||
environment.jersey().register(new EntityExistsExceptionMapper());
|
||||
environment.jersey().register(new EntityNotFoundExceptionMapper());
|
||||
environment.jersey().register(new IllegalArgumentExceptionMapper());
|
||||
environment.jersey().register(new InvalidEntityExceptionMapper());
|
||||
environment.jersey().register(new JsonProcessingExceptionMapper());
|
||||
environment.jersey().register(new JsonMappingExceptionManager());
|
||||
environment.jersey().register(new ConstraintViolationExceptionMapper());
|
||||
environment.jersey().register(new ThrowableExceptionMapper<Throwable>() {});
|
||||
environment.jersey().register(new MultipleMetricsExceptionMapper());
|
||||
|
||||
/** Configure Jackson */
|
||||
environment.getObjectMapper().setPropertyNamingStrategy(
|
||||
PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
|
||||
environment.getObjectMapper().enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
|
||||
environment.getObjectMapper().disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||
SimpleModule module = new SimpleModule("SerializationModule");
|
||||
module.addSerializer(new SubAlarmExpressionSerializer());
|
||||
environment.getObjectMapper().registerModule(module);
|
||||
|
||||
|
||||
/** Configure CORS filter */
|
||||
Dynamic corsFilter = environment.servlets().addFilter("cors", CrossOriginFilter.class);
|
||||
corsFilter.addMappingForUrlPatterns(null, true, "/*");
|
||||
corsFilter.setInitParameter("allowedOrigins", "*");
|
||||
corsFilter.setInitParameter("allowedHeaders",
|
||||
"X-Requested-With,Content-Type,Accept,Origin,X-Auth-Token");
|
||||
corsFilter.setInitParameter("allowedMethods", "OPTIONS,GET,HEAD");
|
||||
|
||||
if (config.middleware.enabled) {
|
||||
ensureHasValue(config.middleware.serverVIP, "serverVIP", "enabled", "true");
|
||||
ensureHasValue(config.middleware.serverPort, "serverPort", "enabled", "true");
|
||||
ensureHasValue(config.middleware.adminAuthMethod, "adminAuthMethod", "enabled", "true");
|
||||
if ("password".equalsIgnoreCase(config.middleware.adminAuthMethod)) {
|
||||
ensureHasValue(config.middleware.adminUser, "adminUser", "adminAuthMethod", "password");
|
||||
ensureHasValue(config.middleware.adminPassword, "adminPassword", "adminAuthMethod", "password");
|
||||
} else if ("token".equalsIgnoreCase(config.middleware.adminAuthMethod)) {
|
||||
ensureHasValue(config.middleware.adminToken, "adminToken", "adminAuthMethod", "token");
|
||||
} else {
|
||||
throw new Exception(String.format(
|
||||
"Invalid value '%s' for adminAuthMethod. Must be either password or token",
|
||||
config.middleware.adminAuthMethod));
|
||||
}
|
||||
if (config.middleware.defaultAuthorizedRoles == null || config.middleware.defaultAuthorizedRoles.isEmpty()) {
|
||||
ensureHasValue(null, "defaultAuthorizedRoles", "enabled", "true");
|
||||
}
|
||||
if (config.middleware.connSSLClientAuth) {
|
||||
ensureHasValue(config.middleware.keystore, "keystore", "connSSLClientAuth", "true");
|
||||
ensureHasValue(config.middleware.keystorePassword, "keystorePassword", "connSSLClientAuth", "true");
|
||||
}
|
||||
Map<String, String> authInitParams = new HashMap<String, String>();
|
||||
authInitParams.put("ServerVIP", config.middleware.serverVIP);
|
||||
authInitParams.put("ServerPort", config.middleware.serverPort);
|
||||
authInitParams.put(AuthConstants.USE_HTTPS, String.valueOf(config.middleware.useHttps));
|
||||
authInitParams.put("ConnTimeout", config.middleware.connTimeout);
|
||||
authInitParams.put("ConnSSLClientAuth", String.valueOf(config.middleware.connSSLClientAuth));
|
||||
authInitParams.put("ConnPoolMaxActive", config.middleware.connPoolMaxActive);
|
||||
authInitParams.put("ConnPoolMaxIdle", config.middleware.connPoolMaxActive);
|
||||
authInitParams.put("ConnPoolEvictPeriod", config.middleware.connPoolEvictPeriod);
|
||||
authInitParams.put("ConnPoolMinIdleTime", config.middleware.connPoolMinIdleTime);
|
||||
authInitParams.put("ConnRetryTimes", config.middleware.connRetryTimes);
|
||||
authInitParams.put("ConnRetryInterval", config.middleware.connRetryInterval);
|
||||
authInitParams.put("AdminToken", config.middleware.adminToken);
|
||||
authInitParams.put("TimeToCacheToken", config.middleware.timeToCacheToken);
|
||||
authInitParams.put("AdminAuthMethod", config.middleware.adminAuthMethod);
|
||||
authInitParams.put("AdminUser", config.middleware.adminUser);
|
||||
authInitParams.put("AdminPassword", config.middleware.adminPassword);
|
||||
authInitParams.put(AuthConstants.ADMIN_PROJECT_ID, config.middleware.adminProjectId);
|
||||
authInitParams.put(AuthConstants.ADMIN_PROJECT_NAME, config.middleware.adminProjectName);
|
||||
authInitParams.put("MaxTokenCacheSize", config.middleware.maxTokenCacheSize);
|
||||
setIfNotNull(authInitParams, AuthConstants.TRUSTSTORE, config.middleware.truststore);
|
||||
setIfNotNull(authInitParams, AuthConstants.TRUSTSTORE_PASS, config.middleware.truststorePassword);
|
||||
setIfNotNull(authInitParams, AuthConstants.KEYSTORE, config.middleware.keystore);
|
||||
setIfNotNull(authInitParams, AuthConstants.KEYSTORE_PASS, config.middleware.keystorePassword);
|
||||
|
||||
/** Configure auth filters */
|
||||
Dynamic preAuthenticationFilter =
|
||||
environment.servlets().addFilter("pre-auth", new PreAuthenticationFilter());
|
||||
preAuthenticationFilter.addMappingForUrlPatterns(null, true, "/");
|
||||
preAuthenticationFilter.addMappingForUrlPatterns(null, true, "/v2.0/*");
|
||||
|
||||
Dynamic tokenAuthFilter = environment.servlets().addFilter("token-auth", new TokenAuth());
|
||||
tokenAuthFilter.addMappingForUrlPatterns(null, true, "/");
|
||||
tokenAuthFilter.addMappingForUrlPatterns(null, true, "/v2.0/*");
|
||||
tokenAuthFilter.setInitParameters(authInitParams);
|
||||
|
||||
Dynamic postAuthenticationFilter =
|
||||
environment.servlets().addFilter(
|
||||
"post-auth",
|
||||
new PostAuthenticationFilter(config.middleware.defaultAuthorizedRoles,
|
||||
config.middleware.agentAuthorizedRoles));
|
||||
postAuthenticationFilter.addMappingForUrlPatterns(null, true, "/");
|
||||
postAuthenticationFilter.addMappingForUrlPatterns(null, true, "/v2.0/*");
|
||||
|
||||
environment.jersey().getResourceConfig().getContainerRequestFilters()
|
||||
.add(new RoleAuthorizationFilter());
|
||||
} else {
|
||||
Dynamic mockAuthenticationFilter =
|
||||
environment.servlets().addFilter("mock-auth", new MockAuthenticationFilter());
|
||||
mockAuthenticationFilter.addMappingForUrlPatterns(null, true, "/");
|
||||
mockAuthenticationFilter.addMappingForUrlPatterns(null, true, "/v2.0/*");
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureHasValue(final String value, final String what, final String control,
|
||||
final String controlValue) throws Exception {
|
||||
if (value == null || value.isEmpty()) {
|
||||
final String message =
|
||||
String
|
||||
.format(
|
||||
"Since %s in middleware section of configuration file is set to %s, %s must have a value",
|
||||
control, controlValue, what);
|
||||
throw new Exception(message);
|
||||
}
|
||||
}
|
||||
|
||||
private void setIfNotNull(Map<String, String> authInitParams, String name, String value) {
|
||||
if (value != null) {
|
||||
authInitParams.put(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeExceptionMappers(Set<Object> items) {
|
||||
for (Iterator<Object> i = items.iterator(); i.hasNext();) {
|
||||
Object o = i.next();
|
||||
if (o instanceof ExceptionMapper)
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api;
|
||||
|
||||
import io.dropwizard.db.DataSourceFactory;
|
||||
import io.dropwizard.jdbi.DBIFactory;
|
||||
import io.dropwizard.setup.Environment;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import kafka.javaapi.producer.Producer;
|
||||
import kafka.producer.ProducerConfig;
|
||||
|
||||
import org.skife.jdbi.v2.DBI;
|
||||
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.ProvisionException;
|
||||
import com.google.inject.name.Names;
|
||||
import monasca.api.app.ApplicationModule;
|
||||
import monasca.api.domain.DomainModule;
|
||||
import monasca.api.infrastructure.InfrastructureModule;
|
||||
|
||||
/**
|
||||
* Monitoring API server bindings.
|
||||
*/
|
||||
public class MonApiModule extends AbstractModule {
|
||||
private final ApiConfig config;
|
||||
private final Environment environment;
|
||||
|
||||
public MonApiModule(Environment environment, ApiConfig config) {
|
||||
this.environment = environment;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(ApiConfig.class).toInstance(config);
|
||||
bind(MetricRegistry.class).toInstance(environment.metrics());
|
||||
bind(DataSourceFactory.class).annotatedWith(Names.named("mysql")).toInstance(config.mysql);
|
||||
bind(DataSourceFactory.class).annotatedWith(Names.named("vertica")).toInstance(config.vertica);
|
||||
|
||||
install(new ApplicationModule());
|
||||
install(new DomainModule());
|
||||
install(new InfrastructureModule(this.config));
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Named("mysql")
|
||||
public DBI getMySqlDBI() {
|
||||
try {
|
||||
return new DBIFactory().build(environment, config.mysql, "mysql");
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new ProvisionException("Failed to provision MySQL DBI", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Named("vertica")
|
||||
public DBI getVerticaDBI() {
|
||||
try {
|
||||
return new DBIFactory().build(environment, config.vertica, "vertica");
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new ProvisionException("Failed to provision Vertica DBI", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
public Producer<String, String> getProducer() {
|
||||
Properties props = new Properties();
|
||||
props.put("metadata.broker.list", Joiner.on(',').join(config.kafka.brokerUris));
|
||||
props.put("serializer.class", "kafka.serializer.StringEncoder");
|
||||
props.put("request.required.acks", "1");
|
||||
ProducerConfig config = new ProducerConfig(props);
|
||||
return new Producer<String, String>(config);
|
||||
}
|
||||
}
|
@ -1,416 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.app;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import kafka.javaapi.producer.Producer;
|
||||
import kafka.producer.KeyedMessage;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import monasca.api.ApiConfig;
|
||||
import monasca.api.app.command.UpdateAlarmDefinitionCommand;
|
||||
import monasca.api.app.validation.DimensionValidation;
|
||||
import monasca.common.model.event.AlarmDefinitionCreatedEvent;
|
||||
import monasca.common.model.event.AlarmDefinitionDeletedEvent;
|
||||
import monasca.common.model.event.AlarmDefinitionUpdatedEvent;
|
||||
import monasca.common.model.event.AlarmDeletedEvent;
|
||||
import monasca.common.model.alarm.AlarmExpression;
|
||||
import monasca.common.model.alarm.AlarmSubExpression;
|
||||
import monasca.common.model.metric.MetricDefinition;
|
||||
import monasca.api.domain.exception.EntityExistsException;
|
||||
import monasca.api.domain.exception.EntityNotFoundException;
|
||||
import monasca.api.domain.exception.InvalidEntityException;
|
||||
import monasca.api.domain.model.alarm.Alarm;
|
||||
import monasca.api.domain.model.alarm.AlarmRepo;
|
||||
import monasca.api.domain.model.alarmdefinition.AlarmDefinition;
|
||||
import monasca.api.domain.model.alarmdefinition.AlarmDefinitionRepo;
|
||||
import monasca.api.domain.model.notificationmethod.NotificationMethodRepo;
|
||||
import monasca.common.util.Exceptions;
|
||||
import monasca.common.util.Serialization;
|
||||
|
||||
/**
|
||||
* Services alarm definition related requests.
|
||||
*/
|
||||
public class AlarmDefinitionService {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AlarmService.class);
|
||||
|
||||
private final ApiConfig config;
|
||||
private final Producer<String, String> producer;
|
||||
private final AlarmDefinitionRepo repo;
|
||||
private final AlarmRepo alarmRepo;
|
||||
private final NotificationMethodRepo notificationMethodRepo;
|
||||
long eventCount;
|
||||
|
||||
@Inject
|
||||
public AlarmDefinitionService(ApiConfig config, Producer<String, String> producer,
|
||||
AlarmDefinitionRepo repo, AlarmRepo alarmRepo,
|
||||
NotificationMethodRepo notificationMethodRepo) {
|
||||
this.config = config;
|
||||
this.producer = producer;
|
||||
this.repo = repo;
|
||||
this.alarmRepo = alarmRepo;
|
||||
this.notificationMethodRepo = notificationMethodRepo;
|
||||
}
|
||||
|
||||
static class SubExpressions {
|
||||
/** Sub expressions which have been removed from an updated alarm expression. */
|
||||
Map<String, AlarmSubExpression> oldAlarmSubExpressions;
|
||||
/** Sub expressions which have had their operator or threshold changed. */
|
||||
Map<String, AlarmSubExpression> changedSubExpressions;
|
||||
/** Sub expressions which have not changed. */
|
||||
Map<String, AlarmSubExpression> unchangedSubExpressions;
|
||||
/** Sub expressions which have been added to an updated alarm expression. */
|
||||
Map<String, AlarmSubExpression> newAlarmSubExpressions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an alarm definition and publishes an AlarmDefinitionCreatedEvent. Note, the event is
|
||||
* published first since chances of failure are higher.
|
||||
*
|
||||
* @throws EntityExistsException if an alarm already exists for the name
|
||||
* @throws InvalidEntityException if one of the actions cannot be found
|
||||
*/
|
||||
public AlarmDefinition create(String tenantId, String name, @Nullable String description,
|
||||
String severity, String expression, AlarmExpression alarmExpression, List<String> matchBy,
|
||||
List<String> alarmActions, @Nullable List<String> okActions,
|
||||
@Nullable List<String> undeterminedActions) {
|
||||
// Assert no alarm exists by the name
|
||||
String alarmDefID=repo.exists(tenantId, name);
|
||||
if (alarmDefID!=null) {
|
||||
throw new EntityExistsException(
|
||||
"An alarm definition already exists for project / tenant: %s named: %s", tenantId, name);
|
||||
}
|
||||
DimensionValidation.validateNames(matchBy);
|
||||
assertActionsExist(tenantId, alarmActions, okActions, undeterminedActions);
|
||||
|
||||
Map<String, AlarmSubExpression> subAlarms = new HashMap<String, AlarmSubExpression>();
|
||||
for (AlarmSubExpression subExpression : alarmExpression.getSubExpressions())
|
||||
subAlarms.put(UUID.randomUUID().toString(), subExpression);
|
||||
|
||||
String alarmDefId = UUID.randomUUID().toString();
|
||||
AlarmDefinition alarm = null;
|
||||
|
||||
try {
|
||||
LOG.debug("Creating alarm definition {} for tenant {}", name, tenantId);
|
||||
alarm =
|
||||
repo.create(tenantId, alarmDefId, name, description, severity, expression, subAlarms,
|
||||
matchBy, alarmActions, okActions, undeterminedActions);
|
||||
|
||||
// Notify interested parties of new alarm
|
||||
String event =
|
||||
Serialization.toJson(new AlarmDefinitionCreatedEvent(tenantId, alarmDefId, name,
|
||||
description, expression, subAlarms, matchBy));
|
||||
producer.send(new KeyedMessage<>(config.eventsTopic, String.valueOf(eventCount++), event));
|
||||
|
||||
return alarm;
|
||||
} catch (Exception e) {
|
||||
if (alarm != null)
|
||||
try {
|
||||
repo.deleteById(tenantId, alarm.getId());
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
throw Exceptions.uncheck(e, "Error creating alarm definition for project / tenant %s",
|
||||
tenantId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the alarm definition identified by the {@code alarmDefId}.
|
||||
*
|
||||
* @throws EntityNotFoundException if the alarm cannot be found
|
||||
*/
|
||||
public void delete(String tenantId, String alarmDefId) {
|
||||
Map<String, MetricDefinition> subAlarmMetricDefs =
|
||||
repo.findSubAlarmMetricDefinitions(alarmDefId);
|
||||
|
||||
// Have to get information about the Alarms before they are deleted. They will be deleted
|
||||
// by the database as a cascade delete from the Alarm Definition delete
|
||||
final List<Alarm> alarms = alarmRepo.find(tenantId, alarmDefId, null, null, null, null, null, 1, false);
|
||||
final Map<String, Map<String, AlarmSubExpression>> alarmSubExpressions =
|
||||
alarmRepo.findAlarmSubExpressionsForAlarmDefinition(alarmDefId);
|
||||
|
||||
repo.deleteById(tenantId, alarmDefId);
|
||||
|
||||
// Notify interested parties of alarm definition deletion
|
||||
String event =
|
||||
Serialization.toJson(new AlarmDefinitionDeletedEvent(alarmDefId, subAlarmMetricDefs));
|
||||
producer.send(new KeyedMessage<>(config.eventsTopic, String.valueOf(eventCount++), event));
|
||||
|
||||
// Notify about the Deletion of the Alarms second because that is the order that thresh
|
||||
// wants it so Alarms don't get recreated
|
||||
for (final Alarm alarm : alarms) {
|
||||
String alarmDeletedEvent =
|
||||
Serialization.toJson(new AlarmDeletedEvent(tenantId, alarm.getId(), alarm.getMetrics(),
|
||||
alarmDefId, alarmSubExpressions.get(alarm.getId())));
|
||||
producer.send(new KeyedMessage<>(config.eventsTopic, String.valueOf(eventCount++), alarmDeletedEvent));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the alarm definition for the {@code tenantId} and
|
||||
* {@code alarmDefId} to the state of the {@code command}.
|
||||
*
|
||||
* @throws EntityNotFoundException
|
||||
* if the alarm cannot be found
|
||||
* @throws InvalidEntityException
|
||||
* if one of the actions cannot be found
|
||||
*/
|
||||
public AlarmDefinition update(String tenantId, String alarmDefId,
|
||||
AlarmExpression alarmExpression,
|
||||
UpdateAlarmDefinitionCommand command) {
|
||||
final AlarmDefinition oldAlarmDefinition = assertAlarmDefinitionExists(
|
||||
tenantId, alarmDefId, command.alarmActions, command.okActions,
|
||||
command.undeterminedActions);
|
||||
final SubExpressions subExpressions = subExpressionsFor(
|
||||
repo.findSubExpressions(alarmDefId), alarmExpression);
|
||||
String alarmID = repo.exists(tenantId, command.name);
|
||||
if (alarmID != null && !alarmID.equalsIgnoreCase(alarmDefId)) {
|
||||
throw new EntityExistsException(
|
||||
"An alarm definition with the same name already exists for project / tenant: %s named: %s",
|
||||
tenantId, command.name);
|
||||
}
|
||||
validateChangesAllowed(command.matchBy, oldAlarmDefinition,
|
||||
subExpressions);
|
||||
updateInternal(tenantId, alarmDefId, false, command.name,
|
||||
command.description, command.expression, command.matchBy,
|
||||
command.severity, alarmExpression, command.actionsEnabled,
|
||||
command.alarmActions, command.okActions,
|
||||
command.undeterminedActions, subExpressions);
|
||||
return new AlarmDefinition(alarmDefId, command.name,
|
||||
command.description, command.severity, command.expression,
|
||||
command.matchBy, command.actionsEnabled, command.alarmActions,
|
||||
command.okActions, command.undeterminedActions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't allow changes that would cause existing Alarms for this AlarmDefinition to be invalidated.
|
||||
*
|
||||
* matchBy can't change and the expression can't change the metrics used or number of subexpressions
|
||||
*/
|
||||
private void validateChangesAllowed(final List<String> newMatchBy,
|
||||
final AlarmDefinition oldAlarmDefinition, final SubExpressions subExpressions) {
|
||||
final boolean matchBySame;
|
||||
if (oldAlarmDefinition.getMatchBy() == null || oldAlarmDefinition.getMatchBy().isEmpty()) {
|
||||
matchBySame = newMatchBy == null || newMatchBy.isEmpty();
|
||||
}
|
||||
else {
|
||||
matchBySame = oldAlarmDefinition.getMatchBy().equals(newMatchBy);
|
||||
}
|
||||
if (!matchBySame) {
|
||||
throw monasca.api.resource.exception.Exceptions.unprocessableEntity("match_by must not change");
|
||||
}
|
||||
if (!subExpressions.oldAlarmSubExpressions.isEmpty() || !subExpressions.newAlarmSubExpressions.isEmpty()) {
|
||||
final int newCount = subExpressions.newAlarmSubExpressions.size() +
|
||||
subExpressions.changedSubExpressions.size() +
|
||||
subExpressions.unchangedSubExpressions.size();
|
||||
if (newCount != AlarmExpression.of(oldAlarmDefinition.getExpression()).getSubExpressions().size()) {
|
||||
throw monasca.api.resource.exception.Exceptions.unprocessableEntity("number of subexpressions must not change");
|
||||
}
|
||||
else {
|
||||
throw monasca.api.resource.exception.Exceptions.unprocessableEntity("metrics in subexpression must not change");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Patches the alarm definition for the {@code tenantId} and {@code alarmDefId} to the state of
|
||||
* the {@code fields}.
|
||||
*
|
||||
* @throws EntityNotFoundException if the alarm cannot be found
|
||||
* @throws InvalidEntityException if one of the actions cannot be found
|
||||
*/
|
||||
public AlarmDefinition patch(String tenantId, String alarmDefId,
|
||||
String name, String description, String severity,
|
||||
String expression, AlarmExpression alarmExpression,
|
||||
List<String> matchBy, Boolean enabled, List<String> alarmActions,
|
||||
List<String> okActions, List<String> undeterminedActions) {
|
||||
AlarmDefinition oldAlarmDefinition = assertAlarmDefinitionExists(
|
||||
tenantId, alarmDefId, alarmActions, okActions,
|
||||
undeterminedActions);
|
||||
name = name == null ? oldAlarmDefinition.getName() : name;
|
||||
String alarmID = repo.exists(tenantId, name);
|
||||
if (alarmID != null && !alarmID.equalsIgnoreCase(alarmDefId)) {
|
||||
throw new EntityExistsException(
|
||||
"An alarm definition with the same name already exists for project / tenant: %s named: %s",
|
||||
tenantId, name);
|
||||
}
|
||||
description = description == null ? oldAlarmDefinition.getDescription()
|
||||
: description;
|
||||
expression = expression == null ? oldAlarmDefinition.getExpression()
|
||||
: expression;
|
||||
severity = severity == null ? oldAlarmDefinition.getSeverity()
|
||||
: severity;
|
||||
alarmExpression = alarmExpression == null ? AlarmExpression
|
||||
.of(expression) : alarmExpression;
|
||||
enabled = enabled == null ? oldAlarmDefinition.isActionsEnabled()
|
||||
: enabled;
|
||||
matchBy = matchBy == null ? oldAlarmDefinition.getMatchBy() : matchBy;
|
||||
|
||||
final SubExpressions subExpressions = subExpressionsFor(
|
||||
repo.findSubExpressions(alarmDefId), alarmExpression);
|
||||
validateChangesAllowed(matchBy, oldAlarmDefinition, subExpressions);
|
||||
updateInternal(tenantId, alarmDefId, true, name, description,
|
||||
expression, matchBy, severity, alarmExpression, enabled,
|
||||
alarmActions, okActions, undeterminedActions, subExpressions);
|
||||
|
||||
return new AlarmDefinition(alarmDefId, name, description, severity,
|
||||
expression, matchBy, enabled,
|
||||
alarmActions == null ? oldAlarmDefinition.getAlarmActions()
|
||||
: alarmActions,
|
||||
okActions == null ? oldAlarmDefinition.getOkActions()
|
||||
: okActions,
|
||||
undeterminedActions == null ? oldAlarmDefinition
|
||||
.getUndeterminedActions() : undeterminedActions);
|
||||
}
|
||||
|
||||
private void updateInternal(String tenantId, String alarmDefId,
|
||||
boolean patch, String name, String description, String expression,
|
||||
List<String> matchBy, String severity,
|
||||
AlarmExpression alarmExpression, Boolean enabled,
|
||||
List<String> alarmActions, List<String> okActions,
|
||||
List<String> undeterminedActions, SubExpressions subExpressions) {
|
||||
|
||||
try {
|
||||
LOG.debug("Updating alarm definition {} for tenant {}", name,
|
||||
tenantId);
|
||||
repo.update(tenantId, alarmDefId, patch, name, description,
|
||||
expression, matchBy, severity, enabled,
|
||||
subExpressions.oldAlarmSubExpressions.keySet(),
|
||||
subExpressions.changedSubExpressions,
|
||||
subExpressions.newAlarmSubExpressions, alarmActions,
|
||||
okActions, undeterminedActions);
|
||||
|
||||
// Notify interested parties of updated alarm
|
||||
String event = Serialization
|
||||
.toJson(new AlarmDefinitionUpdatedEvent(tenantId,
|
||||
alarmDefId, name, description, expression, matchBy,
|
||||
enabled, severity,
|
||||
subExpressions.oldAlarmSubExpressions,
|
||||
subExpressions.changedSubExpressions,
|
||||
subExpressions.unchangedSubExpressions,
|
||||
subExpressions.newAlarmSubExpressions));
|
||||
producer.send(new KeyedMessage<>(config.eventsTopic, String
|
||||
.valueOf(eventCount++), event));
|
||||
} catch (Exception e) {
|
||||
throw Exceptions.uncheck(e,
|
||||
"Error updating alarm definition for project / tenant %s",
|
||||
tenantId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an entry containing Maps of old, changed, and new sub expressions by comparing the
|
||||
* {@code alarmExpression} to the existing sub expressions for the {@code alarmDefId}.
|
||||
*/
|
||||
SubExpressions subExpressionsFor(final Map<String, AlarmSubExpression> initialSubExpressions,
|
||||
AlarmExpression alarmExpression) {
|
||||
BiMap<String, AlarmSubExpression> oldExpressions =
|
||||
HashBiMap.create(initialSubExpressions);
|
||||
Set<AlarmSubExpression> oldSet = oldExpressions.inverse().keySet();
|
||||
Set<AlarmSubExpression> newSet = new HashSet<>(alarmExpression.getSubExpressions());
|
||||
|
||||
// Identify old or changed expressions
|
||||
Set<AlarmSubExpression> oldOrChangedExpressions =
|
||||
new HashSet<>(Sets.difference(oldSet, newSet));
|
||||
|
||||
// Identify new or changed expressions
|
||||
Set<AlarmSubExpression> newOrChangedExpressions =
|
||||
new HashSet<>(Sets.difference(newSet, oldSet));
|
||||
|
||||
// Find changed expressions
|
||||
Map<String, AlarmSubExpression> changedExpressions = new HashMap<>();
|
||||
for (Iterator<AlarmSubExpression> oldIt = oldOrChangedExpressions.iterator(); oldIt.hasNext();) {
|
||||
AlarmSubExpression oldExpr = oldIt.next();
|
||||
for (Iterator<AlarmSubExpression> newIt = newOrChangedExpressions.iterator(); newIt.hasNext();) {
|
||||
AlarmSubExpression newExpr = newIt.next();
|
||||
if (sameKeyFields(oldExpr, newExpr)) {
|
||||
oldIt.remove();
|
||||
newIt.remove();
|
||||
changedExpressions.put(oldExpressions.inverse().get(oldExpr), newExpr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the list of unchanged expressions
|
||||
BiMap<String, AlarmSubExpression> unchangedExpressions = HashBiMap.create(oldExpressions);
|
||||
unchangedExpressions.values().removeAll(oldOrChangedExpressions);
|
||||
unchangedExpressions.keySet().removeAll(changedExpressions.keySet());
|
||||
|
||||
// Remove old sub expressions
|
||||
oldExpressions.values().retainAll(oldOrChangedExpressions);
|
||||
|
||||
// Create IDs for new expressions
|
||||
Map<String, AlarmSubExpression> newExpressions = new HashMap<>();
|
||||
for (AlarmSubExpression expression : newOrChangedExpressions)
|
||||
newExpressions.put(UUID.randomUUID().toString(), expression);
|
||||
|
||||
SubExpressions subExpressions = new SubExpressions();
|
||||
subExpressions.oldAlarmSubExpressions = oldExpressions;
|
||||
subExpressions.changedSubExpressions = changedExpressions;
|
||||
subExpressions.unchangedSubExpressions = unchangedExpressions;
|
||||
subExpressions.newAlarmSubExpressions = newExpressions;
|
||||
return subExpressions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether all of the metrics of {@code a} and {@code b} are the same. The Threshold
|
||||
* Engine can handle any other type of change to the expression
|
||||
*/
|
||||
private boolean sameKeyFields(AlarmSubExpression a, AlarmSubExpression b) {
|
||||
return a.getMetricDefinition().equals(b.getMetricDefinition());
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts an alarm definition exists for the {@code alarmDefId} as well as the actions.
|
||||
*
|
||||
* @throws EntityNotFoundException if the alarm cannot be found
|
||||
*/
|
||||
private AlarmDefinition assertAlarmDefinitionExists(String tenantId, String alarmDefId,
|
||||
List<String> alarmActions, List<String> okActions, List<String> undeterminedActions) {
|
||||
AlarmDefinition alarm = repo.findById(tenantId, alarmDefId);
|
||||
assertActionsExist(tenantId, alarmActions, okActions, undeterminedActions);
|
||||
return alarm;
|
||||
}
|
||||
|
||||
private void assertActionsExist(String tenantId, List<String> alarmActions,
|
||||
List<String> okActions, List<String> undeterminedActions) {
|
||||
Set<String> actions = new HashSet<>();
|
||||
if (alarmActions != null)
|
||||
actions.addAll(alarmActions);
|
||||
if (okActions != null)
|
||||
actions.addAll(okActions);
|
||||
if (undeterminedActions != null)
|
||||
actions.addAll(undeterminedActions);
|
||||
if (!actions.isEmpty())
|
||||
for (String action : actions)
|
||||
if (!notificationMethodRepo.exists(tenantId, action))
|
||||
throw new InvalidEntityException("No notification method exists for action %s", action);
|
||||
}
|
||||
}
|
@ -1,141 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.app;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import kafka.javaapi.producer.Producer;
|
||||
import kafka.producer.KeyedMessage;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import monasca.api.ApiConfig;
|
||||
import monasca.api.app.command.UpdateAlarmCommand;
|
||||
import monasca.common.model.event.AlarmDeletedEvent;
|
||||
import monasca.common.model.event.AlarmStateTransitionedEvent;
|
||||
import monasca.common.model.event.AlarmUpdatedEvent;
|
||||
import monasca.common.model.alarm.AlarmState;
|
||||
import monasca.common.model.alarm.AlarmSubExpression;
|
||||
import monasca.api.domain.exception.EntityNotFoundException;
|
||||
import monasca.api.domain.exception.InvalidEntityException;
|
||||
import monasca.api.domain.model.alarm.Alarm;
|
||||
import monasca.api.domain.model.alarm.AlarmRepo;
|
||||
import monasca.api.domain.model.alarmdefinition.AlarmDefinition;
|
||||
import monasca.api.domain.model.alarmdefinition.AlarmDefinitionRepo;
|
||||
import monasca.common.util.Exceptions;
|
||||
import monasca.common.util.Serialization;
|
||||
|
||||
/**
|
||||
* Services alarmed metric related requests.
|
||||
*/
|
||||
public class AlarmService {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AlarmService.class);
|
||||
|
||||
private final ApiConfig config;
|
||||
private final Producer<String, String> producer;
|
||||
private final AlarmRepo repo;
|
||||
private final AlarmDefinitionRepo alarmDefRepo;
|
||||
private long messageCount = 0;
|
||||
|
||||
@Inject
|
||||
public AlarmService(ApiConfig config, Producer<String, String> producer,
|
||||
AlarmRepo repo, AlarmDefinitionRepo alarmDefRepo) {
|
||||
this.config = config;
|
||||
this.producer = producer;
|
||||
this.repo = repo;
|
||||
this.alarmDefRepo = alarmDefRepo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the alarm identified by the {@code alarmId
|
||||
* }.
|
||||
*
|
||||
* @throws EntityNotFoundException if the alarm cannot be found
|
||||
*/
|
||||
public void delete(String tenantId, String alarmId) {
|
||||
Alarm alarm = repo.findById(tenantId, alarmId);
|
||||
Map<String, AlarmSubExpression> subAlarmMetricDefs = repo.findAlarmSubExpressions(alarmId);
|
||||
repo.deleteById(tenantId, alarmId);
|
||||
|
||||
// Notify interested parties of alarm deletion
|
||||
String event =
|
||||
Serialization.toJson(new AlarmDeletedEvent(tenantId, alarmId, alarm.getMetrics(), alarm
|
||||
.getAlarmDefinition().getId(), subAlarmMetricDefs));
|
||||
producer.send(new KeyedMessage<>(config.eventsTopic, String.valueOf(messageCount++), event));
|
||||
}
|
||||
|
||||
/**
|
||||
* Patches the alarm for the {@code tenantId} and {@code alarmId} to the state of the
|
||||
* {@code fields}.
|
||||
*
|
||||
* @throws EntityNotFoundException if the alarm cannot be found
|
||||
* @throws InvalidEntityException if one of the actions cannot be found
|
||||
*/
|
||||
public Alarm patch(String tenantId, String alarmId, AlarmState state) {
|
||||
if (state == null) {
|
||||
throw new InvalidEntityException("State must be specified");
|
||||
}
|
||||
Alarm alarm = updateInternal(tenantId, alarmId, state);
|
||||
return alarm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the alarmed metric for the {@code tenantId} and {@code alarmedMetricId} to the state of
|
||||
* the {@code command}.
|
||||
*
|
||||
* @throws EntityNotFoundException if the alarmed metric cannot be found
|
||||
*/
|
||||
public Alarm update(String tenantId, String alarmId, UpdateAlarmCommand command) {
|
||||
Alarm alarm = updateInternal(tenantId, alarmId, command.state);
|
||||
return alarm;
|
||||
}
|
||||
|
||||
private String stateChangeReasonFor(AlarmState oldState, AlarmState newState) {
|
||||
return "Alarm state updated via API";
|
||||
}
|
||||
|
||||
private Alarm updateInternal(String tenantId, String alarmId, AlarmState newState) {
|
||||
try {
|
||||
LOG.debug("Updating alarm {} for tenant {}", alarmId, tenantId);
|
||||
final Alarm alarm = repo.update(tenantId, alarmId, newState);
|
||||
final AlarmState oldState = alarm.getState();
|
||||
// Notify interested parties of updated alarm
|
||||
AlarmDefinition alarmDef = alarmDefRepo.findById(tenantId, alarm.getAlarmDefinition().getId());
|
||||
Map<String, AlarmSubExpression> subAlarms = repo.findAlarmSubExpressions(alarmId);
|
||||
String event =
|
||||
Serialization.toJson(new AlarmUpdatedEvent(alarmId, alarmDef.getId(),
|
||||
tenantId, alarm.getMetrics(), subAlarms, newState, oldState));
|
||||
producer.send(new KeyedMessage<>(config.eventsTopic, String.valueOf(messageCount++), event));
|
||||
|
||||
// Notify interested parties of transitioned alarm state
|
||||
if (!oldState.equals(newState)) {
|
||||
event =
|
||||
Serialization.toJson(new AlarmStateTransitionedEvent(tenantId, alarmId, alarmDef
|
||||
.getId(), alarm.getMetrics(), alarmDef.getName(), alarmDef.getDescription(),
|
||||
oldState, newState, alarmDef.getSeverity(), alarmDef.isActionsEnabled(),
|
||||
stateChangeReasonFor(oldState, newState), null, System.currentTimeMillis()));
|
||||
producer.send(new KeyedMessage<>(config.alarmStateTransitionsTopic, String.valueOf(messageCount++), event));
|
||||
}
|
||||
alarm.setState(newState);
|
||||
return alarm;
|
||||
} catch (EntityNotFoundException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw Exceptions.uncheck(e, "Error updating alarm for project / tenant %s", tenantId);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.app;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
|
||||
/**
|
||||
* Application layer bindings.
|
||||
*/
|
||||
public class ApplicationModule extends AbstractModule {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(MetricService.class).in(Singleton.class);
|
||||
bind(AlarmDefinitionService.class).in(Singleton.class);
|
||||
bind(AlarmService.class).in(Singleton.class);
|
||||
}
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.app;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import kafka.javaapi.producer.Producer;
|
||||
import kafka.producer.KeyedMessage;
|
||||
|
||||
import com.codahale.metrics.Meter;
|
||||
import com.codahale.metrics.MetricRegistry;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMap.Builder;
|
||||
|
||||
import monasca.api.ApiConfig;
|
||||
import monasca.common.model.metric.Metric;
|
||||
import monasca.common.model.metric.MetricEnvelope;
|
||||
import monasca.common.model.metric.MetricEnvelopes;
|
||||
|
||||
/**
|
||||
* Metric service implementation.
|
||||
*/
|
||||
public class MetricService {
|
||||
private final ApiConfig config;
|
||||
private final Producer<String, String> producer;
|
||||
private final Meter metricMeter;
|
||||
private final Meter batchMeter;
|
||||
|
||||
@Inject
|
||||
public MetricService(ApiConfig config, Producer<String, String> producer,
|
||||
MetricRegistry metricRegistry) {
|
||||
this.config = config;
|
||||
this.producer = producer;
|
||||
metricMeter =
|
||||
metricRegistry.meter(MetricRegistry.name(MetricService.class, "metrics.published"));
|
||||
batchMeter =
|
||||
metricRegistry.meter(MetricRegistry.name(MetricService.class, "batches.published"));
|
||||
}
|
||||
|
||||
public void create(List<Metric> metrics, String tenantId, @Nullable String crossTenantId) {
|
||||
String metricTenantId = Strings.isNullOrEmpty(crossTenantId) ? tenantId : crossTenantId;
|
||||
Builder<String, Object> metaBuilder =
|
||||
new ImmutableMap.Builder<String, Object>().put("tenantId", metricTenantId).put("region",
|
||||
config.region);
|
||||
ImmutableMap<String, Object> meta = metaBuilder.build();
|
||||
|
||||
List<KeyedMessage<String, String>> keyedMessages = new ArrayList<>(metrics.size());
|
||||
for (Metric metric : metrics) {
|
||||
MetricEnvelope envelope = new MetricEnvelope(metric, meta);
|
||||
keyedMessages.add(new KeyedMessage<>(config.metricsTopic, buildKey(metricTenantId, metric),
|
||||
MetricEnvelopes.toJson(envelope)));
|
||||
metricMeter.mark();
|
||||
}
|
||||
|
||||
producer.send(keyedMessages);
|
||||
batchMeter.mark();
|
||||
}
|
||||
|
||||
private String buildKey(String metricTenantId, Metric metric) {
|
||||
final StringBuilder key = new StringBuilder(metricTenantId);
|
||||
key.append(metric.name);
|
||||
|
||||
// Dimensions are optional.
|
||||
if (metric.dimensions != null && !metric.dimensions.isEmpty()) {
|
||||
|
||||
// Key must be the same for the same metric so sort the dimensions so they will be
|
||||
// in a known order
|
||||
for (final Map.Entry<String, String> dim : buildSortedDimSet(metric.dimensions)) {
|
||||
key.append(dim.getKey());
|
||||
key.append(dim.getValue());
|
||||
}
|
||||
}
|
||||
String keyValue = key.toString();
|
||||
return keyValue;
|
||||
}
|
||||
|
||||
private List<Map.Entry<String, String>> buildSortedDimSet(final Map<String, String> dimMap) {
|
||||
final List<Map.Entry<String, String>> dims = new ArrayList<>(dimMap.entrySet());
|
||||
Collections.sort(dims, new Comparator<Map.Entry<String, String>>() {
|
||||
@Override
|
||||
public int compare(Entry<String, String> o1, Entry<String, String> o2) {
|
||||
int nameCmp = o1.getKey().compareTo(o2.getKey());
|
||||
return (nameCmp != 0 ? nameCmp : o1.getValue().compareTo(o2.getValue()));
|
||||
}
|
||||
});
|
||||
return dims;
|
||||
}
|
||||
}
|
@ -1,124 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.app.command;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.hibernate.validator.constraints.NotEmpty;
|
||||
|
||||
import monasca.api.app.validation.AlarmValidation;
|
||||
|
||||
public class CreateAlarmDefinitionCommand {
|
||||
@NotEmpty
|
||||
public String name;
|
||||
public String description;
|
||||
@NotEmpty
|
||||
public String expression;
|
||||
public List<String> matchBy;
|
||||
public String severity;
|
||||
public List<String> alarmActions;
|
||||
public List<String> okActions;
|
||||
public List<String> undeterminedActions;
|
||||
|
||||
public CreateAlarmDefinitionCommand() {
|
||||
this.severity = "LOW";
|
||||
}
|
||||
|
||||
public CreateAlarmDefinitionCommand(String name, @Nullable String description, String expression,
|
||||
List<String> matchBy, String severity, List<String> alarmActions, List<String> okActions,
|
||||
List<String> undeterminedActions) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.expression = expression;
|
||||
this.matchBy = matchBy;
|
||||
this.alarmActions = alarmActions;
|
||||
this.okActions = okActions;
|
||||
this.undeterminedActions = undeterminedActions;
|
||||
this.severity = severity == null ? "LOW" : severity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (!(obj instanceof CreateAlarmDefinitionCommand))
|
||||
return false;
|
||||
CreateAlarmDefinitionCommand other = (CreateAlarmDefinitionCommand) obj;
|
||||
if (alarmActions == null) {
|
||||
if (other.alarmActions != null)
|
||||
return false;
|
||||
} else if (!alarmActions.equals(other.alarmActions))
|
||||
return false;
|
||||
if (description == null) {
|
||||
if (other.description != null)
|
||||
return false;
|
||||
} else if (!description.equals(other.description))
|
||||
return false;
|
||||
if (expression == null) {
|
||||
if (other.expression != null)
|
||||
return false;
|
||||
} else if (!expression.equals(other.expression))
|
||||
return false;
|
||||
if (matchBy == null) {
|
||||
if (other.matchBy != null)
|
||||
return false;
|
||||
} else if (!matchBy.equals(other.matchBy))
|
||||
return false;
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!name.equals(other.name))
|
||||
return false;
|
||||
if (okActions == null) {
|
||||
if (other.okActions != null)
|
||||
return false;
|
||||
} else if (!okActions.equals(other.okActions))
|
||||
return false;
|
||||
if (severity == null) {
|
||||
if (other.severity != null)
|
||||
return false;
|
||||
} else if (!severity.equals(other.severity))
|
||||
return false;
|
||||
if (undeterminedActions == null) {
|
||||
if (other.undeterminedActions != null)
|
||||
return false;
|
||||
} else if (!undeterminedActions.equals(other.undeterminedActions))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((alarmActions == null) ? 0 : alarmActions.hashCode());
|
||||
result = prime * result + ((description == null) ? 0 : description.hashCode());
|
||||
result = prime * result + ((expression == null) ? 0 : expression.hashCode());
|
||||
result = prime * result + ((matchBy == null) ? 0 : matchBy.hashCode());
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
result = prime * result + ((okActions == null) ? 0 : okActions.hashCode());
|
||||
result = prime * result + ((severity == null) ? 0 : severity.hashCode());
|
||||
result = prime * result + ((undeterminedActions == null) ? 0 : undeterminedActions.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
public void validate() {
|
||||
AlarmValidation.validate(name, description, severity, alarmActions, okActions,
|
||||
undeterminedActions);
|
||||
}
|
||||
}
|
@ -1,143 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.app.command;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import org.hibernate.validator.constraints.NotEmpty;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import monasca.api.app.validation.DimensionValidation;
|
||||
import monasca.api.app.validation.MetricNameValidation;
|
||||
import monasca.api.app.validation.ValueMetaValidation;
|
||||
import monasca.common.model.Services;
|
||||
import monasca.common.model.metric.Metric;
|
||||
import monasca.api.resource.exception.Exceptions;
|
||||
|
||||
public class CreateMetricCommand {
|
||||
private static final long TIME_2MIN_MILLIS = 120*1000;
|
||||
private static final long TIME_2WEEKS_MILLIS = 1209600*1000;
|
||||
public static final int MAX_NAME_LENGTH = 255;
|
||||
|
||||
@NotEmpty
|
||||
@Size(min = 1, max = MAX_NAME_LENGTH)
|
||||
public String name;
|
||||
public Map<String, String> dimensions;
|
||||
public long timestamp;
|
||||
public double value;
|
||||
public Map<String, String> valueMeta;
|
||||
|
||||
public CreateMetricCommand() {}
|
||||
|
||||
public CreateMetricCommand(String name, @Nullable Map<String, String> dimensions,
|
||||
@Nullable Long timestamp, double value, @Nullable Map<String, String> valueMeta) {
|
||||
setName(name);
|
||||
setDimensions(dimensions);
|
||||
setTimestamp(timestamp);
|
||||
setValueMeta(valueMeta);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
private static void validateTimestamp(long timestamp) {
|
||||
long time = System.currentTimeMillis();
|
||||
if (timestamp > time + TIME_2MIN_MILLIS || timestamp < time - TIME_2WEEKS_MILLIS)
|
||||
throw Exceptions.unprocessableEntity("Timestamp %s is out of legal range", timestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
CreateMetricCommand other = (CreateMetricCommand) obj;
|
||||
if (dimensions == null) {
|
||||
if (other.dimensions != null)
|
||||
return false;
|
||||
} else if (!dimensions.equals(other.dimensions))
|
||||
return false;
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!name.equals(other.name))
|
||||
return false;
|
||||
if (timestamp != other.timestamp)
|
||||
return false;
|
||||
if (Double.doubleToLongBits(value) != Double.doubleToLongBits(other.value))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((dimensions == null) ? 0 : dimensions.hashCode());
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
result = prime * result + (int) (timestamp ^ (timestamp >>> 32));
|
||||
long temp;
|
||||
temp = Double.doubleToLongBits(value);
|
||||
result = prime * result + (int) (temp ^ (temp >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public void setDimensions(Map<String, String> dimensions) {
|
||||
this.dimensions =
|
||||
dimensions == null || dimensions.isEmpty() ? null : DimensionValidation
|
||||
.normalize(dimensions);
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public void setValueMeta(Map<String, String> valueMeta) {
|
||||
this.valueMeta = ValueMetaValidation.normalize(valueMeta);
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public void setName(String name) {
|
||||
this.name = MetricNameValidation.normalize(name);
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public void setTimestamp(Long timestamp) {
|
||||
this.timestamp =
|
||||
timestamp == null || timestamp.longValue() == 0L ? System.currentTimeMillis()
|
||||
: timestamp.longValue();
|
||||
}
|
||||
|
||||
public Metric toMetric() {
|
||||
return new Metric(name, dimensions, timestamp, value, valueMeta);
|
||||
}
|
||||
|
||||
public void validate() {
|
||||
// Validate name and dimensions
|
||||
if (dimensions != null) {
|
||||
String service = dimensions.get(Services.SERVICE_DIMENSION);
|
||||
MetricNameValidation.validate(name, service, true);
|
||||
DimensionValidation.validate(dimensions, service);
|
||||
}
|
||||
if (valueMeta != null) {
|
||||
ValueMetaValidation.validate(valueMeta);
|
||||
}
|
||||
|
||||
// Validate times and values
|
||||
validateTimestamp(timestamp);
|
||||
}
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.app.command;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import org.apache.commons.validator.routines.EmailValidator;
|
||||
import org.apache.commons.validator.routines.UrlValidator;
|
||||
import org.hibernate.validator.constraints.NotEmpty;
|
||||
|
||||
import monasca.api.domain.model.notificationmethod.NotificationMethodType;
|
||||
import monasca.api.resource.exception.Exceptions;
|
||||
|
||||
public class CreateNotificationMethodCommand {
|
||||
@NotEmpty
|
||||
@Size(min = 1, max = 250)
|
||||
public String name;
|
||||
@NotNull
|
||||
public NotificationMethodType type;
|
||||
@NotEmpty
|
||||
@Size(min = 1, max = 100)
|
||||
public String address;
|
||||
|
||||
public CreateNotificationMethodCommand() {}
|
||||
|
||||
public CreateNotificationMethodCommand(String name, NotificationMethodType type, String address) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
CreateNotificationMethodCommand other = (CreateNotificationMethodCommand) obj;
|
||||
if (address == null) {
|
||||
if (other.address != null)
|
||||
return false;
|
||||
} else if (!address.equals(other.address))
|
||||
return false;
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!name.equals(other.name))
|
||||
return false;
|
||||
if (type != other.type)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void validate() {
|
||||
switch (type) {
|
||||
case EMAIL : {
|
||||
if (!EmailValidator.getInstance(true).isValid(address))
|
||||
throw Exceptions.unprocessableEntity("Address %s is not of correct format", address);
|
||||
}; break;
|
||||
case WEBHOOK : {
|
||||
String[] schemes = {"http","https"};
|
||||
UrlValidator urlValidator = new UrlValidator(schemes, UrlValidator.ALLOW_LOCAL_URLS | UrlValidator.ALLOW_2_SLASHES);
|
||||
if (!urlValidator.isValid(address))
|
||||
throw Exceptions.unprocessableEntity("Address %s is not of correct format", address);
|
||||
}; break;
|
||||
case PAGERDUTY : {
|
||||
// No known validation for PAGERDUTY type at this time
|
||||
}; break;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.app.command;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import monasca.common.model.alarm.AlarmState;
|
||||
|
||||
public class UpdateAlarmCommand {
|
||||
@NotNull
|
||||
public AlarmState state;
|
||||
|
||||
public UpdateAlarmCommand() {}
|
||||
|
||||
public UpdateAlarmCommand(AlarmState state) {
|
||||
this.state = state;
|
||||
}
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.app.command;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
public class UpdateAlarmDefinitionCommand extends CreateAlarmDefinitionCommand {
|
||||
@NotNull
|
||||
public Boolean actionsEnabled;
|
||||
|
||||
public UpdateAlarmDefinitionCommand() {}
|
||||
|
||||
public UpdateAlarmDefinitionCommand(String name, @Nullable String description, String expression,
|
||||
List<String> matchBy, String severity, boolean enabled, List<String> alarmActions,
|
||||
List<String> okActions, List<String> undeterminedActions) {
|
||||
super(name, description, expression, matchBy, severity, alarmActions, okActions,
|
||||
undeterminedActions);
|
||||
this.actionsEnabled = enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (!super.equals(obj))
|
||||
return false;
|
||||
if (!(obj instanceof UpdateAlarmDefinitionCommand))
|
||||
return false;
|
||||
UpdateAlarmDefinitionCommand other = (UpdateAlarmDefinitionCommand) obj;
|
||||
if (actionsEnabled == null) {
|
||||
if (other.actionsEnabled != null)
|
||||
return false;
|
||||
} else if (!actionsEnabled.equals(other.actionsEnabled))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + ((actionsEnabled == null) ? 0 : actionsEnabled.hashCode());
|
||||
return result;
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Houses the application/service layer.
|
||||
*
|
||||
* @see http://martinfowler.com/eaaCatalog/serviceLayer.html
|
||||
*/
|
||||
package monasca.api.app;
|
@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.app.validation;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
|
||||
import monasca.common.model.Services;
|
||||
import monasca.common.model.alarm.AlarmExpression;
|
||||
import monasca.common.model.alarm.AlarmSubExpression;
|
||||
import monasca.common.model.metric.MetricDefinition;
|
||||
import monasca.api.resource.exception.Exceptions;
|
||||
|
||||
/**
|
||||
* Utilities for validating AlarmExpressions.
|
||||
*/
|
||||
public final class AlarmValidation {
|
||||
|
||||
private static final List<String> VALID_ALARM_SERVERITY = Arrays.asList("low", "medium", "high",
|
||||
"critical");
|
||||
|
||||
private AlarmValidation() {}
|
||||
|
||||
/**
|
||||
* @throws WebApplicationException if validation fails
|
||||
*/
|
||||
public static void validate(String name, String description, String severity,
|
||||
List<String> alarmActions, List<String> okActions, List<String> undeterminedActions) {
|
||||
if (name != null && name.length() > 255)
|
||||
throw Exceptions.unprocessableEntity("Name %s must be 255 characters or less", name);
|
||||
if (description != null && description.length() > 255)
|
||||
throw Exceptions.unprocessableEntity("Description %s must be 255 characters or less",
|
||||
description);
|
||||
if (alarmActions != null)
|
||||
for (String action : alarmActions)
|
||||
if (action.length() > 50)
|
||||
throw Exceptions.unprocessableEntity("Alarm action %s must be 50 characters or less",
|
||||
action);
|
||||
if (okActions != null)
|
||||
for (String action : okActions)
|
||||
if (action.length() > 50)
|
||||
throw Exceptions
|
||||
.unprocessableEntity("Ok action %s must be 50 characters or less", action);
|
||||
if (undeterminedActions != null)
|
||||
for (String action : undeterminedActions)
|
||||
if (action.length() > 50)
|
||||
throw Exceptions.unprocessableEntity(
|
||||
"Undetermined action %s must be 50 characters or less", action);
|
||||
if (severity != null && !VALID_ALARM_SERVERITY.contains(severity.toLowerCase())) {
|
||||
throw Exceptions.unprocessableEntity("%s is not a valid severity", severity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates, normalizes and gets an AlarmExpression for the {@code expression}.
|
||||
*
|
||||
* @throws WebApplicationException if validation fails
|
||||
*/
|
||||
public static AlarmExpression validateNormalizeAndGet(String expression) {
|
||||
AlarmExpression alarmExpression = null;
|
||||
|
||||
try {
|
||||
alarmExpression = AlarmExpression.of(expression);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw Exceptions.unprocessableEntityDetails("The alarm expression is invalid",
|
||||
e.getMessage(), e);
|
||||
}
|
||||
|
||||
for (AlarmSubExpression subExpression : alarmExpression.getSubExpressions()) {
|
||||
MetricDefinition metricDef = subExpression.getMetricDefinition();
|
||||
String service =
|
||||
metricDef.dimensions == null ? null : metricDef.dimensions
|
||||
.get(Services.SERVICE_DIMENSION);
|
||||
|
||||
// Normalize and validate namespace
|
||||
metricDef.name = MetricNameValidation.normalize(metricDef.name);
|
||||
MetricNameValidation.validate(metricDef.name, service, true);
|
||||
|
||||
// Normalize and validate dimensions
|
||||
if (metricDef.dimensions != null) {
|
||||
metricDef.setDimensions(DimensionValidation.normalize(metricDef.dimensions));
|
||||
DimensionValidation.validate(metricDef.dimensions, service);
|
||||
}
|
||||
|
||||
// Validate period
|
||||
if (subExpression.getPeriod() == 0)
|
||||
throw Exceptions.unprocessableEntity("Period must not be 0");
|
||||
if (subExpression.getPeriod() % 60 != 0)
|
||||
throw Exceptions.unprocessableEntity("Period %s must be a multiple of 60",
|
||||
subExpression.getPeriod());
|
||||
|
||||
// Validate periods
|
||||
if (subExpression.getPeriods() < 1)
|
||||
throw Exceptions.unprocessableEntity("Periods %s must be greater than or equal to 1",
|
||||
subExpression.getPeriods());
|
||||
if (subExpression.getPeriod() * subExpression.getPeriods() > 1209600)
|
||||
throw Exceptions.unprocessableEntity(
|
||||
"Period %s times %s must total less than 2 weeks in seconds (1209600)",
|
||||
subExpression.getPeriod(), subExpression.getPeriods());
|
||||
}
|
||||
|
||||
return alarmExpression;
|
||||
}
|
||||
}
|
@ -1,181 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.app.validation;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
|
||||
import com.google.common.base.CharMatcher;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.primitives.Ints;
|
||||
import monasca.common.model.Services;
|
||||
import monasca.api.resource.exception.Exceptions;
|
||||
|
||||
/**
|
||||
* Utilities for validating dimensions.
|
||||
*/
|
||||
public final class DimensionValidation {
|
||||
private static final Map<String, DimensionValidator> VALIDATORS;
|
||||
private static final Pattern UUID_PATTERN = Pattern
|
||||
.compile("\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}");
|
||||
private static final Pattern VALID_DIMENSION_NAME = Pattern.compile("[^><={}(), '\";&]+$");
|
||||
private static final String INVALID_CHAR_STRING = "> < = { } ( ) ' \" , ; &";
|
||||
|
||||
private DimensionValidation() {}
|
||||
|
||||
interface DimensionValidator {
|
||||
boolean isValidDimension(String name, String value);
|
||||
}
|
||||
|
||||
static {
|
||||
VALIDATORS = new HashMap<String, DimensionValidator>();
|
||||
|
||||
// Compute validator
|
||||
VALIDATORS.put(Services.COMPUTE_SERVICE, new DimensionValidator() {
|
||||
@Override
|
||||
public boolean isValidDimension(String name, String value) {
|
||||
if ("instance_id".equals(name))
|
||||
return value.length() != 36 || UUID_PATTERN.matcher(value).matches();
|
||||
if ("az".equals(name))
|
||||
return Ints.tryParse(value) != null;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// Objectstore validator
|
||||
VALIDATORS.put(Services.OBJECT_STORE_SERVICE, new DimensionValidator() {
|
||||
@Override
|
||||
public boolean isValidDimension(String name, String value) {
|
||||
if ("container".equals(name))
|
||||
return value.length() < 256 || !value.contains("/");
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// Volume validator
|
||||
VALIDATORS.put(Services.VOLUME_SERVICE, new DimensionValidator() {
|
||||
@Override
|
||||
public boolean isValidDimension(String name, String value) {
|
||||
if ("instance_id".equals(name))
|
||||
return value.length() != 36 || UUID_PATTERN.matcher(value).matches();
|
||||
if ("az".equals(name))
|
||||
return Ints.tryParse(value) != null;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes dimensions by stripping whitespace.
|
||||
*/
|
||||
public static Map<String, String> normalize(Map<String, String> dimensions) {
|
||||
if (dimensions == null)
|
||||
return null;
|
||||
Map<String, String> result = new HashMap<>();
|
||||
for (Map.Entry<String, String> dimension : dimensions.entrySet()) {
|
||||
String dimensionKey = null;
|
||||
if (dimension.getKey() != null) {
|
||||
dimensionKey = CharMatcher.WHITESPACE.trimFrom(dimension.getKey());
|
||||
if (dimensionKey.isEmpty())
|
||||
dimensionKey = null;
|
||||
}
|
||||
String dimensionValue = null;
|
||||
if (dimension.getValue() != null) {
|
||||
dimensionValue = CharMatcher.WHITESPACE.trimFrom(dimension.getValue());
|
||||
if (dimensionValue.isEmpty())
|
||||
dimensionValue = null;
|
||||
}
|
||||
result.put(dimensionKey, dimensionValue);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that the given {@code dimensions} are valid.
|
||||
*
|
||||
* @throws WebApplicationException if validation fails
|
||||
*/
|
||||
public static void validate(Map<String, String> dimensions, @Nullable String service) {
|
||||
// Validate dimension names and values
|
||||
for (Map.Entry<String, String> dimension : dimensions.entrySet()) {
|
||||
String name = dimension.getKey();
|
||||
String value = dimension.getValue();
|
||||
|
||||
// General validations
|
||||
if (Strings.isNullOrEmpty(name))
|
||||
throw Exceptions.unprocessableEntity("Dimension name cannot be empty");
|
||||
if (Strings.isNullOrEmpty(value))
|
||||
throw Exceptions.unprocessableEntity("Dimension %s cannot have an empty value", name);
|
||||
if (name.length() > 255)
|
||||
throw Exceptions.unprocessableEntity("Dimension name %s must be 255 characters or less",
|
||||
name);
|
||||
if (value.length() > 255)
|
||||
throw Exceptions.unprocessableEntity("Dimension value %s must be 255 characters or less",
|
||||
value);
|
||||
// Dimension names that start with underscores are reserved for internal use only.
|
||||
if (name.startsWith("_")) {
|
||||
throw Exceptions.unprocessableEntity("Dimension name cannot start with underscore (_)",
|
||||
name);
|
||||
}
|
||||
if (!VALID_DIMENSION_NAME.matcher(name).matches())
|
||||
throw Exceptions.unprocessableEntity(
|
||||
"Dimension name %s may not contain: %s", name, INVALID_CHAR_STRING);
|
||||
|
||||
// Service specific validations
|
||||
if (service != null) {
|
||||
if (!name.equals(Services.SERVICE_DIMENSION)
|
||||
&& !Services.isValidDimensionName(service, name))
|
||||
throw Exceptions.unprocessableEntity("%s is not a valid dimension name for service %s",
|
||||
name, service);
|
||||
DimensionValidator validator = VALIDATORS.get(service);
|
||||
if (validator != null && !validator.isValidDimension(name, value))
|
||||
throw Exceptions.unprocessableEntity("%s is not a valid dimension value for service %s",
|
||||
value, service);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a list of dimension names
|
||||
* @param names
|
||||
*/
|
||||
|
||||
public static void validateNames(List<String> names) {
|
||||
if(names != null) {
|
||||
for (String name : names) {
|
||||
if (Strings.isNullOrEmpty(name)) {
|
||||
throw Exceptions.unprocessableEntity("Dimension name cannot be empty");
|
||||
}
|
||||
if (name.length() > 255) {
|
||||
throw Exceptions.unprocessableEntity("Dimension name '%s' must be 255 characters or less",
|
||||
name);
|
||||
}
|
||||
// Dimension names that start with underscores are reserved for internal use only.
|
||||
if (name.startsWith("_")) {
|
||||
throw Exceptions.unprocessableEntity("Dimension name '%s' cannot start with underscore (_)",
|
||||
name);
|
||||
}
|
||||
if (!VALID_DIMENSION_NAME.matcher(name).matches())
|
||||
throw Exceptions.unprocessableEntity(
|
||||
"Dimension name '%s' may not contain: %s", name, INVALID_CHAR_STRING);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.app.validation;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.base.CharMatcher;
|
||||
import com.google.common.base.Strings;
|
||||
import monasca.common.model.Services;
|
||||
import monasca.api.app.command.CreateMetricCommand;
|
||||
import monasca.api.resource.exception.Exceptions;
|
||||
import com.sun.jersey.spi.container.WebApplication;
|
||||
|
||||
/**
|
||||
* Utilities for validating metric names.
|
||||
*/
|
||||
public class MetricNameValidation {
|
||||
private static final Pattern VALID_METRIC_NAME = Pattern.compile("[^><={}(), '\";&]+$");
|
||||
|
||||
private MetricNameValidation() {}
|
||||
|
||||
/**
|
||||
* Normalizes the {@code metricName} by removing whitespace.
|
||||
*/
|
||||
public static String normalize(String metricName) {
|
||||
return metricName == null ? null : CharMatcher.WHITESPACE.trimFrom(metricName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the {@code metricName} for the character constraints.
|
||||
*
|
||||
* @throws WebApplication if validation fails
|
||||
*/
|
||||
public static void validate(String metricName, @Nullable String service, boolean nameRequiredFlag) {
|
||||
|
||||
// General validations
|
||||
|
||||
if (Strings.isNullOrEmpty(metricName)) {
|
||||
if (nameRequiredFlag) {
|
||||
throw Exceptions.unprocessableEntity("Metric name is required");
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (metricName.length() > CreateMetricCommand.MAX_NAME_LENGTH)
|
||||
throw Exceptions.unprocessableEntity("Metric name %s must be %d characters or less",
|
||||
metricName, CreateMetricCommand.MAX_NAME_LENGTH);
|
||||
if (!Services.isReserved(metricName) && !VALID_METRIC_NAME.matcher(metricName).matches())
|
||||
throw Exceptions.unprocessableEntity("Metric name %s may not contain: > < = { } ( ) ' \" , ; &",
|
||||
metricName);
|
||||
|
||||
// Service specific validations
|
||||
if (service != null && Services.isReserved(service)) {
|
||||
if (!Strings.isNullOrEmpty(metricName) && !Services.isValidMetricName(service, metricName)) {
|
||||
throw Exceptions.unprocessableEntity("%s is not a valid metric name for namespace %s",
|
||||
metricName, service);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,167 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.app.validation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.joda.time.format.ISODateTimeFormat;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Iterables;
|
||||
import monasca.common.model.Services;
|
||||
import monasca.api.resource.exception.Exceptions;
|
||||
|
||||
/**
|
||||
* Validation related utilities.
|
||||
*/
|
||||
public final class Validation {
|
||||
private static final Splitter COMMA_SPLITTER = Splitter.on(',').omitEmptyStrings().trimResults();
|
||||
private static final Splitter COLON_SPLITTER = Splitter.on(':').omitEmptyStrings().trimResults().limit(2);
|
||||
private static final DateTimeFormatter ISO_8601_FORMATTER = ISODateTimeFormat
|
||||
.dateOptionalTimeParser().withZoneUTC();
|
||||
private static final List<String> VALID_STATISTICS = Arrays.asList("avg", "min", "max", "sum",
|
||||
"count");
|
||||
private static final List<String> VALID_ALARM_STATE = Arrays
|
||||
.asList("undetermined", "ok", "alarm");
|
||||
|
||||
private Validation() {}
|
||||
|
||||
/**
|
||||
* @throws JsonMappingException if the {@code value} is not valid for the {@code type}
|
||||
*/
|
||||
public static <T extends Enum<T>> T parseAndValidate(Class<T> type, String value)
|
||||
throws JsonMappingException {
|
||||
for (T constant : type.getEnumConstants())
|
||||
if (constant.name().equalsIgnoreCase(value))
|
||||
return constant;
|
||||
List<String> acceptedValues = new ArrayList<>();
|
||||
for (T constant : type.getEnumConstants())
|
||||
acceptedValues.add(constant.name());
|
||||
throw new JsonMappingException(String.format("%s was not one of %s", value, acceptedValues));
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws WebApplicationException if the {@code date} invalid or is required and null.
|
||||
*/
|
||||
public static DateTime parseAndValidateDate(String date, String parameterName, boolean required) {
|
||||
if (Strings.isNullOrEmpty(date)) {
|
||||
if (required)
|
||||
throw Exceptions.unprocessableEntity("%s is required", parameterName);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return ISO_8601_FORMATTER.parseDateTime(date);
|
||||
} catch (Exception e) {
|
||||
throw Exceptions.unprocessableEntity("%s must be an ISO 8601 formatted time", parameterName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws WebApplicationException if the {@code value} is null or empty.
|
||||
*/
|
||||
public static Map<String, String> parseAndValidateNameAndDimensions(String name,
|
||||
String dimensionsStr,
|
||||
boolean nameRequiredFlag) {
|
||||
Map<String, String> dimensions = parseAndValidateDimensions(dimensionsStr);
|
||||
|
||||
String service = dimensions.get(Services.SERVICE_DIMENSION);
|
||||
MetricNameValidation.validate(name, service, nameRequiredFlag);
|
||||
return dimensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws WebApplicationException if the {@code value} is null or empty.
|
||||
*/
|
||||
public static Map<String, String> parseAndValidateDimensions(String dimensionsStr) {
|
||||
Validation.validateNotNullOrEmpty(dimensionsStr, "dimensions");
|
||||
|
||||
Map<String, String> dimensions = new HashMap<String, String>();
|
||||
for (String dimensionStr : COMMA_SPLITTER.split(dimensionsStr)) {
|
||||
String[] dimensionArr = Iterables.toArray(COLON_SPLITTER.split(dimensionStr), String.class);
|
||||
if (dimensionArr.length == 2)
|
||||
dimensions.put(dimensionArr[0], dimensionArr[1]);
|
||||
}
|
||||
|
||||
String service = dimensions.get(Services.SERVICE_DIMENSION);
|
||||
DimensionValidation.validate(dimensions, service);
|
||||
return dimensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws WebApplicationException if the {@code number} is invalid.
|
||||
*/
|
||||
public static int parseAndValidateNumber(String number, String parameterName) {
|
||||
try {
|
||||
return Integer.parseInt(number);
|
||||
} catch (NumberFormatException e) {
|
||||
throw Exceptions.unprocessableEntity("%s must be valid number", parameterName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws WebApplicationException if the {@code statistics} empty or invalid.
|
||||
*/
|
||||
public static List<String> parseValidateAndNormalizeStatistics(Iterable<String> statistics) {
|
||||
List<String> validStats = new ArrayList<String>(5);
|
||||
for (String statistic : statistics) {
|
||||
String statisticLower = statistic.toLowerCase();
|
||||
if (!VALID_STATISTICS.contains(statisticLower))
|
||||
throw Exceptions.unprocessableEntity("%s is not a valid statistic", statistic);
|
||||
validStats.add(statisticLower);
|
||||
}
|
||||
|
||||
if (validStats.isEmpty())
|
||||
throw Exceptions.unprocessableEntity("Statistics are required");
|
||||
|
||||
return validStats;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws WebApplicationException if the {@code statistics} empty or invalid.
|
||||
*/
|
||||
public static void validateAlarmState(String state) {
|
||||
String stateLower = state.toLowerCase();
|
||||
if (!VALID_ALARM_STATE.contains(stateLower)) {
|
||||
throw Exceptions.unprocessableEntity("%s is not a valid state", state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws WebApplicationException if the {@code value} is null or empty.
|
||||
*/
|
||||
public static void validateNotNullOrEmpty(String value, String parameterName) {
|
||||
if (Strings.isNullOrEmpty(value))
|
||||
throw Exceptions.unprocessableEntity("%s is required", parameterName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws WebApplicationException if the {@code startTime} or {@code endTime} are invalid
|
||||
*/
|
||||
public static void validateTimes(DateTime startTime, DateTime endTime) {
|
||||
if (!startTime.isBefore(endTime))
|
||||
throw Exceptions.badRequest("start_time must be before end_time");
|
||||
}
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.app.validation;
|
||||
|
||||
import com.google.common.base.CharMatcher;
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import monasca.api.resource.exception.Exceptions;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
|
||||
/**
|
||||
* Utilities for validating valueMeta.
|
||||
*/
|
||||
public final class ValueMetaValidation {
|
||||
private static final int VALUE_META_MAX_NUMBER = 16;
|
||||
private static final int VALUE_META_VALUE_MAX_LENGTH = 2048;
|
||||
private static final int VALUE_META_NAME_MAX_LENGTH = 255;
|
||||
private static final Map<String, String> EMPTY_VALUE_META = Collections
|
||||
.unmodifiableMap(new HashMap<String, String>());
|
||||
|
||||
private ValueMetaValidation() {}
|
||||
|
||||
/**
|
||||
* Normalizes valueMeta by stripping whitespace from name. validate() must
|
||||
* already have been called on the valueMeta
|
||||
*/
|
||||
public static Map<String, String> normalize(Map<String, String> valueMeta) {
|
||||
if (valueMeta == null || valueMeta.isEmpty()) {
|
||||
return EMPTY_VALUE_META;
|
||||
}
|
||||
final Map<String, String> result = new HashMap<>();
|
||||
for (Map.Entry<String, String> entry : valueMeta.entrySet()) {
|
||||
final String key = CharMatcher.WHITESPACE.trimFrom(entry.getKey());
|
||||
result.put(key, entry.getValue());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that the given {@code valueMetas} are valid.
|
||||
*
|
||||
* @throws WebApplicationException if validation fails
|
||||
*/
|
||||
public static void validate(Map<String, String> valueMetas) {
|
||||
if (valueMetas.size() > VALUE_META_MAX_NUMBER) {
|
||||
throw Exceptions.unprocessableEntity("Maximum number of valueMeta key/value parirs is %d",
|
||||
VALUE_META_MAX_NUMBER);
|
||||
}
|
||||
|
||||
// Validate valueMeta names and values
|
||||
for (Map.Entry<String, String> valueMeta : valueMetas.entrySet()) {
|
||||
// Have to check for null first because later check is for trimmed name
|
||||
if (valueMeta.getKey() == null) {
|
||||
throw Exceptions.unprocessableEntity("valueMeta name cannot be empty");
|
||||
}
|
||||
final String name = CharMatcher.WHITESPACE.trimFrom(valueMeta.getKey());
|
||||
String value = valueMeta.getValue();
|
||||
if (value == null) {
|
||||
// Store nulls as empty strings
|
||||
value = "";
|
||||
}
|
||||
|
||||
// General validations
|
||||
if (Strings.isNullOrEmpty(name)) {
|
||||
throw Exceptions.unprocessableEntity("valueMeta name cannot be empty");
|
||||
}
|
||||
if (name.length() > VALUE_META_NAME_MAX_LENGTH) {
|
||||
throw Exceptions.unprocessableEntity("valueMeta name %s must be %d characters or less",
|
||||
name, VALUE_META_NAME_MAX_LENGTH);
|
||||
}
|
||||
if (value.length() > VALUE_META_VALUE_MAX_LENGTH) {
|
||||
throw Exceptions.unprocessableEntity("valueMeta value %s must be %d characters or less",
|
||||
value, VALUE_META_VALUE_MAX_LENGTH);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import monasca.api.domain.model.version.VersionRepo;
|
||||
import monasca.api.domain.service.impl.VersionRepoImpl;
|
||||
|
||||
/**
|
||||
* Domain layer bindings.
|
||||
*/
|
||||
public class DomainModule extends AbstractModule {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(VersionRepo.class).to(VersionRepoImpl.class).in(Singleton.class);
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.exception;
|
||||
|
||||
/**
|
||||
* Indicates that a domain entity already exists.
|
||||
*/
|
||||
public class EntityExistsException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public EntityExistsException(Exception ex, String msg) {
|
||||
super(msg, ex);
|
||||
}
|
||||
|
||||
public EntityExistsException(Exception ex, String msg, Object... args) {
|
||||
super(String.format(msg, args), ex);
|
||||
}
|
||||
|
||||
public EntityExistsException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public EntityExistsException(String msg, Object... args) {
|
||||
super(String.format(msg, args));
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.exception;
|
||||
|
||||
/**
|
||||
* Indicates that a domain entity is unknown.
|
||||
*/
|
||||
public class EntityNotFoundException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public EntityNotFoundException(Exception ex, String msg) {
|
||||
super(msg, ex);
|
||||
}
|
||||
|
||||
public EntityNotFoundException(Exception ex, String msg, Object... args) {
|
||||
super(String.format(msg, args), ex);
|
||||
}
|
||||
|
||||
public EntityNotFoundException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public EntityNotFoundException(String msg, Object... args) {
|
||||
super(String.format(msg, args));
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.exception;
|
||||
|
||||
/**
|
||||
* Indicates that an entity is invalid.
|
||||
*/
|
||||
public class InvalidEntityException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public InvalidEntityException(Exception ex, String msg) {
|
||||
super(msg, ex);
|
||||
}
|
||||
|
||||
public InvalidEntityException(Exception ex, String msg, Object... args) {
|
||||
super(String.format(msg, args), ex);
|
||||
}
|
||||
|
||||
public InvalidEntityException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public InvalidEntityException(String msg, Object... args) {
|
||||
super(String.format(msg, args));
|
||||
}
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.exception;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class MultipleMetricsException extends Exception {
|
||||
|
||||
private String metricName;
|
||||
private Map<String, String> dimensions;
|
||||
|
||||
public MultipleMetricsException() {
|
||||
super();
|
||||
init(null, null);
|
||||
}
|
||||
|
||||
public MultipleMetricsException(String metricName, Map<String, String> dimensions) {
|
||||
super();
|
||||
init(metricName, dimensions);
|
||||
}
|
||||
|
||||
public MultipleMetricsException(String metricName, Map<String, String> dimensions,
|
||||
String message) {
|
||||
super(message);
|
||||
init(metricName, dimensions);
|
||||
}
|
||||
|
||||
public MultipleMetricsException(String metricName, Map<String, String> dimensions,
|
||||
String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
init(metricName, dimensions);
|
||||
}
|
||||
|
||||
public MultipleMetricsException(String metricName, Map<String, String> dimensions,
|
||||
Throwable cause) {
|
||||
super(cause);
|
||||
init(metricName, dimensions);
|
||||
}
|
||||
|
||||
public MultipleMetricsException(String metricName, Map<String, String> dimensions,
|
||||
String message, Throwable cause, boolean enableSuppression,
|
||||
boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
init(metricName, dimensions);
|
||||
|
||||
}
|
||||
|
||||
private void init(String metricName, Map<String, String> dimensions) {
|
||||
this.metricName = metricName == null ? "" : metricName;
|
||||
this.dimensions = dimensions == null ? new HashMap<String, String>() : dimensions;
|
||||
}
|
||||
|
||||
public String getMetricName() {
|
||||
return metricName;
|
||||
}
|
||||
|
||||
public Map<String, String> getDimensions() {
|
||||
return dimensions;
|
||||
}
|
||||
}
|
@ -1,236 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.model.alarm;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
import monasca.common.model.alarm.AlarmState;
|
||||
import monasca.common.model.metric.MetricDefinition;
|
||||
import monasca.common.model.domain.common.AbstractEntity;
|
||||
import monasca.api.domain.model.common.Link;
|
||||
import monasca.api.domain.model.common.Linked;
|
||||
|
||||
@XmlRootElement(name = "Alarm")
|
||||
public class Alarm extends AbstractEntity implements Linked {
|
||||
private List<Link> links;
|
||||
private List<MetricDefinition> metrics;
|
||||
private AlarmState state;
|
||||
private AlarmDefinitionShort alarmDefinition;
|
||||
private DateTime stateUpdatedTimestamp;
|
||||
private DateTime createdTimestamp;
|
||||
|
||||
public Alarm() {}
|
||||
|
||||
public Alarm(String id, String alarmDefinitionId, String alarmDefinitionName,
|
||||
String alarmDefinitionSeverity, List<MetricDefinition> metrics, AlarmState state, DateTime stateUpdatedTimestamp, DateTime createdAt) {
|
||||
this.id = id;
|
||||
setMetrics(metrics);
|
||||
setState(state);
|
||||
setStateUpdatedTimestamp(stateUpdatedTimestamp);
|
||||
setCreatedTimestamp(createdAt);
|
||||
this.alarmDefinition = new AlarmDefinitionShort(alarmDefinitionId, alarmDefinitionName, alarmDefinitionSeverity);
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public List<Link> getLinks() {
|
||||
return links;
|
||||
}
|
||||
|
||||
public AlarmState getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public DateTime getStateUpdatedTimestamp() { return stateUpdatedTimestamp; }
|
||||
|
||||
public DateTime getCreatedTimestamp() { return createdTimestamp; }
|
||||
|
||||
@XmlElement(name = "id")
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLinks(List<Link> links) {
|
||||
this.links = links;
|
||||
}
|
||||
|
||||
public void setState(AlarmState state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public void setStateUpdatedTimestamp(DateTime stateUpdatedTimestamp) {
|
||||
this.stateUpdatedTimestamp = stateUpdatedTimestamp;
|
||||
}
|
||||
|
||||
public void setCreatedTimestamp(DateTime createdTimestamp) {
|
||||
this.createdTimestamp = createdTimestamp;
|
||||
}
|
||||
|
||||
public List<MetricDefinition> getMetrics() {
|
||||
return metrics;
|
||||
}
|
||||
|
||||
public void setMetrics(List<MetricDefinition> metrics) {
|
||||
this.metrics = metrics;
|
||||
}
|
||||
|
||||
public AlarmDefinitionShort getAlarmDefinition() {
|
||||
return alarmDefinition;
|
||||
}
|
||||
|
||||
public void setAlarmDefinition(AlarmDefinitionShort alarmDefinition) {
|
||||
this.alarmDefinition = alarmDefinition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + ((alarmDefinition == null) ? 0 : alarmDefinition.hashCode());
|
||||
result = prime * result + ((links == null) ? 0 : links.hashCode());
|
||||
result = prime * result + ((metrics == null) ? 0 : metrics.hashCode());
|
||||
result = prime * result + ((state == null) ? 0 : state.hashCode());
|
||||
result = prime * result + ((stateUpdatedTimestamp == null) ? 0 : stateUpdatedTimestamp.hashCode());
|
||||
result = prime * result + ((createdTimestamp == null) ? 0 : createdTimestamp.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (!super.equals(obj))
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Alarm other = (Alarm) obj;
|
||||
if (alarmDefinition == null) {
|
||||
if (other.alarmDefinition != null)
|
||||
return false;
|
||||
} else if (!alarmDefinition.equals(other.alarmDefinition))
|
||||
return false;
|
||||
if (links == null) {
|
||||
if (other.links != null)
|
||||
return false;
|
||||
} else if (!links.equals(other.links))
|
||||
return false;
|
||||
if (metrics == null) {
|
||||
if (other.metrics != null)
|
||||
return false;
|
||||
} else if (!metrics.equals(other.metrics))
|
||||
return false;
|
||||
if (state != other.state)
|
||||
return false;
|
||||
// Ignore timezones, only check milliseconds since epoch
|
||||
if (stateUpdatedTimestamp.getMillis() != other.stateUpdatedTimestamp.getMillis()) {
|
||||
return false;
|
||||
}
|
||||
if (createdTimestamp.getMillis() != other.createdTimestamp.getMillis()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class holds the parts of AlarmDefinition that are returned through the API with
|
||||
* an Alarm
|
||||
* @author craigbr
|
||||
*
|
||||
*/
|
||||
public static class AlarmDefinitionShort extends AbstractEntity implements Linked {
|
||||
private String name;
|
||||
private String severity;
|
||||
private List<Link> links;
|
||||
|
||||
public AlarmDefinitionShort() {
|
||||
}
|
||||
|
||||
public AlarmDefinitionShort(String id, String name, String severity) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.severity = severity;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getSeverity() {
|
||||
return severity;
|
||||
}
|
||||
|
||||
public void setSeverity(String severity) {
|
||||
this.severity = severity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Link> getLinks() {
|
||||
return links;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLinks(List<Link> links) {
|
||||
this.links = links;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + ((links == null) ? 0 : links.hashCode());
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
result = prime * result + ((severity == null) ? 0 : severity.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (!super.equals(obj))
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
AlarmDefinitionShort other = (AlarmDefinitionShort) obj;
|
||||
if (links == null) {
|
||||
if (other.links != null)
|
||||
return false;
|
||||
} else if (!links.equals(other.links))
|
||||
return false;
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!name.equals(other.name))
|
||||
return false;
|
||||
if (severity == null) {
|
||||
if (other.severity != null)
|
||||
return false;
|
||||
} else if (!severity.equals(other.severity))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.model.alarm;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import monasca.common.model.alarm.AlarmState;
|
||||
import monasca.common.model.alarm.AlarmSubExpression;
|
||||
import monasca.api.domain.exception.EntityNotFoundException;
|
||||
|
||||
public interface AlarmRepo {
|
||||
/**
|
||||
* Deletes all alarms associated with the {@code id}.
|
||||
*/
|
||||
void deleteById(String tenantId, String id);
|
||||
|
||||
/**
|
||||
* Returns alarms for the given criteria.
|
||||
*/
|
||||
List<Alarm> find(String tenantId, String alarmDefId, String metricName, Map<String,
|
||||
String> metricDimensions, AlarmState state, DateTime stateUpdatedStart, String offset, int limit, boolean enforceLimit);
|
||||
|
||||
/**
|
||||
* @throws EntityNotFoundException if an alarm cannot be found for the {@code id}
|
||||
*/
|
||||
Alarm findById(String tenantId, String id);
|
||||
|
||||
/**
|
||||
* Updates the state and returns the original alarm for the {@code id}.
|
||||
* @return the original alarm before any state change
|
||||
*/
|
||||
Alarm update(String tenantId, String id, AlarmState state);
|
||||
|
||||
/**
|
||||
* Gets the AlarmSubExpressions mapped by their Ids for an Alarm Id
|
||||
*/
|
||||
Map<String, AlarmSubExpression> findAlarmSubExpressions(String alarmId);
|
||||
|
||||
/**
|
||||
* Gets the AlarmSubExpressions mapped by their Ids then mapped by alarm id for an
|
||||
* Alarm Definition Id
|
||||
*/
|
||||
Map<String, Map<String, AlarmSubExpression>> findAlarmSubExpressionsForAlarmDefinition(String alarmDefinitionId);
|
||||
}
|
@ -1,246 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.model.alarmdefinition;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
import monasca.api.domain.model.common.Link;
|
||||
import monasca.api.domain.model.common.Linked;
|
||||
import monasca.common.model.alarm.AlarmExpression;
|
||||
import monasca.common.model.domain.common.AbstractEntity;
|
||||
|
||||
@XmlRootElement(name = "Alarm definition")
|
||||
public class AlarmDefinition extends AbstractEntity implements Linked {
|
||||
private List<Link> links;
|
||||
private String name;
|
||||
private String description = "";
|
||||
private String expression;
|
||||
private Object expressionData;
|
||||
private List<String> matchBy;
|
||||
private String severity;
|
||||
private boolean actionsEnabled;
|
||||
private List<String> alarmActions;
|
||||
private List<String> okActions;
|
||||
private List<String> undeterminedActions;
|
||||
|
||||
public AlarmDefinition() {}
|
||||
|
||||
public AlarmDefinition(String id, String name, String description, String severity,
|
||||
String expression, List<String> matchBy, boolean actionsEnabled, List<String> alarmActions,
|
||||
List<String> okActions, List<String> undeterminedActions) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
setDescription(description);
|
||||
setSeverity(severity);
|
||||
setExpression(expression);
|
||||
setMatchBy(matchBy);
|
||||
setActionsEnabled(actionsEnabled);
|
||||
setAlarmActions(alarmActions);
|
||||
setOkActions(okActions);
|
||||
setUndeterminedActions(undeterminedActions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (!super.equals(obj))
|
||||
return false;
|
||||
if (!(obj instanceof AlarmDefinition))
|
||||
return false;
|
||||
AlarmDefinition other = (AlarmDefinition) obj;
|
||||
if (actionsEnabled != other.actionsEnabled)
|
||||
return false;
|
||||
if (alarmActions == null) {
|
||||
if (other.alarmActions != null)
|
||||
return false;
|
||||
} else if (!alarmActions.equals(other.alarmActions))
|
||||
return false;
|
||||
if (description == null) {
|
||||
if (other.description != null)
|
||||
return false;
|
||||
} else if (!description.equals(other.description))
|
||||
return false;
|
||||
if (expression == null) {
|
||||
if (other.expression != null)
|
||||
return false;
|
||||
} else if (!expression.equals(other.expression))
|
||||
return false;
|
||||
if (expressionData == null) {
|
||||
if (other.expressionData != null)
|
||||
return false;
|
||||
} else if (!expressionData.equals(other.expressionData))
|
||||
return false;
|
||||
if (links == null) {
|
||||
if (other.links != null)
|
||||
return false;
|
||||
} else if (!links.equals(other.links))
|
||||
return false;
|
||||
if (matchBy == null) {
|
||||
if (other.matchBy != null)
|
||||
return false;
|
||||
} else if (!matchBy.equals(other.matchBy))
|
||||
return false;
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!name.equals(other.name))
|
||||
return false;
|
||||
if (okActions == null) {
|
||||
if (other.okActions != null)
|
||||
return false;
|
||||
} else if (!okActions.equals(other.okActions))
|
||||
return false;
|
||||
if (severity == null) {
|
||||
if (other.severity != null)
|
||||
return false;
|
||||
} else if (!severity.equals(other.severity))
|
||||
return false;
|
||||
if (undeterminedActions == null) {
|
||||
if (other.undeterminedActions != null)
|
||||
return false;
|
||||
} else if (!undeterminedActions.equals(other.undeterminedActions))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public List<String> getAlarmActions() {
|
||||
return alarmActions;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public String getExpression() {
|
||||
return expression;
|
||||
}
|
||||
|
||||
public Object getExpressionData() {
|
||||
return expressionData;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public List<Link> getLinks() {
|
||||
return links;
|
||||
}
|
||||
|
||||
public List<String> getMatchBy() {
|
||||
return matchBy;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<String> getOkActions() {
|
||||
return okActions;
|
||||
}
|
||||
|
||||
public String getSeverity() {
|
||||
return severity;
|
||||
}
|
||||
|
||||
public List<String> getUndeterminedActions() {
|
||||
return undeterminedActions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + (actionsEnabled ? 1231 : 1237);
|
||||
result = prime * result + ((alarmActions == null) ? 0 : alarmActions.hashCode());
|
||||
result = prime * result + ((description == null) ? 0 : description.hashCode());
|
||||
result = prime * result + ((expression == null) ? 0 : expression.hashCode());
|
||||
result = prime * result + ((expressionData == null) ? 0 : expressionData.hashCode());
|
||||
result = prime * result + ((links == null) ? 0 : links.hashCode());
|
||||
result = prime * result + ((matchBy == null) ? 0 : matchBy.hashCode());
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
result = prime * result + ((okActions == null) ? 0 : okActions.hashCode());
|
||||
result = prime * result + ((severity == null) ? 0 : severity.hashCode());
|
||||
result = prime * result + ((undeterminedActions == null) ? 0 : undeterminedActions.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean isActionsEnabled() {
|
||||
return actionsEnabled;
|
||||
}
|
||||
|
||||
public void setActionsEnabled(boolean actionsEnabled) {
|
||||
this.actionsEnabled = actionsEnabled;
|
||||
}
|
||||
|
||||
public void setAlarmActions(List<String> alarmActions) {
|
||||
this.alarmActions = alarmActions;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description == null ? "" : description;
|
||||
}
|
||||
|
||||
public void setExpression(String expression) {
|
||||
this.expression = expression;
|
||||
setExpressionData(AlarmExpression.of(expression).getExpressionTree());
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public void setExpressionData(Object expressionData) {
|
||||
this.expressionData = expressionData;
|
||||
}
|
||||
|
||||
@XmlElement(name = "id")
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLinks(List<Link> links) {
|
||||
this.links = links;
|
||||
}
|
||||
|
||||
public void setMatchBy(List<String> matchBy) {
|
||||
this.matchBy = matchBy == null ? Collections.<String>emptyList() : matchBy;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setOkActions(List<String> okActions) {
|
||||
this.okActions = okActions;
|
||||
}
|
||||
|
||||
public void setSeverity(String severity) {
|
||||
this.severity = severity;
|
||||
}
|
||||
|
||||
public void setUndeterminedActions(List<String> undeterminedActions) {
|
||||
this.undeterminedActions = undeterminedActions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("AlarmDefinition [name=%s]", name);
|
||||
}
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.model.alarmdefinition;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import monasca.common.model.alarm.AlarmSubExpression;
|
||||
import monasca.common.model.metric.MetricDefinition;
|
||||
import monasca.api.domain.exception.EntityNotFoundException;
|
||||
|
||||
/**
|
||||
* Repository for alarm definitions.
|
||||
*/
|
||||
public interface AlarmDefinitionRepo {
|
||||
/**
|
||||
* Creates and returns a new alarm definition for the criteria.
|
||||
*/
|
||||
AlarmDefinition create(String tenantId, String id, String name, String description,
|
||||
String severity, String expression, Map<String, AlarmSubExpression> subExpressions,
|
||||
List<String> matchBy, List<String> alarmActions, List<String> okActions,
|
||||
List<String> undeterminedActions);
|
||||
|
||||
/**
|
||||
* @throws EntityNotFoundException if an alarm definition cannot be found for the
|
||||
* {@code alarmDefId}
|
||||
*/
|
||||
void deleteById(String tenantId, String alarmDefId);
|
||||
|
||||
/**
|
||||
* Returns true if an alarm exists for the given criteria, else false.
|
||||
*/
|
||||
String exists(String tenantId, String name);
|
||||
|
||||
/**
|
||||
* Returns alarms for the given criteria.
|
||||
*/
|
||||
List<AlarmDefinition> find(String tenantId, String name, Map<String, String> dimensions,
|
||||
String offset, int limit);
|
||||
|
||||
/**
|
||||
* @throws EntityNotFoundException if an alarm cannot be found for the {@code alarmDefId}
|
||||
*/
|
||||
AlarmDefinition findById(String tenantId, String alarmDefId);
|
||||
|
||||
/**
|
||||
* Returns the sub-alarm Ids for the {@code alarmDefId}.
|
||||
*/
|
||||
Map<String, MetricDefinition> findSubAlarmMetricDefinitions(String alarmDefId);
|
||||
|
||||
/**
|
||||
* Returns the sub expressions for the {@code alarmDefId}.
|
||||
*/
|
||||
Map<String, AlarmSubExpression> findSubExpressions(String alarmDefId);
|
||||
|
||||
/**
|
||||
* Updates and returns an alarm definition for the criteria.
|
||||
*/
|
||||
void update(String tenantId, String id, boolean patch, String name, String description,
|
||||
String expression, List<String> matchBy, String severity, boolean actionsEnabled,
|
||||
Collection<String> oldSubAlarmIds, Map<String, AlarmSubExpression> changedSubAlarms,
|
||||
Map<String, AlarmSubExpression> newSubAlarms, List<String> alarmActions,
|
||||
List<String> okActions, List<String> undeterminedActions);
|
||||
}
|
@ -1,187 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.model.alarmstatehistory;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import monasca.common.model.alarm.AlarmTransitionSubAlarm;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import monasca.common.model.alarm.AlarmState;
|
||||
import monasca.common.model.domain.common.AbstractEntity;
|
||||
import monasca.common.model.metric.MetricDefinition;
|
||||
|
||||
public class AlarmStateHistory extends AbstractEntity {
|
||||
private String alarmId;
|
||||
private List<MetricDefinition> metrics;
|
||||
private AlarmState oldState;
|
||||
private AlarmState newState;
|
||||
private String reason;
|
||||
private String reasonData;
|
||||
private DateTime timestamp;
|
||||
private List<AlarmTransitionSubAlarm> subAlarms;
|
||||
|
||||
public AlarmStateHistory() {}
|
||||
|
||||
public AlarmStateHistory(String alarmId, List<MetricDefinition> metrics, AlarmState oldState,
|
||||
AlarmState newState, List<AlarmTransitionSubAlarm> subAlarms, String reason, String reasonData, DateTime timestamp) {
|
||||
id = new Long(timestamp.getMillis()).toString();
|
||||
this.alarmId = alarmId;
|
||||
this.setMetrics(metrics);
|
||||
this.oldState = oldState;
|
||||
this.newState = newState;
|
||||
this.subAlarms = subAlarms;
|
||||
this.reason = reason;
|
||||
this.reasonData = reasonData;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (!(obj instanceof AlarmStateHistory))
|
||||
return false;
|
||||
AlarmStateHistory other = (AlarmStateHistory) obj;
|
||||
if (alarmId == null) {
|
||||
if (other.alarmId != null)
|
||||
return false;
|
||||
} else if (!alarmId.equals(other.alarmId))
|
||||
return false;
|
||||
if (metrics == null) {
|
||||
if (other.metrics != null)
|
||||
return false;
|
||||
} else if (!metrics.equals(other.metrics))
|
||||
return false;
|
||||
if (newState != other.newState)
|
||||
return false;
|
||||
if (oldState != other.oldState)
|
||||
return false;
|
||||
if (subAlarms == null) {
|
||||
if (other.subAlarms != null)
|
||||
return false;
|
||||
} else if (!subAlarms.equals(other.subAlarms))
|
||||
return false;
|
||||
if (reason == null) {
|
||||
if (other.reason != null)
|
||||
return false;
|
||||
} else if (!reason.equals(other.reason))
|
||||
return false;
|
||||
if (reasonData == null) {
|
||||
if (other.reasonData != null)
|
||||
return false;
|
||||
} else if (!reasonData.equals(other.reasonData))
|
||||
return false;
|
||||
if (timestamp == null) {
|
||||
if (other.timestamp != null)
|
||||
return false;
|
||||
} else if (!timestamp.equals(other.timestamp))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getAlarmId() {
|
||||
return alarmId;
|
||||
}
|
||||
|
||||
public List<MetricDefinition> getMetrics() {
|
||||
return metrics;
|
||||
}
|
||||
|
||||
public AlarmState getNewState() {
|
||||
return newState;
|
||||
}
|
||||
|
||||
public AlarmState getOldState() {
|
||||
return oldState;
|
||||
}
|
||||
|
||||
public String getReason() {
|
||||
return reason;
|
||||
}
|
||||
|
||||
public String getReasonData() {
|
||||
return reasonData;
|
||||
}
|
||||
|
||||
public DateTime getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((alarmId == null) ? 0 : alarmId.hashCode());
|
||||
result = prime * result + ((metrics == null) ? 0 : metrics.hashCode());
|
||||
result = prime * result + ((newState == null) ? 0 : newState.hashCode());
|
||||
result = prime * result + ((oldState == null) ? 0 : oldState.hashCode());
|
||||
result = prime * result + ((subAlarms == null) ? 0 : subAlarms.hashCode());
|
||||
result = prime * result + ((reason == null) ? 0 : reason.hashCode());
|
||||
result = prime * result + ((reasonData == null) ? 0 : reasonData.hashCode());
|
||||
result = prime * result + ((timestamp == null) ? 0 : timestamp.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setAlarmId(String alarmId) {
|
||||
this.alarmId = alarmId;
|
||||
}
|
||||
|
||||
public void setMetrics(List<MetricDefinition> metrics) {
|
||||
this.metrics = metrics;
|
||||
}
|
||||
|
||||
public void setNewState(AlarmState newState) {
|
||||
this.newState = newState;
|
||||
}
|
||||
|
||||
public void setOldState(AlarmState oldState) {
|
||||
this.oldState = oldState;
|
||||
}
|
||||
|
||||
public void setReason(String reason) {
|
||||
this.reason = reason;
|
||||
}
|
||||
|
||||
public void setReasonData(String reasonData) {
|
||||
this.reasonData = reasonData;
|
||||
}
|
||||
|
||||
public List<AlarmTransitionSubAlarm> getSubAlarms() {
|
||||
return subAlarms;
|
||||
}
|
||||
|
||||
public void setSubAlarms(List<AlarmTransitionSubAlarm> subAlarms) {
|
||||
this.subAlarms = subAlarms;
|
||||
}
|
||||
|
||||
public void setTimestamp(DateTime timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
// Set the id in the AbstractEntity class.
|
||||
id = new Long(timestamp.getMillis()).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AlarmStateHistory [alarmId=" + alarmId + ", metrics=" + metrics + ", oldState="
|
||||
+ oldState + ", newState=" + newState + ", subAlarms=" + subAlarms + ", reason=" + reason + ", reasonData=" + reasonData
|
||||
+ ", timestamp=" + timestamp + "]";
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.model.alarmstatehistory;
|
||||
|
||||
import monasca.api.domain.exception.EntityNotFoundException;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Repository for alarm state history.
|
||||
*/
|
||||
public interface AlarmStateHistoryRepo {
|
||||
/**
|
||||
* @throws EntityNotFoundException if an alarm cannot be found for the {@code alarmId}
|
||||
*/
|
||||
List<AlarmStateHistory> findById(String tenantId, String alarmId, String offset, int limit) throws Exception;
|
||||
|
||||
/**
|
||||
* Finds AlarmStateHistory for the given criteria.
|
||||
*/
|
||||
List<AlarmStateHistory> find(String tenantId, Map<String, String> dimensions,
|
||||
DateTime startTime, @Nullable DateTime endTime, @Nullable String offset, int limit) throws Exception;
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.model.common;
|
||||
|
||||
public class Link {
|
||||
public String rel;
|
||||
|
||||
public String href;
|
||||
|
||||
public Link() {}
|
||||
|
||||
public Link(String rel, String href) {
|
||||
this.rel = rel;
|
||||
this.href = href;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Link other = (Link) obj;
|
||||
if (href == null) {
|
||||
if (other.href != null)
|
||||
return false;
|
||||
} else if (!href.equals(other.href))
|
||||
return false;
|
||||
if (rel == null) {
|
||||
if (other.rel != null)
|
||||
return false;
|
||||
} else if (!rel.equals(other.rel))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((href == null) ? 0 : href.hashCode());
|
||||
result = prime * result + ((rel == null) ? 0 : rel.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("Link [rel=%s, href=%s]", rel, href);
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.model.common;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Defines a type that can be described via a set of links.
|
||||
*/
|
||||
public interface Linked {
|
||||
List<Link> getLinks();
|
||||
|
||||
void setLinks(List<Link> links);
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.model.common;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Paged {
|
||||
|
||||
public static final int LIMIT = 10000;
|
||||
|
||||
public List<Link> links = new ArrayList<>();
|
||||
|
||||
public List<?> elements;
|
||||
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.model.measurement;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Repository for measurements.
|
||||
*/
|
||||
public interface MeasurementRepo {
|
||||
/**
|
||||
* Finds measurements for the given criteria.
|
||||
*/
|
||||
List<Measurements> find(String tenantId, String name, Map<String, String> dimensions,
|
||||
DateTime startTime, @Nullable DateTime endTime, @Nullable String offset,
|
||||
int limit, Boolean mergeMetricsFlag) throws Exception;
|
||||
}
|
@ -1,125 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.model.measurement;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import monasca.common.model.domain.common.AbstractEntity;
|
||||
|
||||
/**
|
||||
* Encapsulates a metric measurements.
|
||||
*/
|
||||
public class Measurements extends AbstractEntity {
|
||||
private static final String[] COLUMNS = new String[] {"timestamp", "value", "value_meta"};
|
||||
|
||||
private String name;
|
||||
private Map<String, String> dimensions;
|
||||
private final String[] columns = COLUMNS;
|
||||
private List<Object[]> measurements;
|
||||
|
||||
public Measurements() {}
|
||||
|
||||
public Measurements(String name, Map<String, String> dimensions, List<Object[]> measurements) {
|
||||
this.name = name;
|
||||
this.dimensions = dimensions;
|
||||
this.measurements = measurements;
|
||||
}
|
||||
|
||||
public Measurements(String name, Map<String, String> dimensions) {
|
||||
this.name = name;
|
||||
this.dimensions = dimensions;
|
||||
this.measurements = new LinkedList<>();
|
||||
}
|
||||
|
||||
public void addMeasurement(Object[] measurement) {
|
||||
measurements.add(measurement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Measurements other = (Measurements) obj;
|
||||
if (dimensions == null) {
|
||||
if (other.dimensions != null)
|
||||
return false;
|
||||
} else if (!dimensions.equals(other.dimensions))
|
||||
return false;
|
||||
if (measurements == null) {
|
||||
if (other.measurements != null)
|
||||
return false;
|
||||
} else if (!measurements.equals(other.measurements))
|
||||
return false;
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!name.equals(other.name))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public String[] getColumns() {
|
||||
return columns;
|
||||
}
|
||||
|
||||
public Map<String, String> getDimensions() {
|
||||
return dimensions;
|
||||
}
|
||||
|
||||
public List<Object[]> getMeasurements() {
|
||||
return measurements;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((dimensions == null) ? 0 : dimensions.hashCode());
|
||||
result = prime * result + ((measurements == null) ? 0 : measurements.hashCode());
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setDimensions(Map<String, String> dimensions) {
|
||||
this.dimensions = dimensions;
|
||||
}
|
||||
|
||||
public void setMeasurements(List<Object[]> measurements) {
|
||||
this.measurements = measurements;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("Measurement [name=%s, dimensions=%s, measurements=%s]", name, dimensions,
|
||||
measurements);
|
||||
}
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.model.metric;
|
||||
|
||||
import monasca.common.model.metric.MetricDefinition;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Repository for metrics.
|
||||
*/
|
||||
public interface MetricDefinitionRepo {
|
||||
|
||||
/**
|
||||
* Finds metrics for the given criteria.
|
||||
*/
|
||||
List<MetricDefinition> find(String tenantId, String name, Map<String, String> dimensions,
|
||||
String offset, int limit)
|
||||
throws Exception;
|
||||
|
||||
List<MetricName> findNames(String tenantId, Map<String, String> dimensions, String offset, int limit) throws Exception;
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.model.metric;
|
||||
|
||||
import monasca.common.model.domain.common.AbstractEntity;
|
||||
|
||||
public class MetricName extends AbstractEntity implements Comparable<MetricName> {
|
||||
|
||||
private String id;
|
||||
private String name;
|
||||
|
||||
public MetricName(String id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
MetricName other = (MetricName) obj;
|
||||
if (id == null) {
|
||||
if (other.id != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!id.equals(other.id)) {
|
||||
return false;
|
||||
}
|
||||
if (name == null) {
|
||||
if (other.name != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!name.equals(other.name)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getId() {return id;}
|
||||
|
||||
public String getName() {return name;}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((id == null) ? 0 : id.hashCode());
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setId(String id) {this.id = id;}
|
||||
|
||||
public void setName(String name) {this.name = name;}
|
||||
|
||||
@Override
|
||||
public int compareTo(MetricName other) {
|
||||
return this.name.compareTo(other.name);
|
||||
}
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.model.notificationmethod;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import monasca.common.model.domain.common.AbstractEntity;
|
||||
import monasca.api.domain.model.common.Link;
|
||||
import monasca.api.domain.model.common.Linked;
|
||||
|
||||
public class NotificationMethod extends AbstractEntity implements Linked {
|
||||
private List<Link> links;
|
||||
private String name;
|
||||
private NotificationMethodType type;
|
||||
private String address;
|
||||
|
||||
public NotificationMethod() {}
|
||||
|
||||
public NotificationMethod(String id, String name, NotificationMethodType type, String address) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (!super.equals(obj))
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
NotificationMethod other = (NotificationMethod) obj;
|
||||
if (address == null) {
|
||||
if (other.address != null)
|
||||
return false;
|
||||
} else if (!address.equals(other.address))
|
||||
return false;
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!name.equals(other.name))
|
||||
return false;
|
||||
if (type != other.type)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public List<Link> getLinks() {
|
||||
return links;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public NotificationMethodType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + ((address == null) ? 0 : address.hashCode());
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
result = prime * result + ((type == null) ? 0 : type.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public void setLinks(List<Link> links) {
|
||||
this.links = links;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setType(NotificationMethodType type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.model.notificationmethod;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import monasca.api.domain.exception.EntityNotFoundException;
|
||||
|
||||
/**
|
||||
* Repository for notification methods.
|
||||
*/
|
||||
public interface NotificationMethodRepo {
|
||||
NotificationMethod create(String tenantId, String name, NotificationMethodType type,
|
||||
String address);
|
||||
|
||||
/**
|
||||
* @throws EntityNotFoundException if a notification method cannot be found for the
|
||||
* {@code notificationMethodId}
|
||||
*/
|
||||
void deleteById(String tenantId, String notificationMethodId);
|
||||
|
||||
/** Returns whether the {@code notificationMethodId} exists for the {@code tenantId}. */
|
||||
boolean exists(String tenantId, String notificationMethodId);
|
||||
|
||||
/**
|
||||
* @throws EntityNotFoundException if a notification method cannot be found for the
|
||||
* {@code notificationMethodId}
|
||||
*/
|
||||
NotificationMethod findById(String tenantId, String notificationMethodId);
|
||||
|
||||
/**
|
||||
* @throws EntityNotFoundException if a notification method cannot be found for the
|
||||
* {@code notificationMethodId}
|
||||
*/
|
||||
NotificationMethod update(String tenantId, String notificationMethodId, String name,
|
||||
NotificationMethodType type, String address);
|
||||
|
||||
List<NotificationMethod> find(String tenantId, String offset, int limit);
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.model.notificationmethod;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
|
||||
public enum NotificationMethodType {
|
||||
EMAIL, WEBHOOK, PAGERDUTY;
|
||||
|
||||
@JsonCreator
|
||||
public static NotificationMethodType fromJson(String text) {
|
||||
return valueOf(text.toUpperCase());
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.model.statistic;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Repository for statistics.
|
||||
*/
|
||||
public interface StatisticRepo {
|
||||
|
||||
/**
|
||||
* Finds statistics for the given criteria.
|
||||
*/
|
||||
List<Statistics> find(String tenantId, String name, Map<String, String> dimensions,
|
||||
DateTime startTime, @Nullable DateTime endTime, List<String> statistics,
|
||||
int period, String offset, int limit, Boolean mergeMetricsFlag)
|
||||
throws Exception;
|
||||
}
|
@ -1,138 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.model.statistic;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import monasca.common.model.domain.common.AbstractEntity;
|
||||
|
||||
/**
|
||||
* Encapsulates a metric measurements.
|
||||
*/
|
||||
public class Statistics extends AbstractEntity {
|
||||
|
||||
private String name;
|
||||
private Map<String, String> dimensions;
|
||||
private List<String> columns;
|
||||
private List<List<Object>> statistics;
|
||||
|
||||
public Statistics() {
|
||||
statistics = new ArrayList<>();
|
||||
}
|
||||
|
||||
public Statistics(String name, Map<String, String> dimensions, List<String> columns) {
|
||||
this.name = name;
|
||||
this.dimensions = dimensions;
|
||||
this.columns = columns;
|
||||
this.statistics = new LinkedList<>();
|
||||
|
||||
}
|
||||
|
||||
public void addValues(List<Object> value) {
|
||||
statistics.add(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Statistics other = (Statistics) obj;
|
||||
if (dimensions == null) {
|
||||
if (other.dimensions != null)
|
||||
return false;
|
||||
} else if (!dimensions.equals(other.dimensions))
|
||||
return false;
|
||||
if (columns == null) {
|
||||
if (other.columns != null)
|
||||
return false;
|
||||
} else if (!columns.equals(other.columns))
|
||||
return false;
|
||||
if (statistics == null) {
|
||||
if (other.statistics != null)
|
||||
return false;
|
||||
} else if (!statistics.equals(other.statistics))
|
||||
return false;
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!name.equals(other.name))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public void addStatistics(List<Object> statistics) {
|
||||
this.statistics.add(statistics);
|
||||
}
|
||||
|
||||
public List<String> getColumns() {
|
||||
return columns;
|
||||
}
|
||||
|
||||
public Map<String, String> getDimensions() {
|
||||
return dimensions;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<List<Object>> getStatistics() {
|
||||
return statistics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((dimensions == null) ? 0 : dimensions.hashCode());
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
result = prime * result + ((statistics == null) ? 0 : statistics.hashCode());
|
||||
result = prime * result + ((columns == null) ? 0 : columns.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setColumns(List<String> columns) {
|
||||
this.columns = columns;
|
||||
}
|
||||
|
||||
public void setDimensions(Map<String, String> dimensions) {
|
||||
this.dimensions = dimensions;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setStatistics(List<List<Object>> statistics) {
|
||||
this.statistics = statistics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("Statistics [name=%s, dimensions=%s,statistics=%s]", name, dimensions,
|
||||
statistics);
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.model.version;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import monasca.common.model.domain.common.AbstractEntity;
|
||||
import monasca.api.domain.model.common.Link;
|
||||
import monasca.api.domain.model.common.Linked;
|
||||
|
||||
public class Version extends AbstractEntity implements Linked {
|
||||
private List<Link> links;
|
||||
public VersionStatus status;
|
||||
public DateTime updated;
|
||||
|
||||
public enum VersionStatus {
|
||||
CURRENT, DEPRECATED, OBSOLETE;
|
||||
}
|
||||
|
||||
public Version() {}
|
||||
|
||||
public Version(String id, VersionStatus status, DateTime updated) {
|
||||
this.id = id;
|
||||
this.status = status;
|
||||
this.updated = updated;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Link> getLinks() {
|
||||
return links;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLinks(List<Link> links) {
|
||||
this.links = links;
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.model.version;
|
||||
|
||||
import monasca.api.domain.exception.EntityNotFoundException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Repository for versions.
|
||||
*/
|
||||
public interface VersionRepo {
|
||||
List<Version> find();
|
||||
|
||||
/**
|
||||
* @throws EntityNotFoundException a version cannot be found for the {@code versionId}
|
||||
*/
|
||||
Version findById(String versionId);
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Houses the domain layer.
|
||||
*/
|
||||
package monasca.api.domain;
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.domain.service.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
|
||||
import monasca.api.domain.exception.EntityNotFoundException;
|
||||
import monasca.api.domain.model.version.Version;
|
||||
import monasca.api.domain.model.version.Version.VersionStatus;
|
||||
import monasca.api.domain.model.version.VersionRepo;
|
||||
|
||||
/**
|
||||
* Version repository implementation.
|
||||
*/
|
||||
public class VersionRepoImpl implements VersionRepo {
|
||||
private static final Version v2_0 = new Version("v2.0", VersionStatus.CURRENT, new DateTime(
|
||||
DateTimeZone.UTC));
|
||||
|
||||
@Override
|
||||
public List<Version> find() {
|
||||
return Arrays.asList(v2_0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Version findById(String versionId) {
|
||||
if ("v2.0".equals(versionId))
|
||||
return v2_0;
|
||||
throw new EntityNotFoundException("No version exists for %s", versionId);
|
||||
}
|
||||
}
|
@ -1,118 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.infrastructure;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.ProvisionException;
|
||||
|
||||
import org.influxdb.InfluxDB;
|
||||
import org.influxdb.InfluxDBFactory;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import monasca.api.ApiConfig;
|
||||
import monasca.api.domain.model.alarm.AlarmRepo;
|
||||
import monasca.api.domain.model.alarmdefinition.AlarmDefinitionRepo;
|
||||
import monasca.api.domain.model.alarmstatehistory.AlarmStateHistoryRepo;
|
||||
import monasca.api.domain.model.measurement.MeasurementRepo;
|
||||
import monasca.api.domain.model.metric.MetricDefinitionRepo;
|
||||
import monasca.api.domain.model.notificationmethod.NotificationMethodRepo;
|
||||
import monasca.api.domain.model.statistic.StatisticRepo;
|
||||
import monasca.api.infrastructure.persistence.PersistUtils;
|
||||
import monasca.api.infrastructure.persistence.influxdb.InfluxV9AlarmStateHistoryRepo;
|
||||
import monasca.api.infrastructure.persistence.influxdb.InfluxV9MeasurementRepo;
|
||||
import monasca.api.infrastructure.persistence.influxdb.InfluxV9MetricDefinitionRepo;
|
||||
import monasca.api.infrastructure.persistence.influxdb.InfluxV9RepoReader;
|
||||
import monasca.api.infrastructure.persistence.influxdb.InfluxV9StatisticRepo;
|
||||
import monasca.api.infrastructure.persistence.influxdb.InfluxV9Utils;
|
||||
import monasca.api.infrastructure.persistence.mysql.AlarmDefinitionMySqlRepoImpl;
|
||||
import monasca.api.infrastructure.persistence.mysql.AlarmMySqlRepoImpl;
|
||||
import monasca.api.infrastructure.persistence.mysql.NotificationMethodMySqlRepoImpl;
|
||||
import monasca.api.infrastructure.persistence.vertica.AlarmStateHistoryVerticaRepoImpl;
|
||||
import monasca.api.infrastructure.persistence.vertica.MeasurementVerticaRepoImpl;
|
||||
import monasca.api.infrastructure.persistence.vertica.MetricDefinitionVerticaRepoImpl;
|
||||
import monasca.api.infrastructure.persistence.vertica.StatisticVerticaRepoImpl;
|
||||
|
||||
/**
|
||||
* Infrastructure layer bindings.
|
||||
*/
|
||||
public class InfrastructureModule extends AbstractModule {
|
||||
private ApiConfig config;
|
||||
|
||||
private static final String VERTICA = "vertica";
|
||||
private static final String INFLUXDB = "influxdb";
|
||||
private static final String INFLUXDB_V9 = "v9";
|
||||
|
||||
public InfrastructureModule(ApiConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
|
||||
// Bind repositories
|
||||
bind(AlarmRepo.class).to(AlarmMySqlRepoImpl.class).in(Singleton.class);
|
||||
bind(AlarmDefinitionRepo.class).to(AlarmDefinitionMySqlRepoImpl.class).in(
|
||||
Singleton.class);
|
||||
|
||||
if (config.databaseConfiguration.getDatabaseType().trim().equalsIgnoreCase(VERTICA)) {
|
||||
|
||||
bind(AlarmStateHistoryRepo.class).to(AlarmStateHistoryVerticaRepoImpl.class).in(
|
||||
Singleton.class);
|
||||
bind(MetricDefinitionRepo.class).to(MetricDefinitionVerticaRepoImpl.class).in(
|
||||
Singleton.class);
|
||||
bind(MeasurementRepo.class).to(MeasurementVerticaRepoImpl.class).in(
|
||||
Singleton.class);
|
||||
bind(StatisticRepo.class).to(StatisticVerticaRepoImpl.class).in(Singleton.class);
|
||||
|
||||
} else if (config.databaseConfiguration.getDatabaseType().trim().equalsIgnoreCase(INFLUXDB)) {
|
||||
|
||||
if (config.influxDB.getVersion() != null
|
||||
&& !config.influxDB.getVersion().equalsIgnoreCase(INFLUXDB_V9)) {
|
||||
|
||||
System.err.println("Found unsupported Influxdb version: " + config.influxDB.getVersion());
|
||||
System.err.println("Supported Influxdb versions are 'v9'");
|
||||
System.err.println("Check your config file");
|
||||
System.exit(1);
|
||||
|
||||
}
|
||||
|
||||
bind(PersistUtils.class).in(Singleton.class);
|
||||
bind(InfluxV9Utils.class).in(Singleton.class);
|
||||
bind(InfluxV9RepoReader.class).in(Singleton.class);
|
||||
|
||||
bind(AlarmStateHistoryRepo.class).to(InfluxV9AlarmStateHistoryRepo.class).in(Singleton.class);
|
||||
bind(MetricDefinitionRepo.class).to(InfluxV9MetricDefinitionRepo.class).in(Singleton.class);
|
||||
bind(MeasurementRepo.class).to(InfluxV9MeasurementRepo.class).in(Singleton.class);
|
||||
bind(StatisticRepo.class).to(InfluxV9StatisticRepo.class).in(Singleton.class);
|
||||
|
||||
} else {
|
||||
|
||||
throw new ProvisionException("Failed to detect supported database. Supported databases are "
|
||||
+ "'vertica' and 'influxdb'. Check your config file.");
|
||||
}
|
||||
|
||||
bind(NotificationMethodRepo.class).to(NotificationMethodMySqlRepoImpl.class).in(
|
||||
Singleton.class);
|
||||
}
|
||||
|
||||
@Provides
|
||||
InfluxDB provideInfluxDB() {
|
||||
InfluxDB influxDB =
|
||||
InfluxDBFactory.connect(this.config.influxDB.getUrl(), this.config.influxDB.getUser(),
|
||||
this.config.influxDB.getPassword());
|
||||
return influxDB;
|
||||
}
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.infrastructure.middleware;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* CS Middleware configuration.
|
||||
*/
|
||||
public class MiddlewareConfiguration {
|
||||
public Boolean enabled = false;
|
||||
@JsonProperty
|
||||
public String serverVIP;
|
||||
@JsonProperty
|
||||
public String serverPort;
|
||||
@JsonProperty
|
||||
public Boolean useHttps = Boolean.FALSE;
|
||||
@JsonProperty
|
||||
public String connTimeout = "500";
|
||||
@JsonProperty
|
||||
public Boolean connSSLClientAuth = Boolean.FALSE;
|
||||
@JsonProperty
|
||||
public String connPoolMaxActive = "3";
|
||||
@JsonProperty
|
||||
public String connPoolMaxIdle = "3";
|
||||
@JsonProperty
|
||||
public String connPoolEvictPeriod = "600000";
|
||||
@JsonProperty
|
||||
public String connPoolMinIdleTime = "600000";
|
||||
@JsonProperty
|
||||
public String connRetryTimes = "2";
|
||||
@JsonProperty
|
||||
public String connRetryInterval = "50";
|
||||
@JsonProperty
|
||||
public List<String> defaultAuthorizedRoles;
|
||||
@JsonProperty
|
||||
public List<String> agentAuthorizedRoles;
|
||||
@JsonProperty
|
||||
public String timeToCacheToken = "600";
|
||||
@JsonProperty
|
||||
public String adminAuthMethod;
|
||||
@JsonProperty
|
||||
public String adminUser;
|
||||
@JsonProperty
|
||||
public String adminToken;
|
||||
@JsonProperty
|
||||
public String adminPassword;
|
||||
@JsonProperty
|
||||
public String adminProjectId = "";
|
||||
@JsonProperty
|
||||
public String adminProjectName = "";
|
||||
@JsonProperty
|
||||
public String maxTokenCacheSize = "1048576";
|
||||
@JsonProperty
|
||||
public String truststore;
|
||||
@JsonProperty
|
||||
public String truststorePassword;
|
||||
@JsonProperty
|
||||
public String keystore;
|
||||
@JsonProperty
|
||||
public String keystorePassword;
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Houses the infrastructure layer.
|
||||
*/
|
||||
package monasca.api.infrastructure;
|
@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.infrastructure.persistence;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.skife.jdbi.v2.Query;
|
||||
|
||||
/**
|
||||
* Utilities for building dimension queries.
|
||||
*
|
||||
* This class has issues with testing with mockito because bind method on Query class is final.
|
||||
*/
|
||||
public final class DimensionQueries {
|
||||
private DimensionQueries() {}
|
||||
|
||||
public static void bindDimensionsToQuery(Query<?> query, Map<String, String> dimensions) {
|
||||
if (dimensions != null) {
|
||||
int i = 0;
|
||||
for (Iterator<Map.Entry<String, String>> it = dimensions.entrySet().iterator(); it.hasNext(); i++) {
|
||||
Map.Entry<String, String> entry = it.next();
|
||||
query.bind("dname" + i, entry.getKey());
|
||||
query.bind("dvalue" + i, entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Map<String, String> dimensionsFor(String dimensionSet) {
|
||||
Map<String, String> dimensions = Collections.emptyMap();
|
||||
|
||||
if (dimensionSet != null) {
|
||||
dimensions = new HashMap<String, String>();
|
||||
for (String kvStr : dimensionSet.split(",")) {
|
||||
String[] kv = kvStr.split("=");
|
||||
if (kv.length > 1)
|
||||
dimensions.put(kv[0], kv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return dimensions;
|
||||
}
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.infrastructure.persistence;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import monasca.api.ApiConfig;
|
||||
|
||||
public class PersistUtils {
|
||||
|
||||
private final int maxQueryLimit;
|
||||
|
||||
private final int DEFAULT_MAX_QUERY_LIMIT = 10000;
|
||||
|
||||
@Inject
|
||||
public PersistUtils(ApiConfig config) {
|
||||
this.maxQueryLimit = config.maxQueryLimit;
|
||||
}
|
||||
|
||||
public PersistUtils(int maxQueryLimit) {
|
||||
|
||||
this.maxQueryLimit = maxQueryLimit;
|
||||
|
||||
}
|
||||
|
||||
public PersistUtils() {
|
||||
|
||||
this.maxQueryLimit = DEFAULT_MAX_QUERY_LIMIT;
|
||||
}
|
||||
|
||||
public int getLimit(String limit) {
|
||||
|
||||
if (limit == null || limit.isEmpty()) {
|
||||
return this.maxQueryLimit;
|
||||
}
|
||||
|
||||
int limitInt;
|
||||
try {
|
||||
limitInt = Integer.parseInt(limit);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException(String.format("Found invalid Limit: '%1$s'. Limit must be an integer.", limit));
|
||||
}
|
||||
|
||||
if (limitInt <= this.maxQueryLimit) {
|
||||
|
||||
return limitInt;
|
||||
|
||||
} else {
|
||||
|
||||
return this.maxQueryLimit;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.infrastructure.persistence;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Utilities for building sub alarm queries.
|
||||
*/
|
||||
public final class SubAlarmDefinitionQueries {
|
||||
private SubAlarmDefinitionQueries() {}
|
||||
|
||||
public static String buildJoinClauseFor(Map<String, String> dimensions) {
|
||||
|
||||
StringBuilder sbJoin = new StringBuilder();
|
||||
|
||||
if (dimensions != null) {
|
||||
|
||||
sbJoin = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < dimensions.size(); i++) {
|
||||
sbJoin.append(" inner join sub_alarm_definition_dimension d").append(i).append(" on d").append(i)
|
||||
.append(".dimension_name = :dname").append(i).append(" and d").append(i)
|
||||
.append(".value = :dvalue").append(i).append(" and dim.sub_alarm_definition_id = d")
|
||||
.append(i).append(".sub_alarm_definition_id");
|
||||
}
|
||||
}
|
||||
|
||||
return sbJoin.toString();
|
||||
}
|
||||
}
|
@ -1,277 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.infrastructure.persistence.influxdb;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.skife.jdbi.v2.DBI;
|
||||
import org.skife.jdbi.v2.Handle;
|
||||
import org.skife.jdbi.v2.Query;
|
||||
import org.skife.jdbi.v2.util.StringMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Named;
|
||||
|
||||
import monasca.api.ApiConfig;
|
||||
import monasca.api.domain.model.alarmstatehistory.AlarmStateHistory;
|
||||
import monasca.api.domain.model.alarmstatehistory.AlarmStateHistoryRepo;
|
||||
import monasca.api.infrastructure.persistence.DimensionQueries;
|
||||
import monasca.common.model.alarm.AlarmState;
|
||||
import monasca.common.model.alarm.AlarmTransitionSubAlarm;
|
||||
import monasca.common.model.metric.MetricDefinition;
|
||||
|
||||
|
||||
public class InfluxV9AlarmStateHistoryRepo implements AlarmStateHistoryRepo {
|
||||
|
||||
private static final Logger logger = LoggerFactory
|
||||
.getLogger(InfluxV9AlarmStateHistoryRepo.class);
|
||||
|
||||
private final DBI mysql;
|
||||
private final ApiConfig config;
|
||||
private final String region;
|
||||
private final InfluxV9RepoReader influxV9RepoReader;
|
||||
private final InfluxV9Utils influxV9Utils;
|
||||
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
static {
|
||||
objectMapper
|
||||
.setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
|
||||
}
|
||||
|
||||
private final SimpleDateFormat simpleDateFormat =
|
||||
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
|
||||
|
||||
private final SimpleDateFormat oldSimpleDateFormat =
|
||||
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
|
||||
|
||||
private static final TypeReference<List<MetricDefinition>> METRICS_TYPE =
|
||||
new TypeReference<List<MetricDefinition>>() {};
|
||||
|
||||
private static final TypeReference<List<AlarmTransitionSubAlarm>> SUB_ALARMS_TYPE =
|
||||
new TypeReference<List<AlarmTransitionSubAlarm>>() {};
|
||||
|
||||
@Inject
|
||||
public InfluxV9AlarmStateHistoryRepo(@Named("mysql") DBI mysql,
|
||||
ApiConfig config,
|
||||
InfluxV9RepoReader influxV9RepoReader,
|
||||
InfluxV9Utils influxV9Utils) {
|
||||
|
||||
this.mysql = mysql;
|
||||
this.config = config;
|
||||
this.region = config.region;
|
||||
this.influxV9RepoReader = influxV9RepoReader;
|
||||
this.influxV9Utils = influxV9Utils;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AlarmStateHistory> findById(String tenantId, String alarmId, String offset,
|
||||
int limit)
|
||||
throws Exception {
|
||||
|
||||
|
||||
String q = String.format("select alarm_id, metrics, old_state, new_state, "
|
||||
+ "reason, reason_data, sub_alarms "
|
||||
+ "from alarm_state_history "
|
||||
+ "where %1$s %2$s %3$s %4$s",
|
||||
this.influxV9Utils.publicTenantIdPart(tenantId),
|
||||
this.influxV9Utils.alarmIdPart(alarmId),
|
||||
this.influxV9Utils.timeOffsetPart(offset),
|
||||
this.influxV9Utils.limitPart(limit));
|
||||
|
||||
logger.debug("Alarm state history query: {}", q);
|
||||
|
||||
String r = this.influxV9RepoReader.read(q);
|
||||
|
||||
Series series = this.objectMapper.readValue(r, Series.class);
|
||||
|
||||
List<AlarmStateHistory> alarmStateHistoryList = alarmStateHistoryList(series);
|
||||
|
||||
logger.debug("Found {} alarm state transitions matching query", alarmStateHistoryList.size());
|
||||
|
||||
return alarmStateHistoryList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AlarmStateHistory> find(String tenantId, Map<String, String> dimensions,
|
||||
DateTime startTime, @Nullable DateTime endTime,
|
||||
@Nullable String offset, int limit) throws Exception {
|
||||
|
||||
List<String> alarmIdList = findAlarmIds(this.mysql, tenantId, dimensions);
|
||||
|
||||
if (alarmIdList == null || alarmIdList.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
|
||||
String q = String.format("select alarm_id, metrics, old_state, new_state, "
|
||||
+ "reason, reason_data, sub_alarms "
|
||||
+ "from alarm_state_history "
|
||||
+ "where %1$s %2$s %3$s %4$s %5$s",
|
||||
this.influxV9Utils.publicTenantIdPart(tenantId),
|
||||
this.influxV9Utils.startTimeEndTimePart(startTime, endTime),
|
||||
this.influxV9Utils.alarmIdsPart(alarmIdList),
|
||||
this.influxV9Utils.timeOffsetPart(offset),
|
||||
this.influxV9Utils.limitPart(limit));
|
||||
|
||||
logger.debug("Alarm state history list query: {}", q);
|
||||
|
||||
String r = this.influxV9RepoReader.read(q);
|
||||
|
||||
Series series = this.objectMapper.readValue(r, Series.class);
|
||||
|
||||
List<AlarmStateHistory> alarmStateHistoryList = alarmStateHistoryList(series);
|
||||
|
||||
logger.debug("Found {} alarm state transitions matching query", alarmStateHistoryList.size());
|
||||
|
||||
return alarmStateHistoryList;
|
||||
|
||||
}
|
||||
|
||||
private List<AlarmStateHistory> alarmStateHistoryList(Series series) {
|
||||
|
||||
List<AlarmStateHistory> alarmStateHistoryList = new LinkedList<>();
|
||||
|
||||
if (!series.isEmpty()) {
|
||||
|
||||
for (Serie serie : series.getSeries()) {
|
||||
|
||||
for (String[] values : serie.getValues()) {
|
||||
|
||||
AlarmStateHistory alarmStateHistory = new AlarmStateHistory();
|
||||
|
||||
Date date;
|
||||
try {
|
||||
date = parseTimestamp(values[0]);
|
||||
} catch (ParseException e) {
|
||||
logger.error("Failed to parse time", e);
|
||||
continue;
|
||||
}
|
||||
|
||||
DateTime dateTime = new DateTime(date.getTime(), DateTimeZone.UTC);
|
||||
alarmStateHistory.setTimestamp(dateTime);
|
||||
|
||||
alarmStateHistory.setAlarmId(values[1]);
|
||||
|
||||
List<MetricDefinition> metricDefinitionList;
|
||||
try {
|
||||
metricDefinitionList = this.objectMapper.readValue(values[2], METRICS_TYPE);
|
||||
} catch (IOException e) {
|
||||
logger.error("Failed to parse metrics", e);
|
||||
continue;
|
||||
}
|
||||
|
||||
alarmStateHistory.setMetrics(metricDefinitionList);
|
||||
|
||||
alarmStateHistory.setOldState(AlarmState.valueOf(values[3]));
|
||||
alarmStateHistory.setNewState(AlarmState.valueOf(values[4]));
|
||||
alarmStateHistory.setReason(values[5]);
|
||||
alarmStateHistory.setReasonData(values[6]);
|
||||
|
||||
List<AlarmTransitionSubAlarm> subAlarmList;
|
||||
try {
|
||||
subAlarmList = this.objectMapper.readValue(values[7], SUB_ALARMS_TYPE);
|
||||
} catch (IOException e) {
|
||||
logger.error("Failed to parse sub-alarms", e);
|
||||
continue;
|
||||
}
|
||||
|
||||
alarmStateHistory.setSubAlarms(subAlarmList);
|
||||
|
||||
alarmStateHistoryList.add(alarmStateHistory);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return alarmStateHistoryList;
|
||||
}
|
||||
|
||||
private Date parseTimestamp(String timestampString) throws ParseException {
|
||||
try {
|
||||
return this.simpleDateFormat.parse(timestampString);
|
||||
}
|
||||
catch (ParseException pe) {
|
||||
// This extra part is here just to handle dates in the old format of only
|
||||
// having seconds. This should be removed in a month or so
|
||||
return this.oldSimpleDateFormat.parse(timestampString);
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> findAlarmIds(DBI mysql, String tenantId,
|
||||
Map<String, String> dimensions) {
|
||||
|
||||
final String
|
||||
FIND_ALARMS_SQL = "select distinct a.id "
|
||||
+ "from alarm as a "
|
||||
+ "join alarm_definition as ad on a.alarm_definition_id = ad.id "
|
||||
+ "%s "
|
||||
+ "where ad.tenant_id = :tenantId and ad.deleted_at is NULL "
|
||||
+ "order by ad.created_at";
|
||||
|
||||
List<String> alarmIdList = null;
|
||||
|
||||
try (Handle h = mysql.open()) {
|
||||
|
||||
final String sql = String.format(FIND_ALARMS_SQL, buildJoinClauseFor(dimensions));
|
||||
|
||||
Query<Map<String, Object>> query = h.createQuery(sql).bind("tenantId", tenantId);
|
||||
|
||||
logger.debug("AlarmStateHistory query '{}'", sql);
|
||||
|
||||
DimensionQueries.bindDimensionsToQuery(query, dimensions);
|
||||
|
||||
alarmIdList = query.map(StringMapper.FIRST).list();
|
||||
}
|
||||
|
||||
return alarmIdList;
|
||||
}
|
||||
|
||||
private String buildJoinClauseFor(Map<String, String> dimensions) {
|
||||
|
||||
if ((dimensions == null) || dimensions.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
final StringBuilder sbJoin = new StringBuilder("join alarm_metric as am on a.id=am.alarm_id ");
|
||||
sbJoin.append(
|
||||
"join metric_definition_dimensions as mdd on am.metric_definition_dimensions_id=mdd.id ");
|
||||
|
||||
for (int i = 0; i < dimensions.size(); i++) {
|
||||
final String tableAlias = "md" + i;
|
||||
sbJoin.append(" inner join metric_dimension ").append(tableAlias).append(" on ")
|
||||
.append(tableAlias).append(".name = :dname").append(i).append(" and ").append(tableAlias)
|
||||
.append(".value = :dvalue").append(i).append(" and mdd.metric_dimension_set_id = ")
|
||||
.append(tableAlias).append(".dimension_set_id");
|
||||
}
|
||||
|
||||
return sbJoin.toString();
|
||||
}
|
||||
}
|
@ -1,178 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.infrastructure.persistence.influxdb;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import monasca.api.ApiConfig;
|
||||
import monasca.api.domain.exception.MultipleMetricsException;
|
||||
import monasca.api.domain.model.measurement.MeasurementRepo;
|
||||
import monasca.api.domain.model.measurement.Measurements;
|
||||
|
||||
public class InfluxV9MeasurementRepo implements MeasurementRepo {
|
||||
|
||||
|
||||
private static final Logger logger = LoggerFactory
|
||||
.getLogger(InfluxV9MeasurementRepo.class);
|
||||
|
||||
private final static TypeReference VALUE_META_TYPE = new TypeReference<Map<String, String>>() {};
|
||||
|
||||
private final ApiConfig config;
|
||||
private final String region;
|
||||
private final InfluxV9RepoReader influxV9RepoReader;
|
||||
private final InfluxV9Utils influxV9Utils;
|
||||
private final InfluxV9MetricDefinitionRepo influxV9MetricDefinitionRepo;
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
@Inject
|
||||
public InfluxV9MeasurementRepo(ApiConfig config,
|
||||
InfluxV9RepoReader influxV9RepoReader,
|
||||
InfluxV9Utils influxV9Utils,
|
||||
InfluxV9MetricDefinitionRepo influxV9MetricDefinitionRepo) {
|
||||
this.config = config;
|
||||
this.region = config.region;
|
||||
this.influxV9RepoReader = influxV9RepoReader;
|
||||
this.influxV9Utils = influxV9Utils;
|
||||
this.influxV9MetricDefinitionRepo = influxV9MetricDefinitionRepo;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Measurements> find(String tenantId, String name, Map<String, String> dimensions,
|
||||
DateTime startTime, @Nullable DateTime endTime,
|
||||
@Nullable String offset, int limit, Boolean mergeMetricsFlag)
|
||||
throws Exception {
|
||||
|
||||
String q = buildQuery(tenantId, name, dimensions, startTime, endTime,
|
||||
offset, limit, mergeMetricsFlag);
|
||||
|
||||
|
||||
String r = this.influxV9RepoReader.read(q);
|
||||
|
||||
Series series = this.objectMapper.readValue(r, Series.class);
|
||||
|
||||
List<Measurements> measurementsList = measurementsList(series);
|
||||
|
||||
logger.debug("Found {} metrics matching query", measurementsList.size());
|
||||
|
||||
return measurementsList;
|
||||
}
|
||||
|
||||
private String buildQuery(String tenantId, String name, Map<String, String> dimensions,
|
||||
DateTime startTime, DateTime endTime, String offset, int limit,
|
||||
Boolean mergeMetricsFlag) throws Exception {
|
||||
|
||||
String q;
|
||||
if (Boolean.TRUE.equals(mergeMetricsFlag)) {
|
||||
|
||||
// Had to use * to handle value meta. If we select valueMeta and it does not exist, then error.
|
||||
q = String.format("select * %1$s "
|
||||
+ "where %2$s %3$s %4$s %5$s %6$s %7$s %8$s",
|
||||
this.influxV9Utils.namePart(name, true),
|
||||
this.influxV9Utils.privateTenantIdPart(tenantId),
|
||||
this.influxV9Utils.privateRegionPart(this.region),
|
||||
this.influxV9Utils.startTimePart(startTime),
|
||||
this.influxV9Utils.dimPart(dimensions),
|
||||
this.influxV9Utils.endTimePart(endTime),
|
||||
this.influxV9Utils.timeOffsetPart(offset),
|
||||
this.influxV9Utils.limitPart(limit));
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
if (!this.influxV9MetricDefinitionRepo.isAtMostOneSeries(tenantId, name, dimensions)) {
|
||||
|
||||
throw new MultipleMetricsException(name, dimensions);
|
||||
|
||||
}
|
||||
|
||||
// Had to use * to handle value meta. If we select valueMeta and it does not exist, then error.
|
||||
q = String.format("select * %1$s "
|
||||
+ "where %2$s %3$s %4$s %5$s %6$s %7$s %8$s %9$s slimit 1",
|
||||
this.influxV9Utils.namePart(name, true),
|
||||
this.influxV9Utils.privateTenantIdPart(tenantId),
|
||||
this.influxV9Utils.privateRegionPart(this.region),
|
||||
this.influxV9Utils.startTimePart(startTime),
|
||||
this.influxV9Utils.dimPart(dimensions),
|
||||
this.influxV9Utils.endTimePart(endTime),
|
||||
this.influxV9Utils.timeOffsetPart(offset),
|
||||
this.influxV9Utils.groupByPart(),
|
||||
this.influxV9Utils.limitPart(limit));
|
||||
}
|
||||
|
||||
logger.debug("Measurements query: {}", q);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
|
||||
private List<Measurements> measurementsList(Series series) {
|
||||
|
||||
List<Measurements> measurementsList = new LinkedList<>();
|
||||
|
||||
if (!series.isEmpty()) {
|
||||
|
||||
for (Serie serie : series.getSeries()) {
|
||||
|
||||
Measurements measurements =
|
||||
new Measurements(serie.getName(),
|
||||
influxV9Utils.filterPrivateTags(serie.getTags()));
|
||||
|
||||
for (String[] values : serie.getValues()) {
|
||||
|
||||
measurements.addMeasurement(
|
||||
new Object[]{values[0], Double.parseDouble(values[1]), getValueMeta(values)});
|
||||
}
|
||||
|
||||
measurementsList.add(measurements);
|
||||
}
|
||||
}
|
||||
|
||||
return measurementsList;
|
||||
|
||||
}
|
||||
|
||||
private Map<String, String> getValueMeta(String[] values) {
|
||||
|
||||
Map<String, String> valueMeta = new HashMap();
|
||||
|
||||
if (values.length >= 3 && values[2] != null && !values[2].isEmpty()) {
|
||||
|
||||
try {
|
||||
valueMeta =
|
||||
this.objectMapper.readValue(values[2], VALUE_META_TYPE);
|
||||
} catch (IOException e) {
|
||||
logger.error("Failed to parse value metadata: {}", values[2], e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return valueMeta;
|
||||
}
|
||||
}
|
@ -1,199 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.infrastructure.persistence.influxdb;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import monasca.api.ApiConfig;
|
||||
import monasca.api.domain.model.metric.MetricDefinitionRepo;
|
||||
import monasca.api.domain.model.metric.MetricName;
|
||||
import monasca.common.model.metric.MetricDefinition;
|
||||
|
||||
|
||||
public class InfluxV9MetricDefinitionRepo implements MetricDefinitionRepo {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(InfluxV9MetricDefinitionRepo.class);
|
||||
|
||||
private final ApiConfig config;
|
||||
private final InfluxV9RepoReader influxV9RepoReader;
|
||||
private final InfluxV9Utils influxV9Utils;
|
||||
private final String region;
|
||||
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
|
||||
@Inject
|
||||
public InfluxV9MetricDefinitionRepo(ApiConfig config,
|
||||
InfluxV9RepoReader influxV9RepoReader,
|
||||
InfluxV9Utils influxV9Utils) {
|
||||
this.config = config;
|
||||
this.region = config.region;
|
||||
this.influxV9RepoReader = influxV9RepoReader;
|
||||
this.influxV9Utils = influxV9Utils;
|
||||
|
||||
}
|
||||
|
||||
boolean isAtMostOneSeries(String tenantId, String name, Map<String, String> dimensions)
|
||||
throws Exception {
|
||||
|
||||
// Set limit to 2. We only care if we get 0, 1, or 2 results back.
|
||||
String q = String.format("show series %1$s "
|
||||
+ "where %2$s %3$s %4$s limit 2",
|
||||
this.influxV9Utils.namePart(name, false),
|
||||
this.influxV9Utils.privateTenantIdPart(tenantId),
|
||||
this.influxV9Utils.privateRegionPart(this.region),
|
||||
this.influxV9Utils.dimPart(dimensions));
|
||||
|
||||
logger.debug("Metric definition query: {}", q);
|
||||
|
||||
String r = this.influxV9RepoReader.read(q);
|
||||
|
||||
Series series = this.objectMapper.readValue(r, Series.class);
|
||||
|
||||
List<MetricDefinition> metricDefinitionList = metricDefinitionList(series, 0);
|
||||
|
||||
logger.debug("Found {} metric definitions matching query", metricDefinitionList.size());
|
||||
|
||||
return metricDefinitionList.size() > 1 ? false : true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<MetricDefinition> find(String tenantId, String name,
|
||||
Map<String, String> dimensions,
|
||||
String offset, int limit) throws Exception {
|
||||
|
||||
int startIndex = this.influxV9Utils.startIndex(offset);
|
||||
|
||||
String q = String.format("show series %1$s "
|
||||
+ "where %2$s %3$s %4$s %5$s %6$s",
|
||||
this.influxV9Utils.namePart(name, false),
|
||||
this.influxV9Utils.privateTenantIdPart(tenantId),
|
||||
this.influxV9Utils.privateRegionPart(this.region),
|
||||
this.influxV9Utils.dimPart(dimensions),
|
||||
this.influxV9Utils.limitPart(limit),
|
||||
this.influxV9Utils.offsetPart(startIndex));
|
||||
|
||||
logger.debug("Metric definition query: {}", q);
|
||||
|
||||
String r = this.influxV9RepoReader.read(q);
|
||||
|
||||
Series series = this.objectMapper.readValue(r, Series.class);
|
||||
|
||||
List<MetricDefinition> metricDefinitionList = metricDefinitionList(series, startIndex);
|
||||
|
||||
logger.debug("Found {} metric definitions matching query", metricDefinitionList.size());
|
||||
|
||||
return metricDefinitionList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetricName> findNames(String tenantId, Map<String, String> dimensions,
|
||||
String offset, int limit) throws Exception {
|
||||
|
||||
int startIndex = this.influxV9Utils.startIndex(offset);
|
||||
|
||||
String q = String.format("show measurements "
|
||||
+ "where %1$s %2$s %3$s %4$s %5$s",
|
||||
this.influxV9Utils.privateTenantIdPart(tenantId),
|
||||
this.influxV9Utils.privateRegionPart(this.region),
|
||||
this.influxV9Utils.dimPart(dimensions),
|
||||
this.influxV9Utils.limitPart(limit),
|
||||
this.influxV9Utils.offsetPart(startIndex));
|
||||
|
||||
logger.debug("Metric name query: {}", q);
|
||||
|
||||
String r = this.influxV9RepoReader.read(q);
|
||||
|
||||
Series series = this.objectMapper.readValue(r, Series.class);
|
||||
|
||||
List<MetricName> metricNameList = metricNameList(series, startIndex);
|
||||
|
||||
logger.debug("Found {} metric definitions matching query", metricNameList.size());
|
||||
|
||||
return metricNameList;
|
||||
}
|
||||
|
||||
private List<MetricDefinition> metricDefinitionList(Series series, int startIndex) {
|
||||
|
||||
List<MetricDefinition> metricDefinitionList = new ArrayList<>();
|
||||
|
||||
if (!series.isEmpty()) {
|
||||
|
||||
int index = startIndex;
|
||||
|
||||
for (Serie serie : series.getSeries()) {
|
||||
|
||||
for (String[] values : serie.getValues()) {
|
||||
|
||||
MetricDefinition m = new MetricDefinition(serie.getName(), dims(values, serie.getColumns()));
|
||||
m.setId(String.valueOf(index++));
|
||||
metricDefinitionList.add(m);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return metricDefinitionList;
|
||||
}
|
||||
|
||||
private List<MetricName> metricNameList(Series series, int startIndex) {
|
||||
List<MetricName> metricNameList = new ArrayList<>();
|
||||
|
||||
if (!series.isEmpty()) {
|
||||
|
||||
int index = startIndex;
|
||||
|
||||
Serie serie = series.getSeries()[0];
|
||||
|
||||
for (String[] values : serie.getValues()) {
|
||||
MetricName m =
|
||||
new MetricName(String.valueOf(index++), values[0]);
|
||||
metricNameList.add(m);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return metricNameList;
|
||||
}
|
||||
|
||||
private Map<String, String> dims(String[] vals, String[] cols) {
|
||||
|
||||
Map<String, String> dims = new HashMap<>();
|
||||
|
||||
for (int i = 0; i < cols.length; ++i) {
|
||||
if (!cols[i].equals("_region")
|
||||
&& !cols[i].equals("_tenant_id")
|
||||
&& !cols[i].equals("_id")) {
|
||||
if (!vals[i].equalsIgnoreCase("null")) {
|
||||
dims.put(cols[i], vals[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return dims;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,168 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package monasca.api.infrastructure.persistence.influxdb;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HeaderElement;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpException;
|
||||
import org.apache.http.HttpRequest;
|
||||
import org.apache.http.HttpRequestInterceptor;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpResponseInterceptor;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.client.entity.GzipDecompressingEntity;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
import monasca.api.ApiConfig;
|
||||
|
||||
public class InfluxV9RepoReader {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(InfluxV9RepoReader.class);
|
||||
|
||||
private final String influxName;
|
||||
private final String influxUrl;
|
||||
private final String influxCreds;
|
||||
private final String influxUser;
|
||||
private final String influxPass;
|
||||
private final String baseAuthHeader;
|
||||
private final boolean gzip;
|
||||
|
||||
private final CloseableHttpClient httpClient;
|
||||
|
||||
@Inject
|
||||
public InfluxV9RepoReader(final ApiConfig config) {
|
||||
|
||||
this.influxName = config.influxDB.getName();
|
||||
logger.debug("Influxdb database name: {}", this.influxName);
|
||||
|
||||
this.influxUrl = config.influxDB.getUrl() + "/query";
|
||||
logger.debug("Influxdb URL: {}", this.influxUrl);
|
||||
|
||||
this.influxUser = config.influxDB.getUser();
|
||||
this.influxPass = config.influxDB.getPassword();
|
||||
this.influxCreds = this.influxUser + ":" + this.influxPass;
|
||||
|
||||
this.gzip = config.influxDB.getGzip();
|
||||
logger.debug("Influxdb gzip responses: {}", this.gzip);
|
||||
|
||||
logger.debug("Setting up basic Base64 authentication");
|
||||
this.baseAuthHeader = "Basic " + new String(Base64.encodeBase64(this.influxCreds.getBytes()));
|
||||
|
||||
// We inject InfluxV9RepoReader as a singleton. So, we must share connections safely.
|
||||
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
|
||||
cm.setMaxTotal(config.influxDB.getMaxHttpConnections());
|
||||
|
||||
if (this.gzip) {
|
||||
|
||||
logger.debug("Setting up gzip responses from Influxdb");
|
||||
|
||||
this.httpClient =
|
||||
HttpClients.custom().setConnectionManager(cm)
|
||||
.addInterceptorFirst(new HttpRequestInterceptor() {
|
||||
|
||||
public void process(final HttpRequest request, final HttpContext context)
|
||||
throws HttpException, IOException {
|
||||
if (!request.containsHeader("Accept-Encoding")) {
|
||||
request.addHeader("Accept-Encoding", "gzip");
|
||||
}
|
||||
}
|
||||
}).addInterceptorFirst(new HttpResponseInterceptor() {
|
||||
|
||||
public void process(final HttpResponse response, final HttpContext context)
|
||||
throws HttpException, IOException {
|
||||
HttpEntity entity = response.getEntity();
|
||||
if (entity != null) {
|
||||
Header ceheader = entity.getContentEncoding();
|
||||
if (ceheader != null) {
|
||||
HeaderElement[] codecs = ceheader.getElements();
|
||||
for (int i = 0; i < codecs.length; i++) {
|
||||
if (codecs[i].getName().equalsIgnoreCase("gzip")) {
|
||||
response.setEntity(new GzipDecompressingEntity(response.getEntity()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}).build();
|
||||
|
||||
} else {
|
||||
|
||||
logger.debug("Setting up non-gzip responses from Influxdb");
|
||||
|
||||
this.httpClient = HttpClients.custom().setConnectionManager(cm).build();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
protected String read(final String query) throws Exception {
|
||||
|
||||
HttpGet request = new HttpGet(this.influxUrl + "?q=" + URLEncoder.encode(query, "UTF-8")
|
||||
+ "&db=" + URLEncoder.encode(this.influxName, "UTF-8"));
|
||||
|
||||
request.addHeader("content-type", "application/json");
|
||||
request.addHeader("Authorization", this.baseAuthHeader);
|
||||
|
||||
try {
|
||||
|
||||
logger.debug("Sending query {} to influx database {} at {}", query, this.influxName,
|
||||
this.influxUrl);
|
||||
|
||||
HttpResponse response = this.httpClient.execute(request);
|
||||
|
||||
int rc = response.getStatusLine().getStatusCode();
|
||||
|
||||
logger.debug("Received {} status code from influx database {} at {}", rc, this.influxName,
|
||||
this.influxUrl);
|
||||
|
||||
if (rc != HttpStatus.SC_OK) {
|
||||
|
||||
HttpEntity entity = response.getEntity();
|
||||
String responseString = EntityUtils.toString(entity, "UTF-8");
|
||||
logger
|
||||
.error("Failed to query influx database {} at {}: {}", this.influxName, this.influxUrl,
|
||||
String.valueOf(rc));
|
||||
logger.error("Http response: {}", responseString);
|
||||
|
||||
throw new Exception(rc + ":" + responseString);
|
||||
}
|
||||
|
||||
logger
|
||||
.debug("Successfully queried influx database {} at {}", this.influxName, this.influxUrl);
|
||||
|
||||
HttpEntity entity = response.getEntity();
|
||||
return entity != null ? EntityUtils.toString(entity, "UTF-8") : null;
|
||||
|
||||
} finally {
|
||||
|
||||
request.releaseConnection();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,207 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.infrastructure.persistence.influxdb;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import monasca.api.ApiConfig;
|
||||
import monasca.api.domain.exception.MultipleMetricsException;
|
||||
import monasca.api.domain.model.statistic.StatisticRepo;
|
||||
import monasca.api.domain.model.statistic.Statistics;
|
||||
|
||||
|
||||
public class InfluxV9StatisticRepo implements StatisticRepo {
|
||||
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(InfluxV9StatisticRepo.class);
|
||||
|
||||
private final ApiConfig config;
|
||||
private final String region;
|
||||
private final InfluxV9RepoReader influxV9RepoReader;
|
||||
private final InfluxV9Utils influxV9Utils;
|
||||
private final InfluxV9MetricDefinitionRepo influxV9MetricDefinitionRepo;
|
||||
|
||||
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
|
||||
@Inject
|
||||
public InfluxV9StatisticRepo(ApiConfig config,
|
||||
InfluxV9RepoReader influxV9RepoReader,
|
||||
InfluxV9Utils influxV9Utils,
|
||||
InfluxV9MetricDefinitionRepo influxV9MetricDefinitionRepo) {
|
||||
this.config = config;
|
||||
this.region = config.region;
|
||||
this.influxV9RepoReader = influxV9RepoReader;
|
||||
this.influxV9Utils = influxV9Utils;
|
||||
this.influxV9MetricDefinitionRepo = influxV9MetricDefinitionRepo;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Statistics> find(String tenantId, String name, Map<String, String> dimensions,
|
||||
DateTime startTime, @Nullable DateTime endTime,
|
||||
List<String> statistics, int period, String offset, int limit,
|
||||
Boolean mergeMetricsFlag) throws Exception {
|
||||
|
||||
String q = buildQuery(tenantId, name, dimensions, startTime, endTime,
|
||||
statistics, period, offset, limit, mergeMetricsFlag);
|
||||
|
||||
String r = this.influxV9RepoReader.read(q);
|
||||
|
||||
Series series = this.objectMapper.readValue(r, Series.class);
|
||||
|
||||
List<Statistics> statisticsList = statisticslist(series);
|
||||
|
||||
logger.debug("Found {} metric definitions matching query", statisticsList.size());
|
||||
|
||||
return statisticsList;
|
||||
|
||||
}
|
||||
|
||||
private String buildQuery(String tenantId, String name, Map<String, String> dimensions,
|
||||
DateTime startTime, DateTime endTime, List<String> statistics,
|
||||
int period, String offset, int limit, Boolean mergeMetricsFlag)
|
||||
throws Exception {
|
||||
|
||||
String q;
|
||||
|
||||
if (Boolean.TRUE.equals(mergeMetricsFlag)) {
|
||||
|
||||
q = String.format("select %1$s %2$s "
|
||||
+ "where %3$s %4$s %5$s %6$s %7$s %8$s %9$s %10$s",
|
||||
funcPart(statistics),
|
||||
this.influxV9Utils.namePart(name, true),
|
||||
this.influxV9Utils.privateTenantIdPart(tenantId),
|
||||
this.influxV9Utils.privateRegionPart(this.region),
|
||||
this.influxV9Utils.startTimePart(startTime),
|
||||
this.influxV9Utils.dimPart(dimensions),
|
||||
this.influxV9Utils.endTimePart(endTime),
|
||||
this.influxV9Utils.timeOffsetPart(offset),
|
||||
this.influxV9Utils.periodPart(period),
|
||||
this.influxV9Utils.limitPart(limit));
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
if (!this.influxV9MetricDefinitionRepo.isAtMostOneSeries(tenantId, name, dimensions)) {
|
||||
|
||||
throw new MultipleMetricsException(name, dimensions);
|
||||
}
|
||||
|
||||
q = String.format("select %1$s %2$s "
|
||||
+ "where %3$s %4$s %5$s %6$s %7$s %8$s %9$s %10$s slimit 1",
|
||||
funcPart(statistics),
|
||||
this.influxV9Utils.namePart(name, true),
|
||||
this.influxV9Utils.privateTenantIdPart(tenantId),
|
||||
this.influxV9Utils.privateRegionPart(this.region),
|
||||
this.influxV9Utils.startTimePart(startTime),
|
||||
this.influxV9Utils.dimPart(dimensions),
|
||||
this.influxV9Utils.endTimePart(endTime),
|
||||
this.influxV9Utils.timeOffsetPart(offset),
|
||||
this.influxV9Utils.periodPartWithGroupBy(period),
|
||||
this.influxV9Utils.limitPart(limit));
|
||||
}
|
||||
|
||||
logger.debug("Statistics query: {}", q);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
|
||||
private List<Statistics> statisticslist(Series series) {
|
||||
|
||||
List<Statistics> statisticsList = new LinkedList<>();
|
||||
|
||||
if (!series.isEmpty()) {
|
||||
|
||||
for (Serie serie : series.getSeries()) {
|
||||
|
||||
Statistics statistics = new Statistics(serie.getName(),
|
||||
this.influxV9Utils.filterPrivateTags(serie.getTags()),
|
||||
Arrays.asList(translateNames(serie.getColumns())));
|
||||
|
||||
for (Object[] values : serie.getValues()) {
|
||||
statistics.addStatistics(buildValsList(values));
|
||||
}
|
||||
|
||||
statisticsList.add(statistics);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return statisticsList;
|
||||
}
|
||||
|
||||
private List<Object> buildValsList(Object[] values) {
|
||||
|
||||
ArrayList<Object> valObjArryList = new ArrayList<>();
|
||||
|
||||
// First value is the timestamp.
|
||||
valObjArryList.add(values[0]);
|
||||
|
||||
// All other values are doubles.
|
||||
for (int i = 1; i < values.length; ++i) {
|
||||
valObjArryList.add(Double.parseDouble((String) values[i]));
|
||||
}
|
||||
|
||||
return valObjArryList;
|
||||
}
|
||||
|
||||
private String[] translateNames(String[] columnNamesArry) {
|
||||
|
||||
for (int i = 0; i < columnNamesArry.length; i++) {
|
||||
|
||||
columnNamesArry[i] = columnNamesArry[i].replaceAll("^time$", "timestamp");
|
||||
columnNamesArry[i] = columnNamesArry[i].replaceAll("^mean$", "avg");
|
||||
|
||||
}
|
||||
|
||||
return columnNamesArry;
|
||||
}
|
||||
|
||||
private String funcPart(List<String> statistics) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (String stat : statistics) {
|
||||
if (sb.length() != 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
|
||||
if (stat.trim().toLowerCase().equals("avg")) {
|
||||
sb.append("mean(value)");
|
||||
} else {
|
||||
sb.append(String.format("%1$s(value)", stat));
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
@ -1,236 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.infrastructure.persistence.influxdb;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.format.ISODateTimeFormat;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import monasca.api.infrastructure.persistence.PersistUtils;
|
||||
|
||||
public class InfluxV9Utils {
|
||||
|
||||
private final PersistUtils persistUtils;
|
||||
|
||||
private static final Pattern sqlUnsafePattern = Pattern.compile("^.*('|;|\")+.*$");
|
||||
|
||||
@Inject
|
||||
public InfluxV9Utils(PersistUtils persistUtils) {
|
||||
|
||||
this.persistUtils = persistUtils;
|
||||
|
||||
}
|
||||
|
||||
public String sanitize(final String taintedString) throws Exception {
|
||||
Matcher m = sqlUnsafePattern.matcher(taintedString);
|
||||
if (m.matches()) {
|
||||
throw new Exception(String.format("Input from user contains single quote ['] or "
|
||||
+ "semi-colon [;] or double quote [\"] characters[ %1$s ]",
|
||||
taintedString));
|
||||
}
|
||||
|
||||
return taintedString;
|
||||
}
|
||||
|
||||
String buildTimePart(final DateTime startTime, final DateTime endTime) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (startTime != null) {
|
||||
sb.append(String.format(" and time > %1$ds", startTime.getMillis() / 1000));
|
||||
}
|
||||
|
||||
if (endTime != null) {
|
||||
sb.append(String.format(" and time < %1$ds", endTime.getMillis() / 1000));
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
public String buildAlarmsPart(List<String> alarmIds) {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String alarmId : alarmIds) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append(" or ");
|
||||
}
|
||||
sb.append(String.format(" alarm_id = '%1$s' ", alarmId));
|
||||
}
|
||||
|
||||
if (sb.length() > 0) {
|
||||
sb.insert(0, " and (");
|
||||
sb.insert(sb.length(), ")");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String groupByPart() {
|
||||
|
||||
return " group by *";
|
||||
|
||||
}
|
||||
|
||||
public String namePart(String name, boolean isRequired) throws Exception {
|
||||
|
||||
if (isRequired) {
|
||||
if (name == null || name.isEmpty()) {
|
||||
throw new Exception(String.format("Found null or empty name: %1$s", name));
|
||||
}
|
||||
}
|
||||
|
||||
if (name == null || name.isEmpty()) {
|
||||
return "";
|
||||
} else {
|
||||
return String.format(" from \"%1$s\"", sanitize(name));
|
||||
}
|
||||
}
|
||||
|
||||
public String publicTenantIdPart(String tenantId) throws Exception {
|
||||
|
||||
if (tenantId == null || tenantId.isEmpty()) {
|
||||
throw new Exception(String.format("Found null or empty tenant id: %1$s", tenantId));
|
||||
}
|
||||
|
||||
return " tenant_id=" + "'" + sanitize(tenantId) + "'";
|
||||
|
||||
}
|
||||
|
||||
public String privateTenantIdPart(String tenantId) throws Exception {
|
||||
|
||||
if (tenantId == null || tenantId.isEmpty()) {
|
||||
throw new Exception(String.format("Found null or empty tenant id: %1$s", tenantId));
|
||||
}
|
||||
|
||||
return " _tenant_id=" + "'" + sanitize(tenantId) + "'";
|
||||
|
||||
}
|
||||
|
||||
public String alarmIdPart(String alarmId) {
|
||||
|
||||
if (alarmId == null || alarmId.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return " and alarm_id=" + "'" + alarmId + "'";
|
||||
}
|
||||
|
||||
|
||||
public String timeOffsetPart(String offset) {
|
||||
|
||||
if (offset == null || offset.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return String.format(" and time > '%1$s'", offset);
|
||||
}
|
||||
|
||||
public String privateRegionPart(String region) throws Exception {
|
||||
|
||||
if (region == null || region.isEmpty()) {
|
||||
throw new Exception(String.format("Found null or empty region: %1$s", region));
|
||||
}
|
||||
|
||||
return " and _region=" + "'" + sanitize(region) + "'";
|
||||
|
||||
}
|
||||
|
||||
public String dimPart(Map<String, String> dims) throws Exception {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (dims != null && !dims.isEmpty()) {
|
||||
for (String k : dims.keySet()) {
|
||||
String v = dims.get(k);
|
||||
if (k != null && !k.isEmpty() && v != null && !v.isEmpty()) {
|
||||
sb.append(" and " + sanitize(k) + "=" + "'" + sanitize(v) + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String startTimePart(DateTime startTime) {
|
||||
|
||||
return startTime != null ? " and time > " + "'" + ISODateTimeFormat.dateTime().print(startTime)
|
||||
+ "'" : "";
|
||||
}
|
||||
|
||||
public String endTimePart(DateTime endTime) {
|
||||
|
||||
return endTime != null ? " and time < " + "'" + ISODateTimeFormat.dateTime().print(endTime)
|
||||
+ "'" : "";
|
||||
}
|
||||
|
||||
public String limitPart(int limit) {
|
||||
|
||||
// We add 1 to limit to determine if we need to insert a next link.
|
||||
return String.format(" limit %1$d", limit + 1);
|
||||
}
|
||||
|
||||
public String offsetPart(int startIndex) {
|
||||
|
||||
return String.format(" offset %1$d", startIndex);
|
||||
}
|
||||
|
||||
public int startIndex(String offset) {
|
||||
|
||||
if (offset == null || offset.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// We've already returned up to offset, so return offset + 1.
|
||||
return Integer.parseInt(offset) + 1;
|
||||
}
|
||||
|
||||
public String startTimeEndTimePart(DateTime startTime, DateTime endTime) {
|
||||
|
||||
return buildTimePart(startTime, endTime);
|
||||
}
|
||||
|
||||
public String alarmIdsPart(List<String> alarmIdList) {
|
||||
|
||||
return buildAlarmsPart(alarmIdList);
|
||||
|
||||
}
|
||||
|
||||
public String periodPartWithGroupBy(int period) {
|
||||
|
||||
return period > 0 ? String.format(" group by time(%1$ds), * fill(0)", period)
|
||||
: " group by time(300s), * fill(0)";
|
||||
}
|
||||
|
||||
public String periodPart(int period) {
|
||||
|
||||
return period > 0 ? String.format(" group by time(%1$ds) fill(0)", period)
|
||||
: " group by time(300s) fill(0)";
|
||||
}
|
||||
|
||||
Map<String, String> filterPrivateTags(Map<String, String> tagMap) {
|
||||
|
||||
Map<String, String> filteredMap = new HashMap<>(tagMap);
|
||||
|
||||
filteredMap.remove("_tenant_id");
|
||||
filteredMap.remove("_region");
|
||||
|
||||
return filteredMap;
|
||||
}
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.infrastructure.persistence.influxdb;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class Series {
|
||||
|
||||
public SeriesElement[] results;
|
||||
public String error;
|
||||
|
||||
boolean isEmpty() {
|
||||
|
||||
return this.results[0].series == null;
|
||||
}
|
||||
|
||||
int getSeriesLength() {
|
||||
|
||||
if (!isEmpty()) {
|
||||
return this.results[0].series.length;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Serie[] getSeries() {
|
||||
|
||||
return this.results[0].series;
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
|
||||
return this.error;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class SeriesElement {
|
||||
|
||||
public Serie[] series;
|
||||
public String error;
|
||||
|
||||
}
|
||||
|
||||
class Serie {
|
||||
|
||||
// Initialize to defaults to avoid NPE.
|
||||
public String name = "";
|
||||
Map<String, String> tags = new HashMap();
|
||||
public String[] columns = new String[0];
|
||||
public String[][] values = new String[0][0];
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Map getTags() {
|
||||
return tags;
|
||||
}
|
||||
|
||||
public String[] getColumns() {
|
||||
return columns;
|
||||
}
|
||||
|
||||
public String[][] getValues() {
|
||||
return values;
|
||||
}
|
||||
}
|
@ -1,412 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.infrastructure.persistence.mysql;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.ArrayList;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.ResultSet;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.skife.jdbi.v2.DBI;
|
||||
import org.skife.jdbi.v2.Handle;
|
||||
import org.skife.jdbi.v2.Query;
|
||||
import org.skife.jdbi.v2.tweak.ResultSetMapper;
|
||||
import org.skife.jdbi.v2.StatementContext;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import monasca.api.infrastructure.persistence.PersistUtils;
|
||||
import monasca.common.model.alarm.AggregateFunction;
|
||||
import monasca.common.model.alarm.AlarmOperator;
|
||||
import monasca.common.model.alarm.AlarmState;
|
||||
import monasca.common.model.alarm.AlarmSubExpression;
|
||||
import monasca.common.model.metric.MetricDefinition;
|
||||
import monasca.api.domain.exception.EntityNotFoundException;
|
||||
import monasca.api.domain.model.alarmdefinition.AlarmDefinition;
|
||||
import monasca.api.domain.model.alarmdefinition.AlarmDefinitionRepo;
|
||||
import monasca.api.infrastructure.persistence.DimensionQueries;
|
||||
import monasca.api.infrastructure.persistence.SubAlarmDefinitionQueries;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
/**
|
||||
* Alarm repository implementation.
|
||||
*/
|
||||
public class AlarmDefinitionMySqlRepoImpl implements AlarmDefinitionRepo {
|
||||
private static final Joiner COMMA_JOINER = Joiner.on(',');
|
||||
private static final String SUB_ALARM_SQL =
|
||||
"select sa.*, sad.dimensions from sub_alarm_definition as sa "
|
||||
+ "left join (select sub_alarm_definition_id, group_concat(dimension_name, '=', value) as dimensions from sub_alarm_definition_dimension group by sub_alarm_definition_id ) as sad "
|
||||
+ "on sad.sub_alarm_definition_id = sa.id where sa.alarm_definition_id = :alarmDefId";
|
||||
|
||||
private final DBI db;
|
||||
private final PersistUtils persistUtils;
|
||||
|
||||
@Inject
|
||||
public AlarmDefinitionMySqlRepoImpl(@Named("mysql") DBI db, PersistUtils persistUtils) {
|
||||
this.db = db;
|
||||
this.persistUtils = persistUtils;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AlarmDefinition create(String tenantId, String id, String name, String description,
|
||||
String severity, String expression, Map<String, AlarmSubExpression> subExpressions,
|
||||
List<String> matchBy, List<String> alarmActions, List<String> okActions,
|
||||
List<String> undeterminedActions) {
|
||||
Handle h = db.open();
|
||||
|
||||
try {
|
||||
h.begin();
|
||||
h.insert(
|
||||
"insert into alarm_definition (id, tenant_id, name, description, severity, expression, match_by, actions_enabled, created_at, updated_at, deleted_at) values (?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW(), NULL)",
|
||||
id, tenantId, name, description, severity, expression,
|
||||
matchBy == null || Iterables.isEmpty(matchBy) ? null : COMMA_JOINER.join(matchBy), true);
|
||||
|
||||
// Persist sub-alarms
|
||||
createSubExpressions(h, id, subExpressions);
|
||||
|
||||
// Persist actions
|
||||
persistActions(h, id, AlarmState.ALARM, alarmActions);
|
||||
persistActions(h, id, AlarmState.OK, okActions);
|
||||
persistActions(h, id, AlarmState.UNDETERMINED, undeterminedActions);
|
||||
|
||||
h.commit();
|
||||
return new AlarmDefinition(id, name, description, severity, expression, matchBy, true,
|
||||
alarmActions, okActions == null ? Collections.<String>emptyList() : okActions,
|
||||
undeterminedActions == null ? Collections.<String>emptyList() : undeterminedActions);
|
||||
} catch (RuntimeException e) {
|
||||
h.rollback();
|
||||
throw e;
|
||||
} finally {
|
||||
h.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteById(String tenantId, String alarmDefId) {
|
||||
try (Handle h = db.open()) {
|
||||
if (h
|
||||
.update(
|
||||
"update alarm_definition set deleted_at = NOW() where tenant_id = ? and id = ? and deleted_at is NULL",
|
||||
tenantId, alarmDefId) == 0)
|
||||
throw new EntityNotFoundException("No alarm definition exists for %s", alarmDefId);
|
||||
|
||||
// Cascade soft delete to alarms
|
||||
h.execute("delete from alarm where alarm_definition_id = :id", alarmDefId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String exists(String tenantId, String name) {
|
||||
try (Handle h = db.open()) {
|
||||
Map<String, Object> map = h
|
||||
.createQuery(
|
||||
"select id from alarm_definition where tenant_id = :tenantId and name = :name and deleted_at is NULL")
|
||||
.bind("tenantId", tenantId).bind("name", name).first();
|
||||
if (map != null) {
|
||||
if (map.values().size() != 0) {
|
||||
return map.get("id").toString();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public List<AlarmDefinition> find(String tenantId, String name,
|
||||
Map<String, String> dimensions, String offset, int limit) {
|
||||
|
||||
|
||||
try (Handle h = db.open()) {
|
||||
|
||||
String query =
|
||||
" SELECT t.id, t.tenant_id, t.name, t.description, t.expression, t.severity, t.match_by,"
|
||||
+ " t.actions_enabled, t.created_at, t.updated_at, t.deleted_at, "
|
||||
+ " GROUP_CONCAT(aa.alarm_state) AS states, "
|
||||
+ " GROUP_CONCAT(aa.action_id) AS notificationIds "
|
||||
+ "FROM (SELECT distinct ad.id, ad.tenant_id, ad.name, ad.description, ad.expression,"
|
||||
+ " ad.severity, ad.match_by, ad.actions_enabled, ad.created_at, "
|
||||
+ " ad.updated_at, ad.deleted_at "
|
||||
+ " FROM alarm_definition AS ad "
|
||||
+ " LEFT OUTER JOIN sub_alarm_definition AS sad ON ad.id = sad.alarm_definition_id "
|
||||
+ " LEFT OUTER JOIN sub_alarm_definition_dimension AS dim ON sad.id = dim.sub_alarm_definition_id %1$s "
|
||||
+ " WHERE ad.tenant_id = :tenantId AND ad.deleted_at IS NULL %2$s %3$s) AS t "
|
||||
+ "LEFT OUTER JOIN alarm_action AS aa ON t.id = aa.alarm_definition_id "
|
||||
+ "GROUP BY t.id ORDER BY t.id, t.created_at";
|
||||
|
||||
|
||||
StringBuilder sbWhere = new StringBuilder();
|
||||
|
||||
if (name != null) {
|
||||
sbWhere.append(" and ad.name = :name");
|
||||
}
|
||||
|
||||
if (offset != null) {
|
||||
sbWhere.append(" and ad.id > :offset");
|
||||
}
|
||||
|
||||
String limitPart = "";
|
||||
if (limit > 0) {
|
||||
limitPart = " limit :limit";
|
||||
}
|
||||
|
||||
String sql = String.format(query,
|
||||
SubAlarmDefinitionQueries.buildJoinClauseFor(dimensions), sbWhere, limitPart);
|
||||
|
||||
Query<?> q = h.createQuery(sql);
|
||||
|
||||
q.bind("tenantId", tenantId);
|
||||
|
||||
if (name != null) {
|
||||
q.bind("name", name);
|
||||
}
|
||||
|
||||
if (offset != null) {
|
||||
q.bind("offset", offset);
|
||||
}
|
||||
|
||||
if (limit > 0) {
|
||||
q.bind("limit", limit + 1);
|
||||
}
|
||||
|
||||
q.registerMapper(new AlarmDefinitionMapper());
|
||||
q = q.mapTo(AlarmDefinition.class);
|
||||
DimensionQueries.bindDimensionsToQuery(q, dimensions);
|
||||
List<AlarmDefinition> resultSet = (List<AlarmDefinition>) q.list();
|
||||
return resultSet;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AlarmDefinition findById(String tenantId, String alarmDefId) {
|
||||
|
||||
try (Handle h = db.open()) {
|
||||
String query = "SELECT alarm_definition.id, alarm_definition.tenant_id, alarm_definition.name, alarm_definition.description, "
|
||||
+ "alarm_definition.expression, alarm_definition.severity, alarm_definition.match_by, alarm_definition.actions_enabled, "
|
||||
+" alarm_definition.created_at, alarm_definition.updated_at, alarm_definition.deleted_at, "
|
||||
+ "GROUP_CONCAT(alarm_action.action_id) AS notificationIds,group_concat(alarm_action.alarm_state) AS states "
|
||||
+ "FROM alarm_definition LEFT OUTER JOIN alarm_action ON alarm_definition.id=alarm_action.alarm_definition_id "
|
||||
+ " WHERE alarm_definition.tenant_id=:tenantId AND alarm_definition.id=:alarmDefId AND alarm_definition.deleted_at "
|
||||
+ " IS NULL GROUP BY alarm_definition.id";
|
||||
|
||||
Query<?> q = h.createQuery(query);
|
||||
q.bind("tenantId", tenantId);
|
||||
q.bind("alarmDefId", alarmDefId);
|
||||
|
||||
q.registerMapper(new AlarmDefinitionMapper());
|
||||
q = q.mapTo(AlarmDefinition.class);
|
||||
AlarmDefinition alarmDefinition = (AlarmDefinition) q.first();
|
||||
if(alarmDefinition == null)
|
||||
{
|
||||
throw new EntityNotFoundException("No alarm definition exists for %s", alarmDefId);
|
||||
}
|
||||
return alarmDefinition;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, MetricDefinition> findSubAlarmMetricDefinitions(String alarmDefId) {
|
||||
try (Handle h = db.open()) {
|
||||
List<Map<String, Object>> rows =
|
||||
h.createQuery(SUB_ALARM_SQL).bind("alarmDefId", alarmDefId).list();
|
||||
Map<String, MetricDefinition> subAlarmMetricDefs = new HashMap<>();
|
||||
for (Map<String, Object> row : rows) {
|
||||
String id = (String) row.get("id");
|
||||
String metricName = (String) row.get("metric_name");
|
||||
Map<String, String> dimensions =
|
||||
DimensionQueries.dimensionsFor((String) row.get("dimensions"));
|
||||
subAlarmMetricDefs.put(id, new MetricDefinition(metricName, dimensions));
|
||||
}
|
||||
|
||||
return subAlarmMetricDefs;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, AlarmSubExpression> findSubExpressions(String alarmDefId) {
|
||||
try (Handle h = db.open()) {
|
||||
List<Map<String, Object>> rows =
|
||||
h.createQuery(SUB_ALARM_SQL).bind("alarmDefId", alarmDefId).list();
|
||||
Map<String, AlarmSubExpression> subExpressions = new HashMap<>();
|
||||
for (Map<String, Object> row : rows) {
|
||||
String id = (String) row.get("id");
|
||||
AggregateFunction function = AggregateFunction.fromJson((String) row.get("function"));
|
||||
String metricName = (String) row.get("metric_name");
|
||||
AlarmOperator operator = AlarmOperator.fromJson((String) row.get("operator"));
|
||||
Double threshold = (Double) row.get("threshold");
|
||||
Integer period = (Integer) row.get("period");
|
||||
Integer periods = (Integer) row.get("periods");
|
||||
Map<String, String> dimensions =
|
||||
DimensionQueries.dimensionsFor((String) row.get("dimensions"));
|
||||
subExpressions.put(id, new AlarmSubExpression(function, new MetricDefinition(metricName,
|
||||
dimensions), operator, threshold, period, periods));
|
||||
}
|
||||
|
||||
return subExpressions;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(String tenantId, String id, boolean patch, String name, String description,
|
||||
String expression, List<String> matchBy, String severity, boolean actionsEnabled,
|
||||
Collection<String> oldSubAlarmIds, Map<String, AlarmSubExpression> changedSubAlarms,
|
||||
Map<String, AlarmSubExpression> newSubAlarms, List<String> alarmActions,
|
||||
List<String> okActions, List<String> undeterminedActions) {
|
||||
Handle h = db.open();
|
||||
|
||||
try {
|
||||
h.begin();
|
||||
h.insert(
|
||||
"update alarm_definition set name = ?, description = ?, expression = ?, match_by = ?, severity = ?, actions_enabled = ?, updated_at = NOW() where tenant_id = ? and id = ?",
|
||||
name, description, expression, matchBy == null || Iterables.isEmpty(matchBy) ? null
|
||||
: COMMA_JOINER.join(matchBy), severity, actionsEnabled, tenantId, id);
|
||||
|
||||
// Delete old sub-alarms
|
||||
if (oldSubAlarmIds != null)
|
||||
for (String oldSubAlarmId : oldSubAlarmIds)
|
||||
h.execute("delete from sub_alarm_definition where id = ?", oldSubAlarmId);
|
||||
|
||||
// Update changed sub-alarms
|
||||
if (changedSubAlarms != null)
|
||||
for (Map.Entry<String, AlarmSubExpression> entry : changedSubAlarms.entrySet()) {
|
||||
AlarmSubExpression sa = entry.getValue();
|
||||
h.execute(
|
||||
"update sub_alarm_definition set operator = ?, threshold = ?, updated_at = NOW() where id = ?",
|
||||
sa.getOperator().name(), sa.getThreshold(), entry.getKey());
|
||||
}
|
||||
|
||||
// Insert new sub-alarms
|
||||
createSubExpressions(h, id, newSubAlarms);
|
||||
|
||||
// Delete old actions
|
||||
if (patch) {
|
||||
deleteActions(h, id, AlarmState.ALARM, alarmActions);
|
||||
deleteActions(h, id, AlarmState.OK, okActions);
|
||||
deleteActions(h, id, AlarmState.UNDETERMINED, undeterminedActions);
|
||||
} else
|
||||
h.execute("delete from alarm_action where alarm_definition_id = ?", id);
|
||||
|
||||
// Insert new actions
|
||||
persistActions(h, id, AlarmState.ALARM, alarmActions);
|
||||
persistActions(h, id, AlarmState.OK, okActions);
|
||||
persistActions(h, id, AlarmState.UNDETERMINED, undeterminedActions);
|
||||
|
||||
h.commit();
|
||||
} catch (RuntimeException e) {
|
||||
h.rollback();
|
||||
throw e;
|
||||
} finally {
|
||||
h.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteActions(Handle handle, String id, AlarmState alarmState, List<String> actions) {
|
||||
if (actions != null)
|
||||
handle.execute("delete from alarm_action where alarm_definition_id = ? and alarm_state = ?", id,
|
||||
alarmState.name());
|
||||
}
|
||||
|
||||
private void persistActions(Handle handle, String id, AlarmState alarmState, List<String> actions) {
|
||||
if (actions != null)
|
||||
for (String action : actions)
|
||||
handle.insert("insert into alarm_action values (?, ?, ?)", id, alarmState.name(), action);
|
||||
}
|
||||
|
||||
private void createSubExpressions(Handle handle, String id,
|
||||
Map<String, AlarmSubExpression> alarmSubExpressions) {
|
||||
if (alarmSubExpressions != null) {
|
||||
for (Map.Entry<String, AlarmSubExpression> subEntry : alarmSubExpressions.entrySet()) {
|
||||
String subAlarmId = subEntry.getKey();
|
||||
AlarmSubExpression subExpr = subEntry.getValue();
|
||||
MetricDefinition metricDef = subExpr.getMetricDefinition();
|
||||
|
||||
// Persist sub-alarm
|
||||
handle
|
||||
.insert(
|
||||
"insert into sub_alarm_definition (id, alarm_definition_id, function, metric_name, operator, threshold, period, periods, created_at, updated_at) "
|
||||
+ "values (?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())", subAlarmId, id, subExpr
|
||||
.getFunction().name(), metricDef.name, subExpr.getOperator().name(), subExpr
|
||||
.getThreshold(), subExpr.getPeriod(), subExpr.getPeriods());
|
||||
|
||||
// Persist sub-alarm dimensions
|
||||
if (metricDef.dimensions != null && !metricDef.dimensions.isEmpty())
|
||||
for (Map.Entry<String, String> dimEntry : metricDef.dimensions.entrySet())
|
||||
handle.insert("insert into sub_alarm_definition_dimension values (?, ?, ?)", subAlarmId,
|
||||
dimEntry.getKey(), dimEntry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class AlarmDefinitionMapper implements ResultSetMapper<AlarmDefinition> {
|
||||
|
||||
private static final Splitter
|
||||
COMMA_SPLITTER =
|
||||
Splitter.on(',').omitEmptyStrings().trimResults();
|
||||
|
||||
public AlarmDefinition map(int index, ResultSet r, StatementContext ctx) throws SQLException {
|
||||
String notificationIds = r.getString("notificationIds");
|
||||
String states = r.getString("states");
|
||||
String matchBy = r.getString("match_by");
|
||||
List<String> notifications = splitStringIntoList(notificationIds);
|
||||
List<String> state = splitStringIntoList(states);
|
||||
List<String> match = splitStringIntoList(matchBy);
|
||||
|
||||
List<String> okActionIds = new ArrayList<String>();
|
||||
List<String> alarmActionIds = new ArrayList<String>();
|
||||
List<String> undeterminedActionIds = new ArrayList<String>();
|
||||
|
||||
int stateAndActionIndex = 0;
|
||||
for (String singleState : state) {
|
||||
if (singleState.equals(AlarmState.UNDETERMINED.name())) {
|
||||
undeterminedActionIds.add(notifications.get(stateAndActionIndex));
|
||||
}
|
||||
if (singleState.equals(AlarmState.OK.name())) {
|
||||
okActionIds.add(notifications.get(stateAndActionIndex));
|
||||
}
|
||||
if (singleState.equals(AlarmState.ALARM.name())) {
|
||||
alarmActionIds.add(notifications.get(stateAndActionIndex));
|
||||
}
|
||||
stateAndActionIndex++;
|
||||
}
|
||||
|
||||
return new AlarmDefinition(r.getString("id"), r.getString("name"), r.getString("description"),
|
||||
r.getString("severity"), r.getString("expression"), match,
|
||||
r.getBoolean("actions_enabled"), alarmActionIds, okActionIds,
|
||||
undeterminedActionIds);
|
||||
}
|
||||
|
||||
private List<String> splitStringIntoList(String commaDelimitedString) {
|
||||
if (commaDelimitedString == null) {
|
||||
return new ArrayList<String>();
|
||||
}
|
||||
Iterable<String> split = COMMA_SPLITTER.split(commaDelimitedString);
|
||||
return Lists.newArrayList(split);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,331 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.infrastructure.persistence.mysql;
|
||||
|
||||
import monasca.api.domain.exception.EntityNotFoundException;
|
||||
import monasca.api.domain.model.alarm.Alarm;
|
||||
import monasca.api.domain.model.alarm.AlarmRepo;
|
||||
import monasca.api.infrastructure.persistence.DimensionQueries;
|
||||
import monasca.api.infrastructure.persistence.PersistUtils;
|
||||
import monasca.common.model.alarm.AlarmState;
|
||||
import monasca.common.model.alarm.AlarmSubExpression;
|
||||
import monasca.common.model.metric.MetricDefinition;
|
||||
import monasca.common.persistence.BeanMapper;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.skife.jdbi.v2.DBI;
|
||||
import org.skife.jdbi.v2.Handle;
|
||||
import org.skife.jdbi.v2.Query;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
/**
|
||||
* Alarmed metric repository implementation.
|
||||
*/
|
||||
public class AlarmMySqlRepoImpl implements AlarmRepo {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AlarmMySqlRepoImpl.class);
|
||||
|
||||
private final DBI db;
|
||||
private final PersistUtils persistUtils;
|
||||
|
||||
private static final String ALARM_SQL =
|
||||
"select ad.id as alarm_definition_id, ad.severity, ad.name as alarm_definition_name, "
|
||||
+ "a.id, a.state, a.updated_at as state_updated_timestamp, a.created_at as created_timestamp,"
|
||||
+ "md.name as metric_name, mdg.dimensions as metric_dimensions from alarm as a "
|
||||
+ "inner join alarm_definition ad on ad.id = a.alarm_definition_id "
|
||||
+ "inner join alarm_metric as am on am.alarm_id = a.id "
|
||||
+ "inner join metric_definition_dimensions as mdd on mdd.id = am.metric_definition_dimensions_id "
|
||||
+ "inner join metric_definition as md on md.id = mdd.metric_definition_id "
|
||||
+ "left join (select dimension_set_id, name, value, group_concat(name, '=', value) as dimensions "
|
||||
+ "from metric_dimension group by dimension_set_id) as mdg on mdg.dimension_set_id = mdd.metric_dimension_set_id "
|
||||
+ "where ad.tenant_id = :tenantId and ad.deleted_at is null %s order by a.id %s";
|
||||
|
||||
@Inject
|
||||
public AlarmMySqlRepoImpl(@Named("mysql") DBI db, PersistUtils persistUtils) {
|
||||
this.db = db;
|
||||
this.persistUtils = persistUtils;
|
||||
}
|
||||
|
||||
private void buildJoinClauseFor(Map<String, String> dimensions, StringBuilder sbJoin) {
|
||||
if (dimensions == null) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < dimensions.size(); i++) {
|
||||
final String indexStr = String.valueOf(i);
|
||||
sbJoin.append(" inner join metric_dimension md").append(indexStr).append(" on md")
|
||||
.append(indexStr)
|
||||
.append(".name = :dname").append(indexStr).append(" and md").append(indexStr)
|
||||
.append(".value = :dvalue").append(indexStr)
|
||||
.append(" and mdd.metric_dimension_set_id = md")
|
||||
.append(indexStr).append(".dimension_set_id");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteById(String tenantId, String id) {
|
||||
final String sql = "delete a from alarm a where a.id = ?";
|
||||
|
||||
try (Handle h = db.open()) {
|
||||
// This will throw an EntityNotFoundException if Alarm doesn't exist or has a different tenant id
|
||||
findAlarm(tenantId, id, h);
|
||||
h.execute(sql, id);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Alarm> find(String tenantId, String alarmDefId, String metricName,
|
||||
Map<String, String> metricDimensions, AlarmState state,
|
||||
DateTime stateUpdatedStart, String offset,
|
||||
int limit, boolean enforceLimit) {
|
||||
|
||||
try (Handle h = db.open()) {
|
||||
|
||||
StringBuilder sbWhere = new StringBuilder();
|
||||
|
||||
if (alarmDefId != null) {
|
||||
sbWhere.append("and ad.id = :alarmDefId ");
|
||||
}
|
||||
if (metricName != null) {
|
||||
sbWhere.append(" and a.id in (select distinct a.id from alarm as a "
|
||||
+ "inner join alarm_metric as am on am.alarm_id = a.id "
|
||||
+ "inner join metric_definition_dimensions as mdd "
|
||||
+ " on mdd.id = am.metric_definition_dimensions_id "
|
||||
+ "inner join (select distinct id from metric_definition "
|
||||
+ " where name = :metricName) as md "
|
||||
+ "on md.id = mdd.metric_definition_id ");
|
||||
|
||||
buildJoinClauseFor(metricDimensions, sbWhere);
|
||||
|
||||
sbWhere.append(")");
|
||||
|
||||
}
|
||||
if (state != null) {
|
||||
sbWhere.append(" and a.state = :state");
|
||||
}
|
||||
if (stateUpdatedStart != null) {
|
||||
sbWhere.append(" and a.updated_at >= :stateUpdatedStart");
|
||||
}
|
||||
if (offset != null) {
|
||||
sbWhere.append(" and a.id > :offset");
|
||||
}
|
||||
|
||||
String limitPart = "";
|
||||
if (enforceLimit && limit > 0) {
|
||||
limitPart = " limit :limit";
|
||||
}
|
||||
|
||||
String sql = String.format(ALARM_SQL, sbWhere, limitPart);
|
||||
final Query<Map<String, Object>> q = h.createQuery(sql).bind("tenantId", tenantId);
|
||||
|
||||
if (alarmDefId != null) {
|
||||
q.bind("alarmDefId", alarmDefId);
|
||||
}
|
||||
if (metricName != null) {
|
||||
q.bind("metricName", metricName);
|
||||
}
|
||||
if (state != null) {
|
||||
q.bind("state", state.name());
|
||||
}
|
||||
if (stateUpdatedStart != null) {
|
||||
q.bind("stateUpdatedStart", stateUpdatedStart.toString().replace('Z', ' '));
|
||||
}
|
||||
if (offset != null) {
|
||||
q.bind("offset", offset);
|
||||
}
|
||||
|
||||
if (enforceLimit && limit > 0) {
|
||||
q.bind("limit", limit + 1);
|
||||
}
|
||||
|
||||
DimensionQueries.bindDimensionsToQuery(q, metricDimensions);
|
||||
|
||||
final long start = System.currentTimeMillis();
|
||||
final List<Map<String, Object>> rows = q.list();
|
||||
logger.debug("Query took {} milliseconds", System.currentTimeMillis() - start);
|
||||
final List<Alarm> alarms = createAlarms(tenantId, rows);
|
||||
return alarms;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Alarm findById(String tenantId, String alarmId) {
|
||||
try (Handle h = db.open()) {
|
||||
return findAlarm(tenantId, alarmId, h);
|
||||
}
|
||||
}
|
||||
|
||||
private Alarm findAlarm(String tenantId, String alarmId, Handle h) {
|
||||
final String sql = String.format(ALARM_SQL, " and a.id = :id", "");
|
||||
|
||||
final List<Map<String, Object>> rows =
|
||||
h.createQuery(sql).bind("id", alarmId).bind("tenantId", tenantId).list();
|
||||
if (rows.isEmpty()) {
|
||||
throw new EntityNotFoundException("No alarm exists for %s", alarmId);
|
||||
}
|
||||
|
||||
return createAlarms(tenantId, rows).get(0);
|
||||
}
|
||||
|
||||
private List<Alarm> createAlarms(String tenantId, List<Map<String, Object>> rows) {
|
||||
Alarm alarm = null;
|
||||
String previousAlarmId = null;
|
||||
final List<Alarm> alarms = new LinkedList<>();
|
||||
List<MetricDefinition> alarmedMetrics = null;
|
||||
for (final Map<String, Object> row : rows) {
|
||||
final String alarmId = (String) row.get("id");
|
||||
if (!alarmId.equals(previousAlarmId)) {
|
||||
alarmedMetrics = new ArrayList<>();
|
||||
alarm =
|
||||
new Alarm(alarmId, getString(row, "alarm_definition_id"), getString(row,
|
||||
"alarm_definition_name"), getString(row, "severity"), alarmedMetrics,
|
||||
AlarmState.valueOf(getString(row, "state")),
|
||||
new DateTime(((Timestamp)row.get("state_updated_timestamp")).getTime(), DateTimeZone.forID("UTC")),
|
||||
new DateTime(((Timestamp)row.get("created_timestamp")).getTime(), DateTimeZone.forID("UTC")));
|
||||
alarms.add(alarm);
|
||||
}
|
||||
previousAlarmId = alarmId;
|
||||
final Map<String, String> dimensionMap = new HashMap<>();
|
||||
|
||||
// Not all Metrics have dimensions (at least theoretically)
|
||||
if (row.containsKey("metric_dimensions")) {
|
||||
final String dimensions = getString(row, "metric_dimensions");
|
||||
if (dimensions != null && !dimensions.isEmpty()) {
|
||||
for (String dimension : dimensions.split(",")) {
|
||||
final String[] parsed_dimension = dimension.split("=");
|
||||
if (parsed_dimension.length == 2) {
|
||||
dimensionMap.put(parsed_dimension[0], parsed_dimension[1]);
|
||||
} else {
|
||||
logger
|
||||
.error("Failed to parse dimension. Dimension is malformed: {}", parsed_dimension);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
alarmedMetrics.add(new MetricDefinition(getString(row, "metric_name"), dimensionMap));
|
||||
}
|
||||
return alarms;
|
||||
}
|
||||
|
||||
private String getString(final Map<String, Object> row, String fieldName) {
|
||||
return (String) row.get(fieldName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Alarm update(String tenantId, String id, AlarmState state) {
|
||||
Handle h = db.open();
|
||||
|
||||
try {
|
||||
h.begin();
|
||||
final Alarm originalAlarm = findAlarm(tenantId, id, h);
|
||||
if (!originalAlarm.getState().equals(state)) {
|
||||
h.insert("update alarm set state = ?, updated_at = NOW() where id = ?", state.name(), id);
|
||||
}
|
||||
h.commit();
|
||||
return originalAlarm;
|
||||
} catch (RuntimeException e) {
|
||||
h.rollback();
|
||||
throw e;
|
||||
} finally {
|
||||
h.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static class SubAlarm {
|
||||
|
||||
private String id;
|
||||
private String expression;
|
||||
|
||||
public SubAlarm() {
|
||||
}
|
||||
|
||||
public SubAlarm(String id, String expression) {
|
||||
this.id = id;
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getExpression() {
|
||||
return expression;
|
||||
}
|
||||
|
||||
public void setExpression(String expression) {
|
||||
this.expression = expression;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, AlarmSubExpression> findAlarmSubExpressions(String alarmId) {
|
||||
try (Handle h = db.open()) {
|
||||
final List<SubAlarm> result = h
|
||||
.createQuery("select * from sub_alarm where alarm_id = :alarmId")
|
||||
.bind("alarmId", alarmId)
|
||||
.map(new BeanMapper<SubAlarm>(SubAlarm.class)).list();
|
||||
final Map<String, AlarmSubExpression> subAlarms = new HashMap<>(result.size());
|
||||
|
||||
for (SubAlarm row : result) {
|
||||
subAlarms.put(row.id, AlarmSubExpression.of(row.expression));
|
||||
}
|
||||
|
||||
return subAlarms;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Map<String, AlarmSubExpression>> findAlarmSubExpressionsForAlarmDefinition(
|
||||
String alarmDefinitionId) {
|
||||
|
||||
try (Handle h = db.open()) {
|
||||
final List<Map<String, Object>> rows = h
|
||||
.createQuery(
|
||||
"select sa.* from sub_alarm as sa, alarm as a where sa.alarm_id=a.id and a.alarm_definition_id = :alarmDefinitionId")
|
||||
.bind("alarmDefinitionId", alarmDefinitionId).list();
|
||||
|
||||
Map<String, Map<String, AlarmSubExpression>> subAlarms = new HashMap<>();
|
||||
for (Map<String, Object> row : rows) {
|
||||
final String alarmId = (String) row.get("alarm_id");
|
||||
Map<String, AlarmSubExpression> alarmMap = subAlarms.get(alarmId);
|
||||
if (alarmMap == null) {
|
||||
alarmMap = new HashMap<>();
|
||||
subAlarms.put(alarmId, alarmMap);
|
||||
}
|
||||
|
||||
final String id = (String) row.get("id");
|
||||
final String expression = (String) row.get("expression");
|
||||
alarmMap.put(id, AlarmSubExpression.of(expression));
|
||||
}
|
||||
|
||||
return subAlarms;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,182 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.infrastructure.persistence.mysql;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.skife.jdbi.v2.DBI;
|
||||
import org.skife.jdbi.v2.Handle;
|
||||
import org.skife.jdbi.v2.Query;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import monasca.api.domain.exception.EntityExistsException;
|
||||
import monasca.api.domain.exception.EntityNotFoundException;
|
||||
import monasca.api.domain.model.notificationmethod.NotificationMethod;
|
||||
import monasca.api.domain.model.notificationmethod.NotificationMethodRepo;
|
||||
import monasca.api.domain.model.notificationmethod.NotificationMethodType;
|
||||
import monasca.api.infrastructure.persistence.PersistUtils;
|
||||
import monasca.common.persistence.BeanMapper;
|
||||
|
||||
/**
|
||||
* Notification method repository implementation.
|
||||
*/
|
||||
public class NotificationMethodMySqlRepoImpl implements NotificationMethodRepo {
|
||||
private static final Logger LOG = LoggerFactory
|
||||
.getLogger(NotificationMethodMySqlRepoImpl.class);
|
||||
private final DBI db;
|
||||
private final PersistUtils persistUtils;
|
||||
|
||||
@Inject
|
||||
public NotificationMethodMySqlRepoImpl(@Named("mysql") DBI db, PersistUtils persistUtils) {
|
||||
this.db = db;
|
||||
this.persistUtils = persistUtils;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NotificationMethod create(String tenantId, String name,
|
||||
NotificationMethodType type, String address) {
|
||||
try (Handle h = db.open()) {
|
||||
h.begin();
|
||||
if (getNotificationIdForTenantIdAndName(h,tenantId, name) != null)
|
||||
throw new EntityExistsException(
|
||||
"Notification method %s \"%s\" already exists.", tenantId, name);
|
||||
|
||||
String id = UUID.randomUUID().toString();
|
||||
h.insert(
|
||||
"insert into notification_method (id, tenant_id, name, type, address, created_at, updated_at) values (?, ?, ?, ?, ?, NOW(), NOW())",
|
||||
id, tenantId, name, type.toString(), address);
|
||||
LOG.debug("Creating notification method {} for {}", name, tenantId);
|
||||
h.commit();
|
||||
return new NotificationMethod(id, name, type, address);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteById(String tenantId, String notificationMethodId) {
|
||||
try (Handle h = db.open()) {
|
||||
if (h.update("delete from notification_method where tenant_id = ? and id = ?", tenantId,
|
||||
notificationMethodId) == 0)
|
||||
throw new EntityNotFoundException("No notification method exists for %s",
|
||||
notificationMethodId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(String tenantId, String notificationMethodId) {
|
||||
try (Handle h = db.open()) {
|
||||
return h
|
||||
.createQuery(
|
||||
"select exists(select 1 from notification_method where tenant_id = :tenantId and id = :notificationMethodId)")
|
||||
.bind("tenantId", tenantId).bind("notificationMethodId", notificationMethodId)
|
||||
.mapTo(Boolean.TYPE).first();
|
||||
}
|
||||
}
|
||||
|
||||
private String getNotificationIdForTenantIdAndName(Handle h,String tenantId, String name) {
|
||||
Map<String, Object> map = h
|
||||
.createQuery(
|
||||
"select id from notification_method where tenant_id = :tenantId and name = :name")
|
||||
.bind("tenantId", tenantId).bind("name", name).first();
|
||||
if (map != null && !map.isEmpty()) {
|
||||
return map.get("id").toString();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<NotificationMethod> find(String tenantId, String offset, int limit) {
|
||||
|
||||
try (Handle h = db.open()) {
|
||||
|
||||
String rawQuery =
|
||||
" SELECT nm.id, nm.tenant_id, nm.name, nm.type, nm.address, nm.created_at, nm.updated_at "
|
||||
+ "FROM notification_method as nm "
|
||||
+ "WHERE tenant_id = :tenantId %1$s order by nm.id asc %2$s";
|
||||
|
||||
String offsetPart = "";
|
||||
if (offset != null) {
|
||||
offsetPart = "and nm.id > :offset";
|
||||
}
|
||||
|
||||
String limitPart = "";
|
||||
if (limit > 0) {
|
||||
limitPart = " limit :limit";
|
||||
}
|
||||
|
||||
String query = String.format(rawQuery, offsetPart, limitPart);
|
||||
|
||||
Query<?> q = h.createQuery(query);
|
||||
|
||||
q.bind("tenantId", tenantId);
|
||||
|
||||
if (offset != null) {
|
||||
q.bind("offset", offset);
|
||||
}
|
||||
|
||||
if (limit > 0) {
|
||||
q.bind("limit", limit + 1);
|
||||
}
|
||||
|
||||
return q.map(new BeanMapper<>(NotificationMethod.class)).list();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public NotificationMethod findById(String tenantId, String notificationMethodId) {
|
||||
try (Handle h = db.open()) {
|
||||
NotificationMethod notificationMethod =
|
||||
h.createQuery(
|
||||
"select * from notification_method where tenant_id = :tenantId and id = :id")
|
||||
.bind("tenantId", tenantId).bind("id", notificationMethodId)
|
||||
.map(new BeanMapper<NotificationMethod>(NotificationMethod.class)).first();
|
||||
|
||||
if (notificationMethod == null)
|
||||
throw new EntityNotFoundException("No notification method exists for %s",
|
||||
notificationMethodId);
|
||||
|
||||
return notificationMethod;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public NotificationMethod update(String tenantId, String notificationMethodId, String name,
|
||||
NotificationMethodType type, String address) {
|
||||
try (Handle h = db.open()) {
|
||||
h.begin();
|
||||
String notificationID = getNotificationIdForTenantIdAndName(h,tenantId, name);
|
||||
if (notificationID != null && !notificationID.equalsIgnoreCase(notificationMethodId)) {
|
||||
throw new EntityExistsException("Notification method %s \"%s\" already exists.",
|
||||
tenantId, name);
|
||||
}
|
||||
|
||||
if (h
|
||||
.update(
|
||||
"update notification_method set name = ?, type = ?, address = ? where tenant_id = ? and id = ?",
|
||||
name, type.name(), address, tenantId, notificationMethodId) == 0)
|
||||
throw new EntityNotFoundException("No notification method exists for %s",
|
||||
notificationMethodId);
|
||||
h.commit();
|
||||
return new NotificationMethod(notificationMethodId, name, type, address);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,123 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.infrastructure.persistence.vertica;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.joda.time.format.ISODateTimeFormat;
|
||||
import org.skife.jdbi.v2.DBI;
|
||||
import org.skife.jdbi.v2.Handle;
|
||||
import org.skife.jdbi.v2.Query;
|
||||
import org.skife.jdbi.v2.util.StringMapper;
|
||||
|
||||
import monasca.api.domain.model.alarmstatehistory.AlarmStateHistory;
|
||||
import monasca.api.domain.model.alarmstatehistory.AlarmStateHistoryRepo;
|
||||
import monasca.api.infrastructure.persistence.DimensionQueries;
|
||||
import monasca.api.infrastructure.persistence.SubAlarmDefinitionQueries;
|
||||
import monasca.common.persistence.BeanMapper;
|
||||
|
||||
/**
|
||||
* Alarm repository implementation.
|
||||
*/
|
||||
public class AlarmStateHistoryVerticaRepoImpl implements AlarmStateHistoryRepo {
|
||||
public static final DateTimeFormatter DATETIME_FORMATTER = ISODateTimeFormat.dateTimeNoMillis()
|
||||
.withZoneUTC();
|
||||
private static final String FIND_ALARMS_SQL =
|
||||
"select distinct ad.id from alarm_definition as ad "
|
||||
+ "join sub_alarm_definition sad on ad.id = sad.alarm_definition_id "
|
||||
+ "left outer join sub_alarm_definition_dimension dim on sad.id = dim.sub_alarm_definition_id%s "
|
||||
+ "where ad.tenant_id = :tenantId and ad.deleted_at is NULL";
|
||||
private static final String FIND_BY_ALARM_DEF_SQL =
|
||||
"select *, time_stamp as timestamp from MonAlarms.StateHistory "
|
||||
+ "where tenant_id = :tenantId%s order by time_stamp desc";
|
||||
|
||||
private final DBI mysql;
|
||||
private final DBI vertica;
|
||||
|
||||
@Inject
|
||||
public AlarmStateHistoryVerticaRepoImpl(@Named("mysql") DBI mysql, @Named("vertica") DBI vertica) {
|
||||
this.mysql = mysql;
|
||||
this.vertica = vertica;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AlarmStateHistory> findById(String tenantId, String alarmId, String offset, int limit) {
|
||||
|
||||
// Todo. Use offset and limit for pagination.
|
||||
|
||||
try (Handle h = vertica.open()) {
|
||||
return h
|
||||
.createQuery(
|
||||
"select alarm_id, old_state, new_state, reason, reason_data, time_stamp as timestamp from MonAlarms.StateHistory where tenant_id = :tenantId and alarm_id = :alarmId order by time_stamp desc")
|
||||
.bind("tenantId", tenantId).bind("alarmId", alarmId)
|
||||
.map(new BeanMapper<>(AlarmStateHistory.class)).list();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AlarmStateHistory> find(String tenantId, Map<String, String> dimensions,
|
||||
DateTime startTime, @Nullable DateTime endTime, @Nullable String offset, int limit) {
|
||||
|
||||
// Todo. Use offset and limit for pagination.
|
||||
|
||||
List<String> alarmIds = null;
|
||||
|
||||
// Find alarm Ids for dimensions
|
||||
try (Handle h = mysql.open()) {
|
||||
String sql = String.format(FIND_ALARMS_SQL, SubAlarmDefinitionQueries.buildJoinClauseFor(dimensions));
|
||||
Query<Map<String, Object>> query = h.createQuery(sql).bind("tenantId", tenantId);
|
||||
DimensionQueries.bindDimensionsToQuery(query, dimensions);
|
||||
alarmIds = query.map(StringMapper.FIRST).list();
|
||||
}
|
||||
|
||||
if (alarmIds == null || alarmIds.isEmpty())
|
||||
return Collections.emptyList();
|
||||
|
||||
// Find alarm state history for alarm Ids
|
||||
try (Handle h = vertica.open()) {
|
||||
// Build sql
|
||||
StringBuilder sbWhere = new StringBuilder();
|
||||
sbWhere.append(" and alarm_id in (");
|
||||
for (int i = 0; i < alarmIds.size(); i++) {
|
||||
if (i > 0)
|
||||
sbWhere.append(", ");
|
||||
sbWhere.append('\'').append(alarmIds.get(i)).append('\'');
|
||||
}
|
||||
sbWhere.append(')');
|
||||
if (startTime != null)
|
||||
sbWhere.append(" and time_stamp >= :startTime");
|
||||
if (endTime != null)
|
||||
sbWhere.append(" and time_stamp <= :endTime");
|
||||
String sql = String.format(FIND_BY_ALARM_DEF_SQL, sbWhere);
|
||||
|
||||
// Build query
|
||||
Query<Map<String, Object>> query = h.createQuery(sql).bind("tenantId", tenantId);
|
||||
if (startTime != null)
|
||||
query.bind("startTime", new Timestamp(startTime.getMillis()));
|
||||
if (endTime != null)
|
||||
query.bind("endTime", new Timestamp(endTime.getMillis()));
|
||||
DimensionQueries.bindDimensionsToQuery(query, dimensions);
|
||||
return query.map(new BeanMapper<>(AlarmStateHistory.class)).list();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.infrastructure.persistence.vertica;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.joda.time.format.ISODateTimeFormat;
|
||||
import org.skife.jdbi.v2.DBI;
|
||||
import org.skife.jdbi.v2.Handle;
|
||||
import org.skife.jdbi.v2.Query;
|
||||
|
||||
import monasca.api.domain.model.measurement.MeasurementRepo;
|
||||
import monasca.api.domain.model.measurement.Measurements;
|
||||
import monasca.api.infrastructure.persistence.DimensionQueries;
|
||||
|
||||
/**
|
||||
* Vertica measurement repository implementation.
|
||||
*/
|
||||
public class MeasurementVerticaRepoImpl implements MeasurementRepo {
|
||||
public static final DateTimeFormatter DATETIME_FORMATTER = ISODateTimeFormat.dateTimeNoMillis()
|
||||
.withZoneUTC();
|
||||
private static final String FIND_BY_METRIC_DEF_SQL =
|
||||
"select def.name, m.definition_dimensions_id, dd.dimension_set_id, m.id, m.time_stamp, m.value "
|
||||
+ "from MonMetrics.Measurements m, MonMetrics.Definitions def, MonMetrics.DefinitionDimensions dd%s "
|
||||
+ "where m.definition_dimensions_id = dd.id and def.id = dd.definition_id "
|
||||
+ "and def.tenant_id = :tenantId and m.time_stamp >= :startTime%s order by dd.id, m.time_stamp, m.id";
|
||||
|
||||
private final DBI db;
|
||||
|
||||
@Inject
|
||||
public MeasurementVerticaRepoImpl(@Named("vertica") DBI db) {
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Measurements> find(String tenantId, String name, Map<String, String> dimensions,
|
||||
DateTime startTime, @Nullable DateTime endTime, @Nullable String offset, int limit,
|
||||
Boolean mergeMetricsFlag) {
|
||||
|
||||
// Todo. Use mergeMetricsFlag.
|
||||
|
||||
// Todo. Use offset and limit for pagination.
|
||||
|
||||
try (Handle h = db.open()) {
|
||||
// Build sql
|
||||
StringBuilder sbWhere = new StringBuilder();
|
||||
if (name != null)
|
||||
sbWhere.append(" and def.name = :name");
|
||||
if (endTime != null)
|
||||
sbWhere.append(" and m.time_stamp <= :endTime");
|
||||
String sql =
|
||||
String.format(FIND_BY_METRIC_DEF_SQL, MetricQueries.buildJoinClauseFor(dimensions),
|
||||
sbWhere);
|
||||
|
||||
// Build query
|
||||
Query<Map<String, Object>> query =
|
||||
h.createQuery(sql).bind("tenantId", tenantId)
|
||||
.bind("startTime", new Timestamp(startTime.getMillis()));
|
||||
if (name != null)
|
||||
query.bind("name", name);
|
||||
if (endTime != null)
|
||||
query.bind("endTime", new Timestamp(endTime.getMillis()));
|
||||
DimensionQueries.bindDimensionsToQuery(query, dimensions);
|
||||
|
||||
// Execute query
|
||||
List<Map<String, Object>> rows = query.list();
|
||||
|
||||
// Build results
|
||||
Map<ByteBuffer, Measurements> results = new LinkedHashMap<>();
|
||||
for (Map<String, Object> row : rows) {
|
||||
String metricName = (String) row.get("name");
|
||||
byte[] defIdBytes = (byte[]) row.get("definition_dimensions_id");
|
||||
byte[] dimSetIdBytes = (byte[]) row.get("dimension_set_id");
|
||||
ByteBuffer defId = ByteBuffer.wrap(defIdBytes);
|
||||
long measurementId = (Long) row.get("id");
|
||||
String timestamp = DATETIME_FORMATTER.print(((Timestamp) row.get("time_stamp")).getTime());
|
||||
double value = (double) row.get("value");
|
||||
|
||||
Measurements measurements = results.get(defId);
|
||||
if (measurements == null) {
|
||||
measurements =
|
||||
new Measurements(metricName, MetricQueries.dimensionsFor(h, dimSetIdBytes),
|
||||
new ArrayList<Object[]>());
|
||||
results.put(defId, measurements);
|
||||
}
|
||||
|
||||
// TODO - Really support valueMeta
|
||||
measurements.addMeasurement(new Object[] {measurementId, timestamp, value, new HashMap<String, String>()});
|
||||
}
|
||||
|
||||
return new ArrayList<Measurements>(results.values());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.infrastructure.persistence.vertica;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.skife.jdbi.v2.DBI;
|
||||
import org.skife.jdbi.v2.Handle;
|
||||
import org.skife.jdbi.v2.Query;
|
||||
|
||||
import monasca.api.domain.model.metric.MetricName;
|
||||
import monasca.common.model.metric.MetricDefinition;
|
||||
import monasca.api.domain.model.metric.MetricDefinitionRepo;
|
||||
import monasca.api.infrastructure.persistence.DimensionQueries;
|
||||
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
|
||||
|
||||
/**
|
||||
* Vertica metric definition repository implementation.
|
||||
*/
|
||||
public class MetricDefinitionVerticaRepoImpl implements MetricDefinitionRepo {
|
||||
private static final String FIND_BY_METRIC_DEF_SQL =
|
||||
"select dd.id, def.name, d.name as dname, d.value as dvalue "
|
||||
+ "from MonMetrics.Definitions def, MonMetrics.DefinitionDimensions dd "
|
||||
+ "left outer join MonMetrics.Dimensions d on d.dimension_set_id = dd.dimension_set_id%s "
|
||||
+ "where def.id = dd.definition_id and def.tenant_id = :tenantId%s order by dd.id";
|
||||
|
||||
private final DBI db;
|
||||
|
||||
@Inject
|
||||
public MetricDefinitionVerticaRepoImpl(@Named("vertica") DBI db) {
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetricDefinition> find(String tenantId, String name, Map<String, String> dimensions,
|
||||
String offset, int limit) {
|
||||
|
||||
// Todo. Use offset and limit for pagination.
|
||||
|
||||
try (Handle h = db.open()) {
|
||||
// Build sql
|
||||
StringBuilder sbWhere = new StringBuilder();
|
||||
if (name != null)
|
||||
sbWhere.append(" and def.name = :name");
|
||||
String sql =
|
||||
String.format(FIND_BY_METRIC_DEF_SQL, MetricQueries.buildJoinClauseFor(dimensions),
|
||||
sbWhere);
|
||||
|
||||
// Build query
|
||||
Query<Map<String, Object>> query = h.createQuery(sql).bind("tenantId", tenantId);
|
||||
if (name != null)
|
||||
query.bind("name", name);
|
||||
DimensionQueries.bindDimensionsToQuery(query, dimensions);
|
||||
|
||||
// Execute query
|
||||
List<Map<String, Object>> rows = query.list();
|
||||
|
||||
// Build results
|
||||
List<MetricDefinition> metricDefs = new ArrayList<>(rows.size());
|
||||
byte[] currentId = null;
|
||||
Map<String, String> dims = null;
|
||||
for (Map<String, Object> row : rows) {
|
||||
byte[] defId = (byte[]) row.get("id");
|
||||
String metricName = (String) row.get("name");
|
||||
String dName = (String) row.get("dname");
|
||||
String dValue = (String) row.get("dvalue");
|
||||
|
||||
if (defId == null || !Arrays.equals(currentId, defId)) {
|
||||
currentId = defId;
|
||||
dims = new HashMap<>();
|
||||
if (dName != null && dValue != null)
|
||||
dims.put(dName, dValue);
|
||||
metricDefs.add(new MetricDefinition(metricName, dims));
|
||||
} else
|
||||
dims.put(dName, dValue);
|
||||
}
|
||||
|
||||
return metricDefs;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MetricName> findNames(String tenantId, Map<String, String> dimensions, String offset, int limit) throws Exception {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package monasca.api.infrastructure.persistence.vertica;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.skife.jdbi.v2.Handle;
|
||||
|
||||
import monasca.common.persistence.SqlQueries;
|
||||
|
||||
/**
|
||||
* Vertica utilities for building metric queries.
|
||||
*/
|
||||
final class MetricQueries {
|
||||
private MetricQueries() {}
|
||||
|
||||
static String buildJoinClauseFor(Map<String, String> dimensions) {
|
||||
StringBuilder sbJoin = null;
|
||||
if (dimensions != null) {
|
||||
sbJoin = new StringBuilder();
|
||||
for (int i = 0; i < dimensions.size(); i++)
|
||||
sbJoin.append(" inner join MonMetrics.Dimensions d").append(i).append(" on d").append(i)
|
||||
.append(".name = :dname").append(i).append(" and d").append(i)
|
||||
.append(".value = " + ":dvalue").append(i).append(" and dd.dimension_set_id = d")
|
||||
.append(i).append("" + ".dimension_set_id");
|
||||
}
|
||||
|
||||
return sbJoin == null ? "" : sbJoin.toString();
|
||||
}
|
||||
|
||||
static Map<String, String> dimensionsFor(Handle handle, byte[] dimensionSetId) {
|
||||
return SqlQueries.keyValuesFor(handle, "select name, value from MonMetrics.Dimensions "
|
||||
+ "where" + " dimension_set_id = ?", dimensionSetId);
|
||||
}
|
||||
}
|
@ -1,258 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.infrastructure.persistence.vertica;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.joda.time.format.ISODateTimeFormat;
|
||||
import org.skife.jdbi.v2.DBI;
|
||||
import org.skife.jdbi.v2.Handle;
|
||||
import org.skife.jdbi.v2.Query;
|
||||
|
||||
import monasca.api.domain.model.statistic.StatisticRepo;
|
||||
import monasca.api.domain.model.statistic.Statistics;
|
||||
import monasca.api.infrastructure.persistence.DimensionQueries;
|
||||
|
||||
/**
|
||||
* Vertica statistic repository implementation.
|
||||
*/
|
||||
public class StatisticVerticaRepoImpl implements StatisticRepo {
|
||||
public static final DateTimeFormatter DATETIME_FORMATTER = ISODateTimeFormat.dateTimeNoMillis()
|
||||
.withZoneUTC();
|
||||
private static final String FIND_BY_METRIC_DEF_SQL =
|
||||
"select dd.id, def.name, d.name as dname, d.value as dvalue "
|
||||
+ "from MonMetrics.Definitions def, MonMetrics.DefinitionDimensions dd "
|
||||
+ "left outer join MonMetrics.Dimensions d on d.dimension_set_id = dd.dimension_set_id%s "
|
||||
+ "where def.id = dd.definition_id and def.tenant_id = :tenantId%s order by dd.id";
|
||||
|
||||
private final DBI db;
|
||||
|
||||
@Inject
|
||||
public StatisticVerticaRepoImpl(@Named("vertica") DBI db) {
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Statistics> find(String tenantId, String name, Map<String, String> dimensions,
|
||||
DateTime startTime, DateTime endTime, List<String> statistics,
|
||||
int period, String offset, int limit, Boolean mergeMetricsFlag) {
|
||||
|
||||
// Todo. Use mergeMetricsFlag.
|
||||
|
||||
// Todo. Use offset and limit for pagination.
|
||||
|
||||
List<Statistics> listStats = new ArrayList<>();
|
||||
List<String> copyStatistics = createColumns(statistics);
|
||||
|
||||
try (Handle h = db.open()) {
|
||||
Map<byte[], Statistics> byteMap =
|
||||
findDefIds(h, tenantId, name, dimensions, startTime, endTime);
|
||||
|
||||
for (byte[] bufferId : byteMap.keySet()) {
|
||||
|
||||
Query<Map<String, Object>> query =
|
||||
h.createQuery(createQuery(period, startTime, endTime, statistics))
|
||||
.bind("definition_id", bufferId).bind("start_time", startTime)
|
||||
.bind("end_time", endTime);
|
||||
|
||||
// Execute
|
||||
List<Map<String, Object>> rows = query.list();
|
||||
List<Object> statisticsRow = new ArrayList<Object>();
|
||||
|
||||
for (Map<String, Object> row : rows) {
|
||||
Double sum = (Double) row.get("sum");
|
||||
Double average = (Double) row.get("avg");
|
||||
Double min = (Double) row.get("min");
|
||||
Double max = (Double) row.get("max");
|
||||
Long count = (Long) row.get("count");
|
||||
Timestamp time_stamp = (Timestamp) row.get("time_interval");
|
||||
|
||||
if (time_stamp != null) {
|
||||
statisticsRow.add(DATETIME_FORMATTER.print(time_stamp.getTime()));
|
||||
}
|
||||
|
||||
if (average != null) {
|
||||
statisticsRow.add(average);
|
||||
}
|
||||
if (count != null) {
|
||||
statisticsRow.add(count);
|
||||
}
|
||||
if (max != null) {
|
||||
statisticsRow.add(max);
|
||||
}
|
||||
if (min != null) {
|
||||
statisticsRow.add(min);
|
||||
}
|
||||
if (sum != null) {
|
||||
statisticsRow.add(sum);
|
||||
}
|
||||
byteMap.get(bufferId).addValues(statisticsRow);
|
||||
statisticsRow = new ArrayList<>();
|
||||
}
|
||||
|
||||
byteMap.get(bufferId).setColumns(copyStatistics);
|
||||
listStats.add(byteMap.get(bufferId));
|
||||
}
|
||||
}
|
||||
return listStats;
|
||||
}
|
||||
|
||||
private Map<byte[], Statistics> findDefIds(Handle h, String tenantId, String name,
|
||||
Map<String, String> dimensions, DateTime startTime, DateTime endTime) {
|
||||
List<byte[]> bytes = new ArrayList<>();
|
||||
|
||||
// Build query
|
||||
StringBuilder sbWhere = new StringBuilder();
|
||||
|
||||
if (name != null)
|
||||
sbWhere.append(" and def.name = :name");
|
||||
|
||||
String sql =
|
||||
String
|
||||
.format(FIND_BY_METRIC_DEF_SQL, MetricQueries.buildJoinClauseFor(dimensions), sbWhere);
|
||||
|
||||
Query<Map<String, Object>> query =
|
||||
h.createQuery(sql).bind("tenantId", tenantId).bind("startTime", startTime);
|
||||
|
||||
if (name != null) {
|
||||
query.bind("name", name);
|
||||
}
|
||||
|
||||
if (endTime != null) {
|
||||
query.bind("endTime", new Timestamp(endTime.getMillis()));
|
||||
}
|
||||
|
||||
DimensionQueries.bindDimensionsToQuery(query, dimensions);
|
||||
|
||||
// Execute
|
||||
List<Map<String, Object>> rows = query.list();
|
||||
|
||||
Map<byte[], Statistics> byteIdMap = new HashMap<>();
|
||||
|
||||
// Build results
|
||||
byte[] currentId = null;
|
||||
Map<String, String> dims = null;
|
||||
for (Map<String, Object> row : rows) {
|
||||
byte[] defId = (byte[]) row.get("id");
|
||||
String defName = (String) row.get("name");
|
||||
String demName = (String) row.get("dname");
|
||||
String demValue = (String) row.get("dvalue");
|
||||
|
||||
if (defId == null || !Arrays.equals(currentId, defId)) {
|
||||
currentId = defId;
|
||||
dims = new HashMap<>();
|
||||
dims.put(demName, demValue);
|
||||
|
||||
Statistics statistics = new Statistics();
|
||||
statistics.setName(defName);
|
||||
statistics.setDimensions(dims);
|
||||
byteIdMap.put(currentId, statistics);
|
||||
} else
|
||||
dims.put(demName, demValue);
|
||||
}
|
||||
|
||||
bytes.add(currentId);
|
||||
|
||||
return byteIdMap;
|
||||
}
|
||||
|
||||
List<String> createColumns(List<String> list) {
|
||||
List<String> copy = new ArrayList<>();
|
||||
for (String string : list) {
|
||||
copy.add(string);
|
||||
}
|
||||
Collections.sort(copy);
|
||||
copy.add(0, "timestamp");
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
private String createQuery(int period, DateTime startTime, DateTime endTime,
|
||||
List<String> statistics) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
builder.append("SELECT " + getColumns(statistics));
|
||||
|
||||
if (period >= 1) {
|
||||
builder.append(",MIN(time_stamp) as time_interval ");
|
||||
builder.append(" FROM (Select FLOOR((EXTRACT('epoch' from time_stamp) - ");
|
||||
builder.append(createOffset(period, startTime, endTime));
|
||||
builder.append(" AS time_slice, time_stamp, value ");
|
||||
}
|
||||
|
||||
builder.append(" FROM MonMetrics.Measurements ");
|
||||
builder.append("WHERE definition_dimensions_id = :definition_id ");
|
||||
builder.append(createWhereClause(startTime, endTime));
|
||||
|
||||
if (period >= 1) {
|
||||
builder.append(") as TimeSlices group by time_slice order by time_slice");
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private String createWhereClause(DateTime startTime, DateTime endTime) {
|
||||
String clause = "";
|
||||
if (startTime != null && endTime != null) {
|
||||
clause = "AND time_stamp >= :start_time AND time_stamp <= :end_time ";
|
||||
} else if (startTime != null) {
|
||||
clause = "AND time_stamp >= :start_time ";
|
||||
}
|
||||
return clause;
|
||||
}
|
||||
|
||||
private String createOffset(int period, DateTime startTime, DateTime endTime) {
|
||||
|
||||
StringBuilder offset = new StringBuilder();
|
||||
offset
|
||||
.append("(select mod((select extract('epoch' from time_stamp) from MonMetrics.Measurements ");
|
||||
offset.append("WHERE definition_dimensions_id = :definition_id ");
|
||||
offset.append(createWhereClause(startTime, endTime));
|
||||
offset.append("order by time_stamp limit 1");
|
||||
offset.append("),");
|
||||
offset.append(period + ")))/" + period + ")");
|
||||
|
||||
return offset.toString();
|
||||
}
|
||||
|
||||
private String getColumns(List<String> statistics) {
|
||||
StringBuilder buildColumns = new StringBuilder();
|
||||
|
||||
int size = statistics.size();
|
||||
int count = 0;
|
||||
for (String statistic : statistics) {
|
||||
if (statistic.equals("average")) {
|
||||
buildColumns.append("avg(value) as average ");
|
||||
} else {
|
||||
buildColumns.append(statistic + "(value) as " + statistic + " ");
|
||||
}
|
||||
|
||||
if (size - 1 > count) {
|
||||
buildColumns.append(",");
|
||||
}
|
||||
count++;
|
||||
}
|
||||
return buildColumns.toString();
|
||||
}
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.infrastructure.servlet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
|
||||
/**
|
||||
* Mocks authentication by converting X-Auth-Token headers to X-Tenant-Ids.
|
||||
*/
|
||||
public class MockAuthenticationFilter implements Filter {
|
||||
private static final String X_AUTH_TOKEN_HEADER = "X-Auth-Token";
|
||||
|
||||
@Override
|
||||
public void destroy() {}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||
throws IOException, ServletException {
|
||||
final HttpServletRequest req = (HttpServletRequest) request;
|
||||
HttpServletRequestWrapper wrapper = requestWrapperFor(req);
|
||||
chain.doFilter(wrapper, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {}
|
||||
|
||||
/**
|
||||
* Returns an HttpServletRequestWrapper that serves tenant id headers from request attributes.
|
||||
*/
|
||||
private HttpServletRequestWrapper requestWrapperFor(final HttpServletRequest request) {
|
||||
return new HttpServletRequestWrapper(request) {
|
||||
@Override
|
||||
public Object getAttribute(String name) {
|
||||
if (name.equalsIgnoreCase(PostAuthenticationFilter.X_TENANT_ID_HEADER)) {
|
||||
String tenantId = request.getHeader(PostAuthenticationFilter.X_TENANT_ID_HEADER);
|
||||
return tenantId == null ? request.getHeader(X_AUTH_TOKEN_HEADER) : tenantId;
|
||||
}
|
||||
if (name.equalsIgnoreCase(PostAuthenticationFilter.X_IDENTITY_STATUS_ATTRIBUTE))
|
||||
return PostAuthenticationFilter.CONFIRMED_STATUS;
|
||||
if (name.equalsIgnoreCase(PostAuthenticationFilter.X_ROLES_ATTRIBUTE))
|
||||
return "user";
|
||||
return super.getAttribute(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHeader(String name) {
|
||||
if (name.equalsIgnoreCase(PostAuthenticationFilter.X_TENANT_ID_HEADER))
|
||||
return request.getHeader(X_AUTH_TOKEN_HEADER);
|
||||
return super.getHeader(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getHeaderNames() {
|
||||
List<String> names = Collections.list(super.getHeaderNames());
|
||||
names.add(PostAuthenticationFilter.X_TENANT_ID_HEADER);
|
||||
return Collections.enumeration(names);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getHeaders(String name) {
|
||||
if (name.equalsIgnoreCase(PostAuthenticationFilter.X_TENANT_ID_HEADER)) {
|
||||
String authToken = request.getHeader(X_AUTH_TOKEN_HEADER);
|
||||
return authToken == null ? Collections.<String>emptyEnumeration() : Collections
|
||||
.enumeration(Collections.singleton(authToken));
|
||||
}
|
||||
return super.getHeaders(name);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -1,192 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.infrastructure.servlet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletRequestWrapper;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import monasca.api.infrastructure.servlet.PreAuthenticationFilter.ErrorCapturingServletResponseWrapper;
|
||||
|
||||
/**
|
||||
* Authenticates requests using header information from the CsMiddleware. Provides the X-TENANT-ID
|
||||
* servlet attribute as a request header. Intended to be added to a servlet filter chain after the
|
||||
* CsMiddleware TokenAuth filter.
|
||||
*/
|
||||
public class PostAuthenticationFilter implements Filter {
|
||||
static final String CONFIRMED_STATUS = "CONFIRMED";
|
||||
static final String X_ROLES_ATTRIBUTE = "X-ROLES";
|
||||
static final String X_MONASCA_AGENT = "X-MONASCA_AGENT";
|
||||
static final String X_IDENTITY_STATUS_ATTRIBUTE = "X-IDENTITY-STATUS";
|
||||
private static final String X_TENANT_ID_ATTRIBUTE = "X-PROJECT-ID";
|
||||
static final String X_TENANT_ID_HEADER = "X-Tenant-Id";
|
||||
static final String X_ROLES_HEADER = "X-Roles";
|
||||
|
||||
private final List<String> defaultAuthorizedRoles = new ArrayList<String>();
|
||||
private final List<String> agentAuthorizedRoles = new ArrayList<String>();
|
||||
|
||||
public PostAuthenticationFilter(List<String> defaultAuthorizedRoles,
|
||||
List<String> agentAuthorizedRoles) {
|
||||
for (String defaultRole : defaultAuthorizedRoles) {
|
||||
this.defaultAuthorizedRoles.add(defaultRole.toLowerCase());
|
||||
}
|
||||
for (String agentRole : agentAuthorizedRoles) {
|
||||
this.agentAuthorizedRoles.add(agentRole.toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
|
||||
final HttpServletRequest req = (HttpServletRequest) request;
|
||||
ErrorCapturingServletResponseWrapper res = (ErrorCapturingServletResponseWrapper) response;
|
||||
String tenantIdStr = null;
|
||||
|
||||
try {
|
||||
// According to CORS spec OPTIONS method does not pass auth info
|
||||
if (req.getMethod().equals("OPTIONS")) {
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
Object tenantId = request.getAttribute(X_TENANT_ID_ATTRIBUTE);
|
||||
|
||||
if (tenantId == null) {
|
||||
sendAuthError(res, null, null, null);
|
||||
return;
|
||||
}
|
||||
tenantIdStr = tenantId.toString();
|
||||
|
||||
boolean authenticated = isAuthenticated(req);
|
||||
boolean authorized = isAuthorized(req);
|
||||
|
||||
if (authenticated && authorized) {
|
||||
HttpServletRequestWrapper wrapper = requestWrapperFor(req);
|
||||
chain.doFilter(wrapper, response);
|
||||
return;
|
||||
}
|
||||
|
||||
if (authorized)
|
||||
sendAuthError(res, tenantIdStr, null, null);
|
||||
else
|
||||
sendAuthError(res, tenantIdStr, "Tenant is missing a required role to access this service",
|
||||
null);
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
sendAuthError(res, tenantIdStr, null, e);
|
||||
} catch (IOException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {}
|
||||
|
||||
/**
|
||||
* @return true if the request is authenticated else false
|
||||
*/
|
||||
private boolean isAuthenticated(HttpServletRequest request) {
|
||||
Object identityStatus = request.getAttribute(X_IDENTITY_STATUS_ATTRIBUTE);
|
||||
return identityStatus != null && CONFIRMED_STATUS.equalsIgnoreCase(identityStatus.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the request is authorized else false
|
||||
*/
|
||||
private boolean isAuthorized(HttpServletRequest request) {
|
||||
Object rolesFromKeystone = request.getAttribute(X_ROLES_ATTRIBUTE);
|
||||
if (rolesFromKeystone == null)
|
||||
return false;
|
||||
|
||||
boolean agentUser = false;
|
||||
for (String role : rolesFromKeystone.toString().split(",")) {
|
||||
String lowerCaseRole = role.toLowerCase();
|
||||
if ((defaultAuthorizedRoles != null) && defaultAuthorizedRoles.contains(lowerCaseRole)) {
|
||||
return true;
|
||||
}
|
||||
if ((agentAuthorizedRoles != null) && agentAuthorizedRoles.contains(lowerCaseRole)) {
|
||||
agentUser = true;
|
||||
}
|
||||
}
|
||||
if (agentUser) {
|
||||
request.setAttribute(X_MONASCA_AGENT, true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an HttpServletRequestWrapper that serves tenant id headers from request attributes.
|
||||
*/
|
||||
private HttpServletRequestWrapper requestWrapperFor(final HttpServletRequest request) {
|
||||
return new HttpServletRequestWrapper(request) {
|
||||
@Override
|
||||
public String getHeader(String name) {
|
||||
if (name.equalsIgnoreCase(X_TENANT_ID_HEADER))
|
||||
return request.getAttribute(X_TENANT_ID_ATTRIBUTE).toString();
|
||||
else if (name.equalsIgnoreCase(X_ROLES_HEADER))
|
||||
return request.getAttribute(X_ROLES_ATTRIBUTE).toString();
|
||||
return super.getHeader(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getHeaderNames() {
|
||||
List<String> names = Collections.list(super.getHeaderNames());
|
||||
names.add(X_TENANT_ID_HEADER);
|
||||
names.add(X_ROLES_HEADER);
|
||||
return Collections.enumeration(names);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getHeaders(String name) {
|
||||
if (name.equalsIgnoreCase(X_TENANT_ID_HEADER))
|
||||
return Collections.enumeration(Collections.singleton(request.getAttribute(
|
||||
X_TENANT_ID_ATTRIBUTE).toString()));
|
||||
else if (name.equalsIgnoreCase(X_ROLES_HEADER))
|
||||
return Collections.enumeration(Collections.singleton(request.getAttribute(
|
||||
X_ROLES_ATTRIBUTE).toString()));
|
||||
return super.getHeaders(name);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void sendAuthError(ErrorCapturingServletResponseWrapper response,
|
||||
@Nullable String tenantId, @Nullable String message, @Nullable Exception exception)
|
||||
throws IOException {
|
||||
response.setContentType(MediaType.APPLICATION_JSON);
|
||||
|
||||
if (message == null)
|
||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
|
||||
tenantId == null ? "Failed to authenticate request"
|
||||
: "Failed to authenticate request for " + tenantId, exception);
|
||||
else
|
||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, String.format(message, tenantId));
|
||||
}
|
||||
}
|
@ -1,134 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.infrastructure.servlet;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpServletResponseWrapper;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.eclipse.jetty.server.Response;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import monasca.api.resource.exception.Exceptions;
|
||||
import monasca.api.resource.exception.Exceptions.FaultType;
|
||||
|
||||
/**
|
||||
* Authenticates requests using header information from the CsMiddleware. Provides the X-TENANT-ID
|
||||
* servlet attribute as a request header. Intended to be added to a servlet filter chain after the
|
||||
* CsMiddleware TokenAuth filter.
|
||||
*/
|
||||
public class PreAuthenticationFilter implements Filter {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(PreAuthenticationFilter.class);
|
||||
|
||||
static class ErrorCapturingServletResponseWrapper extends HttpServletResponseWrapper {
|
||||
private int statusCode;
|
||||
private String errorMessage;
|
||||
private Exception exception;
|
||||
|
||||
public ErrorCapturingServletResponseWrapper(HttpServletResponse response) {
|
||||
super(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendError(int statusCode) throws IOException {
|
||||
this.statusCode = statusCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendError(int statusCode, String msg) throws IOException {
|
||||
this.statusCode = statusCode;
|
||||
errorMessage = msg;
|
||||
}
|
||||
|
||||
void sendError(int statusCode, String msg, Exception exception) throws IOException {
|
||||
sendError(statusCode, msg);
|
||||
this.exception = exception;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
|
||||
HttpServletResponse res = (HttpServletResponse) response;
|
||||
ErrorCapturingServletResponseWrapper responseWrapper =
|
||||
new ErrorCapturingServletResponseWrapper(res);
|
||||
|
||||
boolean caughtException = false;
|
||||
ServletOutputStream out = null;
|
||||
try {
|
||||
out = res.getOutputStream();
|
||||
chain.doFilter(request, responseWrapper);
|
||||
if (responseWrapper.statusCode != 401 && responseWrapper.statusCode != 500)
|
||||
return;
|
||||
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error while executing pre authentication filter", e);
|
||||
caughtException = true;
|
||||
}
|
||||
|
||||
try {
|
||||
res.setContentType(MediaType.APPLICATION_JSON);
|
||||
if (caughtException) {
|
||||
res.setStatus(Response.SC_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
else {
|
||||
res.setStatus(responseWrapper.statusCode);
|
||||
FaultType faultType;
|
||||
if (responseWrapper.statusCode == 500) {
|
||||
faultType = FaultType.SERVER_ERROR;
|
||||
}
|
||||
else {
|
||||
faultType = FaultType.UNAUTHORIZED;
|
||||
}
|
||||
String output = Exceptions.buildLoggedErrorMessage(faultType, responseWrapper.errorMessage,
|
||||
null, responseWrapper.exception);
|
||||
out.print(output);
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
// CSMiddleware is throwing this error for invalid tokens.
|
||||
// This problem appears to be fixed in other versions, but they are not approved yet.
|
||||
try {
|
||||
String output =
|
||||
Exceptions.buildLoggedErrorMessage(FaultType.UNAUTHORIZED, "invalid authToken", null,
|
||||
responseWrapper.exception);
|
||||
out.print(output);
|
||||
} catch (Exception x) {
|
||||
LOG.error("Error while writing failed authentication HTTP response", x);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error while writing failed authentication HTTP response", e);
|
||||
} finally {
|
||||
if (out != null)
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {}
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package monasca.api.infrastructure.servlet;
|
||||
|
||||
import monasca.api.resource.exception.Exceptions;
|
||||
import monasca.common.middleware.AuthConstants;
|
||||
|
||||
import com.sun.jersey.spi.container.ContainerRequest;
|
||||
import com.sun.jersey.spi.container.ContainerRequestFilter;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.ws.rs.core.Context;
|
||||
|
||||
import static monasca.api.infrastructure.servlet.PostAuthenticationFilter.X_MONASCA_AGENT;
|
||||
|
||||
public class RoleAuthorizationFilter implements ContainerRequestFilter {
|
||||
private static final Logger logger = LoggerFactory.getLogger
|
||||
(ContainerRequestFilter.class);
|
||||
@Context
|
||||
private HttpServletRequest httpServletRequest;
|
||||
private static final String[] VALID_MONASCA_AGENT_POST_PATHS = new String[] { "/v2.0/metrics" };
|
||||
private static final String[] VALID_MONASCA_AGENT_GET_PATHS = new String[] { "/", "/v2.0" };
|
||||
|
||||
@Override
|
||||
public ContainerRequest filter(ContainerRequest containerRequest) {
|
||||
String method = containerRequest.getMethod();
|
||||
Object isAgent = httpServletRequest.getAttribute(X_MONASCA_AGENT);
|
||||
String pathInfo = httpServletRequest.getPathInfo();
|
||||
|
||||
// X_MONASCA_AGENT is only set if the only valid role for this user is an agent role
|
||||
if (isAgent != null) {
|
||||
if (!(method.equals("POST") && validPath(pathInfo, VALID_MONASCA_AGENT_POST_PATHS)) &&
|
||||
!(method.equals("GET") && validPath(pathInfo, VALID_MONASCA_AGENT_GET_PATHS))) {
|
||||
logger.warn("User {} is missing a required role to {} on {}",
|
||||
httpServletRequest.getAttribute(AuthConstants.AUTH_USER_NAME),
|
||||
method, pathInfo);
|
||||
throw Exceptions.badRequest("User is missing a required role to perform this request");
|
||||
}
|
||||
}
|
||||
return containerRequest;
|
||||
}
|
||||
|
||||
private boolean validPath(String pathInfo, String[] paths) {
|
||||
// Make the comparison easier by getting rid of trailing slashes
|
||||
while (!pathInfo.isEmpty() && !"/".equals(pathInfo) && pathInfo.endsWith("/")) {
|
||||
pathInfo = pathInfo.substring(0, pathInfo.length() - 1);
|
||||
}
|
||||
for (final String validPath : paths) {
|
||||
if (validPath.equals(pathInfo)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,171 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.resource;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import com.codahale.metrics.annotation.Timed;
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
|
||||
import org.hibernate.validator.constraints.NotEmpty;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.validation.Valid;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.HeaderParam;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import monasca.api.app.AlarmDefinitionService;
|
||||
import monasca.api.app.command.CreateAlarmDefinitionCommand;
|
||||
import monasca.api.app.command.UpdateAlarmDefinitionCommand;
|
||||
import monasca.api.app.validation.AlarmValidation;
|
||||
import monasca.api.app.validation.Validation;
|
||||
import monasca.api.domain.model.alarmdefinition.AlarmDefinition;
|
||||
import monasca.api.domain.model.alarmdefinition.AlarmDefinitionRepo;
|
||||
import monasca.api.infrastructure.persistence.PersistUtils;
|
||||
import monasca.api.resource.annotation.PATCH;
|
||||
import monasca.common.model.alarm.AlarmExpression;
|
||||
|
||||
/**
|
||||
* Alarm definition resource implementation.
|
||||
*/
|
||||
@Path(AlarmDefinitionResource.ALARM_DEFINITIONS_PATH)
|
||||
public class AlarmDefinitionResource {
|
||||
private final AlarmDefinitionService service;
|
||||
private final AlarmDefinitionRepo repo;
|
||||
private final PersistUtils persistUtils;
|
||||
public final static String ALARM_DEFINITIONS = "alarm-definitions";
|
||||
public final static String ALARM_DEFINITIONS_PATH = "/v2.0/" + ALARM_DEFINITIONS;
|
||||
|
||||
@Inject
|
||||
public AlarmDefinitionResource(AlarmDefinitionService service,
|
||||
AlarmDefinitionRepo repo,
|
||||
PersistUtils persistUtils) {
|
||||
this.service = service;
|
||||
this.repo = repo;
|
||||
this.persistUtils = persistUtils;
|
||||
}
|
||||
|
||||
@POST
|
||||
@Timed
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response create(@Context UriInfo uriInfo, @HeaderParam("X-Tenant-Id") String tenantId,
|
||||
@Valid CreateAlarmDefinitionCommand command) {
|
||||
command.validate();
|
||||
AlarmExpression alarmExpression = AlarmValidation.validateNormalizeAndGet(command.expression);
|
||||
AlarmDefinition alarm =
|
||||
Links.hydrate(service.create(tenantId, command.name, command.description, command.severity,
|
||||
command.expression, alarmExpression, command.matchBy, command.alarmActions,
|
||||
command.okActions, command.undeterminedActions), uriInfo, false);
|
||||
return Response.created(URI.create(alarm.getId())).entity(alarm).build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Timed
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Object list(@Context UriInfo uriInfo,
|
||||
@HeaderParam("X-Tenant-Id") String tenantId, @QueryParam("name") String name,
|
||||
@QueryParam("dimensions") String dimensionsStr,
|
||||
@QueryParam("offset") String offset,
|
||||
@QueryParam("limit") String limit) throws UnsupportedEncodingException {
|
||||
Map<String, String> dimensions =
|
||||
Strings.isNullOrEmpty(dimensionsStr) ? null : Validation
|
||||
.parseAndValidateDimensions(dimensionsStr);
|
||||
|
||||
return Links.paginate(this.persistUtils.getLimit(limit),
|
||||
Links.hydrate(repo.find(tenantId, name, dimensions, offset,
|
||||
this.persistUtils.getLimit(limit)), uriInfo),
|
||||
uriInfo);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Timed
|
||||
@Path("/{alarm_definition_id}")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public AlarmDefinition get(
|
||||
@Context UriInfo uriInfo,
|
||||
@HeaderParam("X-Tenant-Id") String tenantId,
|
||||
@PathParam("alarm_definition_id") String alarmDefinitionId) {
|
||||
return Links.hydrate(repo.findById(tenantId, alarmDefinitionId), uriInfo, true);
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Timed
|
||||
@Path("/{alarm_definition_id}")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public AlarmDefinition update(@Context UriInfo uriInfo,
|
||||
@HeaderParam("X-Tenant-Id") String tenantId,
|
||||
@PathParam("alarm_definition_id") String alarmDefinitionId,
|
||||
@Valid UpdateAlarmDefinitionCommand command) {
|
||||
command.validate();
|
||||
AlarmExpression alarmExpression = AlarmValidation.validateNormalizeAndGet(command.expression);
|
||||
return Links.hydrate(service.update(tenantId, alarmDefinitionId, alarmExpression, command),
|
||||
uriInfo, true);
|
||||
}
|
||||
|
||||
@PATCH
|
||||
@Timed
|
||||
@Path("/{alarm_definition_id}")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@SuppressWarnings("unchecked")
|
||||
public AlarmDefinition patch(@Context UriInfo uriInfo,
|
||||
@HeaderParam("X-Tenant-Id") String tenantId,
|
||||
@PathParam("alarm_definition_id") String alarmDefinitionId,
|
||||
@NotEmpty Map<String, Object> fields) throws JsonMappingException {
|
||||
String name = (String) fields.get("name");
|
||||
String description = (String) fields.get("description");
|
||||
String severity = (String) fields.get("severity");
|
||||
String expression = (String) fields.get("expression");
|
||||
List<String> matchBy = (List<String>) fields.get("match_by");
|
||||
Boolean enabled = (Boolean) fields.get("actions_enabled");
|
||||
List<String> alarmActions = (List<String>) fields.get("alarm_actions");
|
||||
List<String> okActions = (List<String>) fields.get("ok_actions");
|
||||
List<String> undeterminedActions = (List<String>) fields.get("undetermined_actions");
|
||||
AlarmValidation.validate(name, description, severity, alarmActions, okActions,
|
||||
undeterminedActions);
|
||||
AlarmExpression alarmExpression =
|
||||
expression == null ? null : AlarmValidation.validateNormalizeAndGet(expression);
|
||||
|
||||
return Links.hydrate(service.patch(tenantId, alarmDefinitionId, name, description, severity,
|
||||
expression, alarmExpression, matchBy, enabled, alarmActions, okActions,
|
||||
undeterminedActions), uriInfo, true);
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Timed
|
||||
@Path("/{alarm_definition_id}")
|
||||
public void delete(@HeaderParam("X-Tenant-Id") String tenantId,
|
||||
@PathParam("alarm_definition_id") String alarmDefinitionId) {
|
||||
service.delete(tenantId, alarmDefinitionId);
|
||||
}
|
||||
}
|
@ -1,189 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.resource;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import com.codahale.metrics.annotation.Timed;
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
|
||||
import org.hibernate.validator.constraints.NotEmpty;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.validation.Valid;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.HeaderParam;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import monasca.api.app.AlarmService;
|
||||
import monasca.api.app.command.UpdateAlarmCommand;
|
||||
import monasca.api.app.validation.Validation;
|
||||
import monasca.api.domain.model.alarm.Alarm;
|
||||
import monasca.api.domain.model.alarm.AlarmRepo;
|
||||
import monasca.api.domain.model.alarmstatehistory.AlarmStateHistoryRepo;
|
||||
import monasca.api.infrastructure.persistence.PersistUtils;
|
||||
import monasca.api.resource.annotation.PATCH;
|
||||
import monasca.common.model.alarm.AlarmState;
|
||||
|
||||
/**
|
||||
* Alarm resource implementation.
|
||||
*/
|
||||
@Path("/v2.0/alarms")
|
||||
public class AlarmResource {
|
||||
private final AlarmService service;
|
||||
private final AlarmRepo repo;
|
||||
private final PersistUtils persistUtils;
|
||||
private final AlarmStateHistoryRepo stateHistoryRepo;
|
||||
|
||||
@Inject
|
||||
public AlarmResource(AlarmService service, AlarmRepo repo,
|
||||
AlarmStateHistoryRepo stateHistoryRepo,
|
||||
PersistUtils persistUtils) {
|
||||
this.service = service;
|
||||
this.repo = repo;
|
||||
this.stateHistoryRepo = stateHistoryRepo;
|
||||
this.persistUtils = persistUtils;
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Timed
|
||||
@Path("/{alarm_id}")
|
||||
public void delete(@HeaderParam("X-Tenant-Id") String tenantId,
|
||||
@PathParam("alarm_id") String alarmId) {
|
||||
service.delete(tenantId, alarmId);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Timed
|
||||
@Path("/{alarm_id}")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Alarm get(
|
||||
@Context UriInfo uriInfo,
|
||||
@HeaderParam("X-Tenant-Id") String tenantId, @PathParam("alarm_id") String alarm_id) {
|
||||
return fixAlarmLinks(uriInfo, repo.findById(tenantId, alarm_id));
|
||||
}
|
||||
|
||||
private Alarm fixAlarmLinks(UriInfo uriInfo, Alarm alarm) {
|
||||
Links.hydrate(alarm.getAlarmDefinition(), uriInfo,
|
||||
AlarmDefinitionResource.ALARM_DEFINITIONS_PATH);
|
||||
return Links.hydrate(alarm, uriInfo, true);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Timed
|
||||
@Path("/{alarm_id}/state-history")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Object getStateHistory(@Context UriInfo uriInfo,
|
||||
@HeaderParam("X-Tenant-Id") String tenantId, @PathParam("alarm_id") String alarmId,
|
||||
@QueryParam("offset") String offset,
|
||||
@QueryParam("limit") String limit)
|
||||
throws Exception {
|
||||
return Links.paginate(this.persistUtils.getLimit(limit),
|
||||
stateHistoryRepo.findById(tenantId, alarmId, offset,
|
||||
this.persistUtils.getLimit(limit)), uriInfo);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Timed
|
||||
@Path("/state-history")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Object listStateHistory(
|
||||
@Context UriInfo uriInfo,
|
||||
@HeaderParam("X-Tenant-Id") String tenantId, @QueryParam("dimensions") String dimensionsStr,
|
||||
@QueryParam("start_time") String startTimeStr, @QueryParam("end_time") String endTimeStr,
|
||||
@QueryParam("offset") String offset,
|
||||
@QueryParam("limit") String limit)
|
||||
throws Exception {
|
||||
|
||||
// Validate query parameters
|
||||
DateTime startTime = Validation.parseAndValidateDate(startTimeStr, "start_time", false);
|
||||
DateTime endTime = Validation.parseAndValidateDate(endTimeStr, "end_time", false);
|
||||
if (startTime != null)
|
||||
Validation.validateTimes(startTime, endTime);
|
||||
Map<String, String> dimensions =
|
||||
Strings.isNullOrEmpty(dimensionsStr) ? null : Validation
|
||||
.parseAndValidateDimensions(dimensionsStr);
|
||||
|
||||
return Links.paginate(this.persistUtils.getLimit(limit),
|
||||
stateHistoryRepo.find(tenantId, dimensions, startTime,
|
||||
endTime, offset, this.persistUtils.getLimit(limit)), uriInfo);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Timed
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Object list(@Context UriInfo uriInfo, @HeaderParam("X-Tenant-Id") String tenantId,
|
||||
@QueryParam("alarm_definition_id") String alarmDefId,
|
||||
@QueryParam("metric_name") String metricName,
|
||||
@QueryParam("metric_dimensions") String metricDimensionsStr,
|
||||
@QueryParam("state") AlarmState state,
|
||||
@QueryParam("state_updated_start_time") String stateUpdatedStartStr,
|
||||
@QueryParam("offset") String offset,
|
||||
@QueryParam("limit") String limit)
|
||||
throws Exception {
|
||||
|
||||
Map<String, String> metricDimensions =
|
||||
Strings.isNullOrEmpty(metricDimensionsStr) ? null : Validation
|
||||
.parseAndValidateNameAndDimensions(metricName, metricDimensionsStr, false);
|
||||
DateTime stateUpdatedStart =
|
||||
Validation.parseAndValidateDate(stateUpdatedStartStr,
|
||||
"state_updated_start_time", false);
|
||||
|
||||
final List<Alarm> alarms = repo.find(tenantId, alarmDefId, metricName, metricDimensions, state, stateUpdatedStart,
|
||||
offset, this.persistUtils.getLimit(limit), true);
|
||||
for (final Alarm alarm : alarms) {
|
||||
Links.hydrate(alarm.getAlarmDefinition(), uriInfo, AlarmDefinitionResource.ALARM_DEFINITIONS_PATH);
|
||||
}
|
||||
return Links.paginate(this.persistUtils.getLimit(limit), Links.hydrate(alarms, uriInfo), uriInfo);
|
||||
}
|
||||
|
||||
@PATCH
|
||||
@Timed
|
||||
@Path("/{alarm_id}")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Alarm patch(@Context UriInfo uriInfo, @HeaderParam("X-Tenant-Id") String tenantId,
|
||||
@PathParam("alarm_id") String alarmId, @NotEmpty Map<String, Object> fields)
|
||||
throws JsonMappingException {
|
||||
String stateStr = (String) fields.get("state");
|
||||
AlarmState state =
|
||||
stateStr == null ? null : Validation.parseAndValidate(AlarmState.class, stateStr);
|
||||
|
||||
return fixAlarmLinks(uriInfo, service.patch(tenantId, alarmId, state));
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Timed
|
||||
@Path("/{alarm_id}")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Alarm update(@Context UriInfo uriInfo, @HeaderParam("X-Tenant-Id") String tenantId,
|
||||
@PathParam("alarm_id") String alarmId, @Valid UpdateAlarmCommand command) {
|
||||
|
||||
return fixAlarmLinks(uriInfo, service.update(tenantId, alarmId, command));
|
||||
}
|
||||
}
|
@ -1,351 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.resource;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import monasca.api.ApiConfig;
|
||||
import monasca.api.domain.model.common.Paged;
|
||||
import monasca.api.domain.model.measurement.Measurements;
|
||||
import monasca.api.domain.model.statistic.Statistics;
|
||||
import monasca.common.model.domain.common.AbstractEntity;
|
||||
import monasca.api.domain.model.common.Link;
|
||||
import monasca.api.domain.model.common.Linked;
|
||||
import monasca.common.util.Injector;
|
||||
|
||||
/**
|
||||
* Utilities for working with links.
|
||||
*/
|
||||
public final class Links {
|
||||
static boolean accessedViaHttps;
|
||||
|
||||
static {
|
||||
ApiConfig config = Injector.getInstance(ApiConfig.class);
|
||||
if (config != null && config.accessedViaHttps != null)
|
||||
accessedViaHttps = config.accessedViaHttps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hydrates the {@code resources} with links for the {@code uriInfo}.
|
||||
*
|
||||
* @throws NullPointerException if {@code resource} is null
|
||||
*/
|
||||
public static <T extends AbstractEntity & Linked> List<T> hydrate(List<T> resources,
|
||||
UriInfo uriInfo, String... children) {
|
||||
Preconditions.checkNotNull(resources, "resources");
|
||||
|
||||
// Safe since this path should not be specific to a resource
|
||||
String absolutePath = prefixForHttps(uriInfo.getAbsolutePath().toString());
|
||||
for (T resource : resources)
|
||||
hydrate(resource, absolutePath, false, children);
|
||||
return resources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hydrates the {@code resource} with links for the {@code uriInfo}.
|
||||
*
|
||||
* @param resource to obtain id from
|
||||
* @param uriInfo to obtain path from
|
||||
* @throws NullPointerException if {@code resource} is null
|
||||
*/
|
||||
public static <T extends AbstractEntity & Linked> T hydrate(T resource, UriInfo uriInfo) {
|
||||
return hydrate(resource, prefixForHttps(uriInfo.getAbsolutePath().toString()), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hydrates the {@code resource} with links for the {@code uriInfo}.
|
||||
*
|
||||
* @param resource to obtain id from
|
||||
* @param uriInfo to obtain base path from
|
||||
* @param resourcePath path to type of resource
|
||||
* @throws NullPointerException if {@code resource} is null
|
||||
*/
|
||||
public static <T extends AbstractEntity & Linked> T hydrate(T resource, UriInfo uriInfo, String resourcePath) {
|
||||
return hydrate(resource, concatPaths(uriInfo.getBaseUri().toString(), resourcePath) + "/", false);
|
||||
}
|
||||
|
||||
private static String concatPaths(final String first, final String second) {
|
||||
// Check if this would cause two slashes in a row or a slash at the start
|
||||
if ((first.isEmpty() || first.endsWith("/")) && !second.isEmpty() && second.startsWith("/")) {
|
||||
return first + second.substring(1);
|
||||
}
|
||||
else {
|
||||
return first + second;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hydrates the {@code resource} with links for the {@code uriInfo}.
|
||||
*
|
||||
* @param resource to obtain id from
|
||||
* @param uriInfo to obtain path from
|
||||
* @param uriInfoForSpecificResource whether the uriInfo is for a specific resource
|
||||
* @param children child link elements to create
|
||||
* @throws NullPointerException if {@code resource} is null
|
||||
*/
|
||||
public static <T extends AbstractEntity & Linked> T hydrate(T resource, UriInfo uriInfo,
|
||||
boolean uriInfoForSpecificResource, String... children) {
|
||||
return hydrate(resource, prefixForHttps(uriInfo.getAbsolutePath().toString()),
|
||||
uriInfoForSpecificResource, children);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string that is prefixed for prefixForHttp if https is being used.
|
||||
*/
|
||||
static String prefixForHttps(String path) {
|
||||
if (accessedViaHttps && !path.toLowerCase().startsWith("https"))
|
||||
path = "https" + path.substring(path.indexOf("://"));
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hydrates the {@code resource} with links for the {@code path}.
|
||||
*
|
||||
* @throws NullPointerException if {@code resource} is null
|
||||
*/
|
||||
private static <T extends AbstractEntity & Linked> T hydrate(T resource, String path,
|
||||
boolean pathForSpecificResource, String... children) {
|
||||
Preconditions.checkNotNull(resource, "resource");
|
||||
|
||||
List<Link> links = new ArrayList<>(children.length + 1);
|
||||
if (!pathForSpecificResource) {
|
||||
boolean pathEndsInSlash = path.length() > 0 && path.charAt(path.length() - 1) == '/';
|
||||
if (!pathEndsInSlash)
|
||||
path += "/";
|
||||
path += resource.getId();
|
||||
}
|
||||
|
||||
links.add(new Link("self", path));
|
||||
for (String child : children)
|
||||
links.add(new Link(child, path + "/" + child));
|
||||
|
||||
resource.setLinks(links);
|
||||
return resource;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method handles the case that the elements list size is one greater than the
|
||||
* limit. The next link will be created automatically.
|
||||
*
|
||||
* This method also handles the case that the element size is the limit. The next
|
||||
* link will not be created.
|
||||
*
|
||||
* The convention is for methods that query the DB to request limit + 1 elements.
|
||||
*
|
||||
* Only limit number of elements will be returned.
|
||||
*
|
||||
* @param limit
|
||||
* @param elements
|
||||
* @param uriInfo
|
||||
* @return
|
||||
*/
|
||||
public static Object paginate(int limit, List<? extends AbstractEntity> elements, UriInfo uriInfo)
|
||||
throws UnsupportedEncodingException {
|
||||
|
||||
// Check for paging turned off. Happens if maxQueryLimit is not set or is set to zero.
|
||||
if (limit == 0) {
|
||||
Paged paged = new Paged();
|
||||
paged.elements = elements != null ? elements : new ArrayList<>();
|
||||
return paged;
|
||||
}
|
||||
|
||||
Paged paged = new Paged();
|
||||
|
||||
paged.links.add(getSelfLink(uriInfo));
|
||||
|
||||
if (elements != null) {
|
||||
|
||||
if (elements.size() > limit) {
|
||||
|
||||
String offset = elements.get(limit - 1).getId();
|
||||
|
||||
paged.links.add(getNextLink(offset, uriInfo));
|
||||
|
||||
// Truncate the list. Normally this will just truncate one extra element.
|
||||
elements = elements.subList(0, limit);
|
||||
}
|
||||
|
||||
paged.elements = elements;
|
||||
|
||||
} else {
|
||||
|
||||
paged.elements = new ArrayList();
|
||||
|
||||
}
|
||||
|
||||
return paged;
|
||||
|
||||
}
|
||||
|
||||
public static Object paginateMeasurements(int limit, List<Measurements> elements, UriInfo uriInfo)
|
||||
throws UnsupportedEncodingException {
|
||||
|
||||
// Check for paging turned off. Happens if maxQueryLimit is not set or is set to zero.
|
||||
if (limit == 0) {
|
||||
Paged paged = new Paged();
|
||||
paged.elements = elements != null ? elements : new ArrayList<>();
|
||||
return paged;
|
||||
}
|
||||
|
||||
Paged paged = new Paged();
|
||||
|
||||
paged.links.add(getSelfLink(uriInfo));
|
||||
|
||||
if (elements != null && !elements.isEmpty()) {
|
||||
|
||||
Measurements m = elements.get(0);
|
||||
|
||||
if (m != null) {
|
||||
|
||||
List<Object[]> l = m.getMeasurements();
|
||||
|
||||
if (l.size() > limit) {
|
||||
|
||||
String offset = (String) l.get(limit - 1)[0];
|
||||
|
||||
m.setId(offset);
|
||||
|
||||
paged.links.add(getNextLink(offset, uriInfo));
|
||||
|
||||
// Truncate the list. Normally this will just truncate one extra element.
|
||||
l = l.subList(0, limit);
|
||||
m.setMeasurements(l);
|
||||
|
||||
}
|
||||
|
||||
// Check if there are any elements.
|
||||
if (l.size() > 0) {
|
||||
// Set the id to the last date in the list.
|
||||
m.setId((String) l.get(l.size() - 1)[0]);
|
||||
}
|
||||
paged.elements = elements;
|
||||
|
||||
} else {
|
||||
|
||||
paged.elements = new ArrayList<>();
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
paged.elements = new ArrayList();
|
||||
}
|
||||
|
||||
return paged;
|
||||
|
||||
}
|
||||
|
||||
public static Object paginateStatistics(int limit, List<Statistics> elements, UriInfo uriInfo)
|
||||
throws UnsupportedEncodingException {
|
||||
|
||||
// Check for paging turned off. Happens if maxQueryLimit is not set or is set to zero.
|
||||
if (limit == 0) {
|
||||
Paged paged = new Paged();
|
||||
paged.elements = elements != null ? elements : new ArrayList<>();
|
||||
return paged;
|
||||
}
|
||||
|
||||
Paged paged = new Paged();
|
||||
|
||||
paged.links.add(getSelfLink(uriInfo));
|
||||
|
||||
if (elements != null && !elements.isEmpty()) {
|
||||
|
||||
Statistics s = elements.get(0);
|
||||
|
||||
if (s != null) {
|
||||
|
||||
List<List<Object>> l = s.getStatistics();
|
||||
|
||||
if (l.size() > limit) {
|
||||
|
||||
String offset = (String) l.get(limit - 1).get(0);
|
||||
|
||||
s.setId(offset);
|
||||
|
||||
paged.links.add(getNextLink(offset, uriInfo));
|
||||
|
||||
// Truncate the list. Normally this will just truncate one extra element.
|
||||
l = l.subList(0, limit);
|
||||
s.setStatistics(l);
|
||||
|
||||
}
|
||||
|
||||
// Check if there are any elements.
|
||||
if (l.size() > 0) {
|
||||
// Set the id to the last date in the list.
|
||||
s.setId((String) l.get(l.size() - 1).get(0));
|
||||
}
|
||||
paged.elements = elements;
|
||||
|
||||
} else {
|
||||
|
||||
paged.elements = new ArrayList<>();
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
paged.elements = new ArrayList();
|
||||
}
|
||||
|
||||
return paged;
|
||||
|
||||
}
|
||||
|
||||
private static Link getSelfLink(UriInfo uriInfo) {
|
||||
|
||||
Link selfLink = new Link();
|
||||
selfLink.rel = "self";
|
||||
selfLink.href = uriInfo.getRequestUri().toString();
|
||||
return selfLink;
|
||||
}
|
||||
|
||||
private static Link getNextLink(String offset, UriInfo uriInfo)
|
||||
throws UnsupportedEncodingException {
|
||||
|
||||
Link nextLink = new Link();
|
||||
nextLink.rel = "next";
|
||||
|
||||
// Create a new URL with the new offset.
|
||||
nextLink.href = uriInfo.getAbsolutePath().toString()
|
||||
+ "?offset=" + URLEncoder.encode(offset, "UTF-8");
|
||||
|
||||
// Add the query parms back to the URL without the original offset.
|
||||
for (String parmKey : uriInfo.getQueryParameters().keySet()) {
|
||||
|
||||
if (!parmKey.equalsIgnoreCase("offset")) {
|
||||
|
||||
List<String> parmValList = uriInfo.getQueryParameters().get(parmKey);
|
||||
for (String parmVal : parmValList) {
|
||||
|
||||
nextLink.href +=
|
||||
"&" + URLEncoder.encode(parmKey, "UTF-8") + "=" + URLEncoder.encode(parmVal, "UTF-8");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nextLink;
|
||||
}
|
||||
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.resource;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import com.codahale.metrics.annotation.Timed;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.HeaderParam;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import monasca.api.app.validation.Validation;
|
||||
import monasca.api.domain.model.measurement.MeasurementRepo;
|
||||
import monasca.api.infrastructure.persistence.PersistUtils;
|
||||
|
||||
/**
|
||||
* Measurement resource implementation.
|
||||
*/
|
||||
@Path("/v2.0/metrics/measurements")
|
||||
public class MeasurementResource {
|
||||
|
||||
private final MeasurementRepo repo;
|
||||
private final PersistUtils persistUtils;
|
||||
|
||||
@Inject
|
||||
public MeasurementResource(MeasurementRepo repo, PersistUtils persistUtils) {
|
||||
this.repo = repo;
|
||||
this.persistUtils = persistUtils;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Timed
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Object get(@Context UriInfo uriInfo, @HeaderParam("X-Tenant-Id") String tenantId,
|
||||
@QueryParam("name") String name, @QueryParam("dimensions") String dimensionsStr,
|
||||
@QueryParam("start_time") String startTimeStr,
|
||||
@QueryParam("end_time") String endTimeStr,
|
||||
@QueryParam("offset") String offset,
|
||||
@QueryParam("limit") String limit,
|
||||
@QueryParam("merge_metrics") Boolean mergeMetricsFlag)
|
||||
throws Exception {
|
||||
|
||||
// Validate query parameters
|
||||
DateTime startTime = Validation.parseAndValidateDate(startTimeStr, "start_time", true);
|
||||
DateTime endTime = Validation.parseAndValidateDate(endTimeStr, "end_time", false);
|
||||
Validation.validateTimes(startTime, endTime);
|
||||
Map<String, String>
|
||||
dimensions =
|
||||
Strings.isNullOrEmpty(dimensionsStr) ? null : Validation
|
||||
.parseAndValidateNameAndDimensions(name, dimensionsStr, true);
|
||||
|
||||
return Links.paginateMeasurements(this.persistUtils.getLimit(limit),
|
||||
repo.find(tenantId, name, dimensions, startTime, endTime,
|
||||
offset, this.persistUtils.getLimit(limit),
|
||||
mergeMetricsFlag),
|
||||
uriInfo);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,136 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.resource;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import com.codahale.metrics.annotation.Timed;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.validation.Valid;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.HeaderParam;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import monasca.api.app.MetricService;
|
||||
import monasca.api.app.command.CreateMetricCommand;
|
||||
import monasca.api.app.validation.Validation;
|
||||
import monasca.api.domain.model.metric.MetricDefinitionRepo;
|
||||
import monasca.api.infrastructure.persistence.PersistUtils;
|
||||
import monasca.api.resource.exception.Exceptions;
|
||||
import monasca.common.model.Services;
|
||||
import monasca.common.model.metric.Metric;
|
||||
|
||||
/**
|
||||
* Metric resource implementation.
|
||||
*/
|
||||
@Path("/v2.0/metrics")
|
||||
public class MetricResource {
|
||||
|
||||
private static final String MONITORING_DELEGATE_ROLE = "monitoring-delegate";
|
||||
private static final Splitter COMMA_SPLITTER = Splitter.on(',').omitEmptyStrings().trimResults();
|
||||
|
||||
private final MetricService service;
|
||||
private final MetricDefinitionRepo metricRepo;
|
||||
private final PersistUtils persistUtils;
|
||||
|
||||
@Inject
|
||||
public MetricResource(MetricService service, MetricDefinitionRepo metricRepo,
|
||||
PersistUtils persistUtils) {
|
||||
this.service = service;
|
||||
this.metricRepo = metricRepo;
|
||||
this.persistUtils = persistUtils;
|
||||
}
|
||||
|
||||
@POST
|
||||
@Timed
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void create(@Context UriInfo uriInfo, @HeaderParam("X-Tenant-Id") String tenantId,
|
||||
@HeaderParam("X-Roles") String roles,
|
||||
@QueryParam("tenant_id") String crossTenantId,
|
||||
@Valid CreateMetricCommand[] commands) {
|
||||
boolean
|
||||
isDelegate =
|
||||
!Strings.isNullOrEmpty(roles) && COMMA_SPLITTER.splitToList(roles)
|
||||
.contains(MONITORING_DELEGATE_ROLE);
|
||||
List<Metric> metrics = new ArrayList<>(commands.length);
|
||||
for (CreateMetricCommand command : commands) {
|
||||
if (!isDelegate) {
|
||||
if (command.dimensions != null) {
|
||||
String service = command.dimensions.get(Services.SERVICE_DIMENSION);
|
||||
if (service != null && Services.isReserved(service)) {
|
||||
throw Exceptions
|
||||
.forbidden("Project %s cannot POST metrics for the hpcs service", tenantId);
|
||||
}
|
||||
}
|
||||
if (!Strings.isNullOrEmpty(crossTenantId) && !crossTenantId.equals(tenantId)) {
|
||||
throw Exceptions.forbidden("Project %s cannot POST cross tenant metrics", tenantId);
|
||||
}
|
||||
}
|
||||
|
||||
command.validate();
|
||||
metrics.add(command.toMetric());
|
||||
}
|
||||
|
||||
service.create(metrics, tenantId, crossTenantId);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Timed
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Object getMetrics(@Context UriInfo uriInfo, @HeaderParam("X-Tenant-Id") String tenantId,
|
||||
@QueryParam("name") String name,
|
||||
@QueryParam("dimensions") String dimensionsStr,
|
||||
@QueryParam("offset") String offset,
|
||||
@QueryParam("limit") String limit)
|
||||
throws Exception {
|
||||
Map<String, String>
|
||||
dimensions =
|
||||
Strings.isNullOrEmpty(dimensionsStr) ? null : Validation
|
||||
.parseAndValidateNameAndDimensions(name, dimensionsStr, false);
|
||||
|
||||
return Links.paginate(this.persistUtils.getLimit(limit),
|
||||
metricRepo.find(tenantId, name, dimensions, offset, this.persistUtils.getLimit(limit)), uriInfo);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/names")
|
||||
@Timed
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Object getMetricNames(@Context UriInfo uriInfo,
|
||||
@HeaderParam("X-Tenant-Id") String tenantId,
|
||||
@QueryParam("dimensions") String dimensionsStr,
|
||||
@QueryParam("offset") String offset,
|
||||
@QueryParam("limit") String limit) throws Exception {
|
||||
Map<String, String>
|
||||
dimensions =
|
||||
Strings.isNullOrEmpty(dimensionsStr) ? null : Validation
|
||||
.parseAndValidateDimensions(dimensionsStr);
|
||||
|
||||
return Links.paginate(this.persistUtils.getLimit(limit),
|
||||
metricRepo.findNames(tenantId, dimensions, offset, this.persistUtils.getLimit(limit)), uriInfo);
|
||||
}
|
||||
}
|
@ -1,119 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.resource;
|
||||
|
||||
import com.codahale.metrics.annotation.Timed;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.validation.Valid;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.HeaderParam;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import monasca.api.app.command.CreateNotificationMethodCommand;
|
||||
import monasca.api.domain.model.notificationmethod.NotificationMethod;
|
||||
import monasca.api.domain.model.notificationmethod.NotificationMethodRepo;
|
||||
import monasca.api.infrastructure.persistence.PersistUtils;
|
||||
|
||||
/**
|
||||
* Notification Method resource implementation.
|
||||
*/
|
||||
@Path("/v2.0/notification-methods")
|
||||
public class NotificationMethodResource {
|
||||
private final NotificationMethodRepo repo;
|
||||
private final PersistUtils persistUtils;
|
||||
|
||||
@Inject
|
||||
public NotificationMethodResource(NotificationMethodRepo repo, PersistUtils persistUtils) {
|
||||
this.repo = repo;
|
||||
this.persistUtils = persistUtils;
|
||||
}
|
||||
|
||||
@POST
|
||||
@Timed
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response create(@Context UriInfo uriInfo, @HeaderParam("X-Tenant-Id") String tenantId,
|
||||
@Valid CreateNotificationMethodCommand command) {
|
||||
command.validate();
|
||||
|
||||
NotificationMethod notificationMethod =
|
||||
Links.hydrate(repo.create(tenantId, command.name, command.type, command.address), uriInfo,
|
||||
false);
|
||||
return Response.created(URI.create(notificationMethod.getId())).entity(notificationMethod)
|
||||
.build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Timed
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Object list(@Context UriInfo uriInfo, @HeaderParam("X-Tenant-Id") String tenantId,
|
||||
@QueryParam("offset") String offset,
|
||||
@QueryParam("limit") String limit) throws UnsupportedEncodingException {
|
||||
|
||||
return Links.paginate(this.persistUtils.getLimit(limit),
|
||||
Links.hydrate(repo.find(tenantId, offset,
|
||||
this.persistUtils.getLimit(limit)), uriInfo),
|
||||
uriInfo);
|
||||
|
||||
}
|
||||
|
||||
@GET
|
||||
@Timed
|
||||
@Path("/{notification_method_id}")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public NotificationMethod get(@Context UriInfo uriInfo,
|
||||
@HeaderParam("X-Tenant-Id") String tenantId,
|
||||
@PathParam("notification_method_id") String notificationMethodId) {
|
||||
return Links.hydrate(repo.findById(tenantId, notificationMethodId), uriInfo, true);
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Timed
|
||||
@Path("/{notification_method_id}")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public NotificationMethod update(@Context UriInfo uriInfo,
|
||||
@HeaderParam("X-Tenant-Id") String tenantId,
|
||||
@PathParam("notification_method_id") String notificationMethodId,
|
||||
@Valid CreateNotificationMethodCommand command) {
|
||||
command.validate();
|
||||
|
||||
return Links.hydrate(
|
||||
repo.update(tenantId, notificationMethodId, command.name, command.type, command.address),
|
||||
uriInfo, true);
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Timed
|
||||
@Path("/{notification_method_id}")
|
||||
public void delete(@HeaderParam("X-Tenant-Id") String tenantId,
|
||||
@PathParam("notification_method_id") String notificationMethodId) {
|
||||
repo.deleteById(tenantId, notificationMethodId);
|
||||
}
|
||||
}
|
@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.resource;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import com.codahale.metrics.annotation.Timed;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.DefaultValue;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.HeaderParam;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import monasca.api.app.validation.Validation;
|
||||
import monasca.api.domain.model.statistic.StatisticRepo;
|
||||
import monasca.api.infrastructure.persistence.PersistUtils;
|
||||
|
||||
// import monasca.common.util.stats.Statistics;
|
||||
|
||||
/**
|
||||
* Statistics resource implementation.
|
||||
*/
|
||||
@Path("/v2.0/metrics/statistics")
|
||||
public class StatisticResource {
|
||||
private static final Splitter COMMA_SPLITTER = Splitter.on(',').omitEmptyStrings().trimResults();
|
||||
|
||||
private final StatisticRepo repo;
|
||||
private final PersistUtils persistUtils;
|
||||
|
||||
@Inject
|
||||
public StatisticResource(StatisticRepo repo, PersistUtils persistUtils) {
|
||||
this.repo = repo;
|
||||
this.persistUtils = persistUtils;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Timed
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
|
||||
public Object get(@Context UriInfo uriInfo, @HeaderParam("X-Tenant-Id") String tenantId,
|
||||
@QueryParam("name") String name,
|
||||
@QueryParam("dimensions") String dimensionsStr,
|
||||
@QueryParam("start_time") String startTimeStr,
|
||||
@QueryParam("end_time") String endTimeStr,
|
||||
@QueryParam("statistics") String statisticsStr,
|
||||
@DefaultValue("300")
|
||||
@QueryParam("period") String periodStr,
|
||||
@QueryParam("offset") String offset,
|
||||
@QueryParam("limit") String limit,
|
||||
@QueryParam("merge_metrics") Boolean mergeMetricsFlag) throws Exception {
|
||||
|
||||
// Validate query parameters
|
||||
DateTime startTime = Validation.parseAndValidateDate(startTimeStr, "start_time", true);
|
||||
DateTime endTime = Validation.parseAndValidateDate(endTimeStr, "end_time", false);
|
||||
Validation.validateTimes(startTime, endTime);
|
||||
Validation.validateNotNullOrEmpty(statisticsStr, "statistics");
|
||||
int period = Validation.parseAndValidateNumber(periodStr, "period");
|
||||
List<String> statistics =
|
||||
Validation.parseValidateAndNormalizeStatistics(COMMA_SPLITTER.split(statisticsStr));
|
||||
Map<String, String> dimensions =
|
||||
Strings.isNullOrEmpty(dimensionsStr) ? null : Validation.parseAndValidateNameAndDimensions(
|
||||
name, dimensionsStr, true);
|
||||
|
||||
|
||||
return Links.paginateStatistics(this.persistUtils.getLimit(limit),
|
||||
repo.find(tenantId, name, dimensions, startTime, endTime,
|
||||
statistics, period, offset,
|
||||
this.persistUtils.getLimit(limit),
|
||||
mergeMetricsFlag),
|
||||
uriInfo);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.resource;
|
||||
|
||||
import com.codahale.metrics.annotation.Timed;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import monasca.api.domain.model.version.Version;
|
||||
import monasca.api.domain.model.version.VersionRepo;
|
||||
import monasca.api.infrastructure.persistence.PersistUtils;
|
||||
|
||||
/**
|
||||
* Version resource implementation.
|
||||
*/
|
||||
@Path("/")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public class VersionResource {
|
||||
private final VersionRepo repository;
|
||||
private final PersistUtils persistUtils;
|
||||
|
||||
@Inject
|
||||
public VersionResource(VersionRepo repository,
|
||||
PersistUtils persistUtils) {
|
||||
this.repository = repository;
|
||||
this.persistUtils = persistUtils;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Timed
|
||||
public Object list(@Context UriInfo uriInfo,
|
||||
@QueryParam("offset") String offset,
|
||||
@QueryParam("limit") String limit) throws UnsupportedEncodingException {
|
||||
|
||||
return Links.paginate(this.persistUtils.getLimit(limit),
|
||||
Links.hydrate(repository.find(), uriInfo), uriInfo);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Timed
|
||||
@Path("{version_id}")
|
||||
public Version get(@Context UriInfo uriInfo, @PathParam("version_id") String versionId) {
|
||||
return Links.hydrate(repository.findById(versionId), uriInfo, true);
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.resource.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import javax.ws.rs.HttpMethod;
|
||||
|
||||
@Target({ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@HttpMethod("PATCH")
|
||||
public @interface PATCH {
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.resource.exception;
|
||||
|
||||
import io.dropwizard.jersey.validation.ValidationErrorMessage;
|
||||
|
||||
import javax.validation.ConstraintViolationException;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.ext.ExceptionMapper;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
|
||||
import monasca.api.resource.exception.Exceptions.FaultType;
|
||||
|
||||
@Provider
|
||||
public class ConstraintViolationExceptionMapper implements
|
||||
ExceptionMapper<ConstraintViolationException> {
|
||||
private static final int UNPROCESSABLE_ENTITY = 422;
|
||||
|
||||
@Override
|
||||
public Response toResponse(ConstraintViolationException exception) {
|
||||
final ValidationErrorMessage message =
|
||||
new ValidationErrorMessage(exception.getConstraintViolations());
|
||||
String msg =
|
||||
message.getErrors().isEmpty() ? exception.getMessage() : message.getErrors().toString();
|
||||
return Response.status(UNPROCESSABLE_ENTITY).type(MediaType.APPLICATION_JSON)
|
||||
.entity(Exceptions.buildLoggedErrorMessage(FaultType.UNPROCESSABLE_ENTITY, msg)).build();
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.resource.exception;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import javax.ws.rs.ext.ExceptionMapper;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
|
||||
import monasca.api.domain.exception.EntityExistsException;
|
||||
import monasca.api.resource.exception.Exceptions.FaultType;
|
||||
|
||||
@Provider
|
||||
public class EntityExistsExceptionMapper implements ExceptionMapper<EntityExistsException> {
|
||||
@Override
|
||||
public Response toResponse(EntityExistsException e) {
|
||||
return Response.status(Status.CONFLICT).type(MediaType.APPLICATION_JSON)
|
||||
.entity(Exceptions.buildLoggedErrorMessage(FaultType.CONFLICT, e.getMessage())).build();
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.resource.exception;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import javax.ws.rs.ext.ExceptionMapper;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
|
||||
import monasca.api.domain.exception.EntityNotFoundException;
|
||||
import monasca.api.resource.exception.Exceptions.FaultType;
|
||||
|
||||
@Provider
|
||||
public class EntityNotFoundExceptionMapper implements ExceptionMapper<EntityNotFoundException> {
|
||||
@Override
|
||||
public Response toResponse(EntityNotFoundException e) {
|
||||
return Response.status(Status.NOT_FOUND).type(MediaType.APPLICATION_JSON)
|
||||
.entity(Exceptions.buildLoggedErrorMessage(FaultType.NOT_FOUND, e.getMessage())).build();
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.resource.exception;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
public class ErrorMessage {
|
||||
public int code;
|
||||
public String message;
|
||||
public String details;
|
||||
@JsonProperty("internal_code")
|
||||
public String internalCode;
|
||||
|
||||
ErrorMessage() {}
|
||||
|
||||
public ErrorMessage(int code, String message, String details, String internalCode) {
|
||||
Preconditions.checkNotNull(internalCode, "internalCode");
|
||||
|
||||
this.code = code;
|
||||
this.message = message == null ? "" : message;
|
||||
this.details = details == null ? "" : details;
|
||||
this.internalCode = internalCode;
|
||||
}
|
||||
}
|
@ -1,164 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.resource.exception;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
|
||||
import com.google.common.base.Splitter;
|
||||
|
||||
/**
|
||||
* Exception factory methods.
|
||||
*/
|
||||
public final class Exceptions {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Exceptions.class);
|
||||
private static final ObjectMapper OBJECT_MAPPER;
|
||||
private static final Splitter LINE_SPLITTER = Splitter.on("\n").trimResults();
|
||||
private static final Random RANDOM = new Random();
|
||||
|
||||
static {
|
||||
OBJECT_MAPPER = new ObjectMapper();
|
||||
OBJECT_MAPPER
|
||||
.setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
|
||||
}
|
||||
|
||||
public enum FaultType {
|
||||
SERVER_ERROR(Status.INTERNAL_SERVER_ERROR, true), BAD_REQUEST(Status.BAD_REQUEST, true), UNAUTHORIZED(
|
||||
Status.UNAUTHORIZED, false), NOT_FOUND(Status.NOT_FOUND, true), CONFLICT(Status.CONFLICT,
|
||||
true), UNPROCESSABLE_ENTITY(422, true), FORBIDDEN(Status.FORBIDDEN, true);
|
||||
|
||||
public final int statusCode;
|
||||
public final boolean loggable;
|
||||
|
||||
FaultType(int statusCode, boolean loggable) {
|
||||
this.statusCode = statusCode;
|
||||
this.loggable = loggable;
|
||||
}
|
||||
|
||||
FaultType(Status status, boolean loggable) {
|
||||
this.statusCode = status.getStatusCode();
|
||||
this.loggable = loggable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name().toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
private static class WebAppException extends WebApplicationException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public WebAppException(FaultType faultType, String message) {
|
||||
super(Response.status(faultType.statusCode).entity(message).type(MediaType.APPLICATION_JSON)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
private Exceptions() {}
|
||||
|
||||
public static WebApplicationException badRequest(String msg, Object... args) {
|
||||
return new WebAppException(FaultType.BAD_REQUEST, buildLoggedErrorMessage(
|
||||
FaultType.BAD_REQUEST, msg, args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and returns an error message containing an error code, and logs the message with the
|
||||
* corresponding error code.
|
||||
*/
|
||||
public static String buildLoggedErrorMessage(FaultType faultType, String message, Object... args) {
|
||||
return buildLoggedErrorMessage(faultType,
|
||||
args == null || args.length == 0 ? message : String.format(message, args), null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and returns an error message containing an error code, and logs the message with the
|
||||
* corresponding error code.
|
||||
*/
|
||||
public static String buildLoggedErrorMessage(FaultType faultType, String message,
|
||||
@Nullable String details, @Nullable Throwable exception) {
|
||||
String errorCode = Long.toHexString(RANDOM.nextLong());
|
||||
|
||||
if (faultType.loggable) {
|
||||
String withoutDetails = "{} {} - {}";
|
||||
String withDetails = "{} {} - {} {}";
|
||||
|
||||
if (details == null) {
|
||||
if (exception == null)
|
||||
LOG.error(withoutDetails, faultType.name(), errorCode, message);
|
||||
else
|
||||
LOG.error(withoutDetails, faultType.name(), errorCode, message, exception);
|
||||
} else {
|
||||
if (exception == null)
|
||||
LOG.error(withDetails, faultType.name(), errorCode, message, details);
|
||||
else
|
||||
LOG.error(withDetails, faultType.name(), errorCode, message, details, exception);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
StringBuilder str = new StringBuilder("{\"");
|
||||
str.append(faultType.toString());
|
||||
str.append("\":");
|
||||
str.append(OBJECT_MAPPER.writeValueAsString(new ErrorMessage(faultType.statusCode, message,
|
||||
details, errorCode)));
|
||||
str.append("}");
|
||||
return str.toString();
|
||||
} catch (JsonProcessingException bestEffort) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static WebApplicationException forbidden(String msg, Object... args) {
|
||||
return new WebAppException(FaultType.FORBIDDEN, buildLoggedErrorMessage(FaultType.FORBIDDEN,
|
||||
msg, args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first line off of a stacktrace message.
|
||||
*/
|
||||
public static String stripLocationFromStacktrace(String message) {
|
||||
for (String s : LINE_SPLITTER.split(message))
|
||||
return s;
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that the content of a a POSTed request entity is invalid.
|
||||
*/
|
||||
public static WebApplicationException unprocessableEntity(String msg, Object... args) {
|
||||
return new WebAppException(FaultType.UNPROCESSABLE_ENTITY, buildLoggedErrorMessage(
|
||||
FaultType.UNPROCESSABLE_ENTITY, msg, args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that the content of a a POSTed request entity is invalid.
|
||||
*/
|
||||
public static WebApplicationException unprocessableEntityDetails(String msg, String details,
|
||||
Exception exception) {
|
||||
return new WebAppException(FaultType.UNPROCESSABLE_ENTITY, buildLoggedErrorMessage(
|
||||
FaultType.UNPROCESSABLE_ENTITY, msg, details, exception));
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.resource.exception;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import javax.ws.rs.ext.ExceptionMapper;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
|
||||
import monasca.api.resource.exception.Exceptions.FaultType;
|
||||
|
||||
@Provider
|
||||
public class IllegalArgumentExceptionMapper implements ExceptionMapper<IllegalArgumentException> {
|
||||
@Override
|
||||
public Response toResponse(IllegalArgumentException e) {
|
||||
return Response.status(Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON)
|
||||
.entity(Exceptions.buildLoggedErrorMessage(FaultType.BAD_REQUEST, e.getMessage())).build();
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.resource.exception;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.ext.ExceptionMapper;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
|
||||
import monasca.api.domain.exception.InvalidEntityException;
|
||||
import monasca.api.resource.exception.Exceptions.FaultType;
|
||||
|
||||
@Provider
|
||||
public class InvalidEntityExceptionMapper implements ExceptionMapper<InvalidEntityException> {
|
||||
@Override
|
||||
public Response toResponse(InvalidEntityException e) {
|
||||
return Response.status(FaultType.BAD_REQUEST.statusCode).type(MediaType.APPLICATION_JSON)
|
||||
.entity(Exceptions.buildLoggedErrorMessage(FaultType.BAD_REQUEST, e.getMessage())).build();
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.resource.exception;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.ext.ExceptionMapper;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import monasca.api.resource.exception.Exceptions.FaultType;
|
||||
|
||||
/**
|
||||
* Adapted from Dropwizard's JsonMappingExceptionManager.
|
||||
*/
|
||||
@Provider
|
||||
public class JsonMappingExceptionManager implements ExceptionMapper<JsonMappingException> {
|
||||
@Override
|
||||
public Response toResponse(JsonMappingException exception) {
|
||||
return Response
|
||||
.status(FaultType.BAD_REQUEST.statusCode)
|
||||
.type(MediaType.APPLICATION_JSON)
|
||||
.entity(
|
||||
Exceptions.buildLoggedErrorMessage(FaultType.BAD_REQUEST,
|
||||
"Unable to process the provided JSON",
|
||||
Exceptions.stripLocationFromStacktrace(exception.getMessage()), null)).build();
|
||||
}
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.resource.exception;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import javax.ws.rs.ext.ExceptionMapper;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerationException;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import monasca.api.resource.exception.Exceptions.FaultType;
|
||||
|
||||
/**
|
||||
* Adapted from Dropwizard's JsonProcessingExceptionMapper.
|
||||
*/
|
||||
@Provider
|
||||
public class JsonProcessingExceptionMapper implements ExceptionMapper<JsonProcessingException> {
|
||||
@Override
|
||||
public Response toResponse(JsonProcessingException exception) {
|
||||
/*
|
||||
* If the error is in the JSON generation, it's a server error.
|
||||
*/
|
||||
if (exception instanceof JsonGenerationException)
|
||||
return Response
|
||||
.status(Status.INTERNAL_SERVER_ERROR)
|
||||
.type(MediaType.APPLICATION_JSON)
|
||||
.entity(
|
||||
Exceptions.buildLoggedErrorMessage(FaultType.SERVER_ERROR, "Error generating JSON",
|
||||
null, exception)).build();
|
||||
|
||||
final String message = exception.getMessage();
|
||||
|
||||
/*
|
||||
* If we can't deserialize the JSON because someone forgot a no-arg constructor, it's a server
|
||||
* error and we should inform the developer.
|
||||
*/
|
||||
if (message.startsWith("No suitable constructor found"))
|
||||
return Response
|
||||
.status(Status.INTERNAL_SERVER_ERROR)
|
||||
.type(MediaType.APPLICATION_JSON)
|
||||
.entity(
|
||||
Exceptions.buildLoggedErrorMessage(FaultType.SERVER_ERROR,
|
||||
"Unable to deserialize the provided JSON", null, exception)).build();
|
||||
|
||||
/*
|
||||
* Otherwise, it's those pesky users.
|
||||
*/
|
||||
return Response
|
||||
.status(Status.BAD_REQUEST)
|
||||
.type(MediaType.APPLICATION_JSON)
|
||||
.entity(
|
||||
Exceptions.buildLoggedErrorMessage(FaultType.BAD_REQUEST,
|
||||
"Unable to process the provided JSON",
|
||||
Exceptions.stripLocationFromStacktrace(message), exception)).build();
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.resource.exception;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.ext.ExceptionMapper;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
|
||||
import monasca.api.domain.exception.MultipleMetricsException;
|
||||
|
||||
@Provider
|
||||
public class MultipleMetricsExceptionMapper implements ExceptionMapper<MultipleMetricsException> {
|
||||
|
||||
private static final String
|
||||
MULTIPLE_METRICS_ERROR_MSG =
|
||||
"Found multiple metrics matching metric name and dimensions. "
|
||||
+ "Please refine your search criteria using a unique metric name or additional dimensions. "
|
||||
+ "Alternatively, you may specify 'merge_metrics=true' as a query param to combine "
|
||||
+ "all metrics matching search criteria into a single series.";
|
||||
|
||||
|
||||
@Override
|
||||
public Response toResponse(MultipleMetricsException exception) {
|
||||
|
||||
String details = String.format("search criteria: {metric name: %s, dimensions: %s}",
|
||||
exception.getMetricName(), exception.getDimensions());
|
||||
|
||||
return Response.status(Response.Status.CONFLICT).type(MediaType.APPLICATION_JSON).entity(
|
||||
Exceptions
|
||||
.buildLoggedErrorMessage(Exceptions.FaultType.CONFLICT, MULTIPLE_METRICS_ERROR_MSG,
|
||||
details, null)).build();
|
||||
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.resource.exception;
|
||||
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import javax.ws.rs.ext.ExceptionMapper;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
|
||||
import monasca.api.resource.exception.Exceptions.FaultType;
|
||||
|
||||
/**
|
||||
* Adapted from Dropwizard's LoggingExceptionMapper.
|
||||
*
|
||||
* @param <E> Exception type
|
||||
*/
|
||||
@Provider
|
||||
public class ThrowableExceptionMapper<E extends Throwable> implements ExceptionMapper<E> {
|
||||
@Override
|
||||
public Response toResponse(E exception) {
|
||||
if (exception instanceof WebApplicationException)
|
||||
return ((WebApplicationException) exception).getResponse();
|
||||
|
||||
return Response
|
||||
.status(Status.INTERNAL_SERVER_ERROR)
|
||||
.type(MediaType.APPLICATION_JSON)
|
||||
.entity(
|
||||
Exceptions.buildLoggedErrorMessage(FaultType.SERVER_ERROR,
|
||||
"An internal server error occurred", null, exception)).build();
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package monasca.api.resource.serialization;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import monasca.common.model.alarm.AlarmSubExpression;
|
||||
|
||||
public class SubAlarmExpressionSerializer extends JsonSerializer<AlarmSubExpression> {
|
||||
@Override
|
||||
public void serialize(AlarmSubExpression value, JsonGenerator jgen, SerializerProvider provider)
|
||||
throws IOException, JsonProcessingException {
|
||||
jgen.writeStartObject();
|
||||
jgen.writeStringField("function", value.getFunction().name());
|
||||
jgen.writeStringField("metric_name", value.getMetricDefinition().name);
|
||||
jgen.writeObjectField(
|
||||
"dimensions",
|
||||
value.getMetricDefinition().dimensions == null ? Collections.emptyMap() : value
|
||||
.getMetricDefinition().dimensions);
|
||||
jgen.writeStringField("operator", value.getOperator().name());
|
||||
jgen.writeNumberField("threshold", value.getThreshold());
|
||||
jgen.writeNumberField("period", value.getPeriod());
|
||||
jgen.writeNumberField("periods", value.getPeriods());
|
||||
jgen.writeEndObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<AlarmSubExpression> handledType() {
|
||||
return AlarmSubExpression.class;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user