├── .gitignore ├── .travis.yml ├── Gemfile ├── LICENSE ├── README.md ├── hystrix-application ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── .project ├── README.adoc ├── manual │ └── swagger.png ├── maven-package-deploy.bat ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ └── main │ ├── java │ └── de │ │ └── ahus1 │ │ └── hystrix │ │ ├── base │ │ ├── AbstractSaveAccount.java │ │ ├── Account.java │ │ ├── HystrixApplication.java │ │ ├── IBANValidator.java │ │ ├── InterruptedExceptionMapper.java │ │ ├── Message.java │ │ ├── ValidationException.java │ │ └── ValidationExceptionMapper.java │ │ ├── rest │ │ ├── HystrixFutureSaveAccount.java │ │ ├── HystrixObservableSaveAccount.java │ │ ├── HystrixSaveAccount.java │ │ └── SimpleSaveAccount.java │ │ └── util │ │ ├── HystrixSetupListener.java │ │ ├── prometheus │ │ └── PrometheusMetricsServlet.java │ │ ├── riemann │ │ └── HystrixRiemannEventNotifier.java │ │ └── zabbix │ │ ├── HystrixZabbixMetricsPublisher.java │ │ ├── HystrixZabbixMetricsPublisherCommand.java │ │ └── ZabbixCommandMetricsProvider.java │ ├── resources │ └── log4j.xml │ └── webapp │ ├── WEB-INF │ ├── ibm-web-ext.xml │ └── web.xml │ ├── index.html │ └── swagger │ ├── css │ ├── reset.css │ └── screen.css │ ├── images │ ├── explorer_icons.png │ ├── logo_small.png │ ├── pet_store_api.png │ ├── throbber.gif │ └── wordnik_api.png │ ├── index.html │ ├── lib │ ├── backbone-min.js │ ├── handlebars-1.0.0.js │ ├── highlight.7.3.pack.js │ ├── jquery-1.8.0.min.js │ ├── jquery.ba-bbq.min.js │ ├── jquery.slideto.min.js │ ├── jquery.wiggle.min.js │ ├── shred.bundle.js │ ├── shred │ │ └── content.js │ ├── swagger-oauth.js │ ├── swagger.js │ └── underscore-min.js │ ├── o2c.html │ ├── swagger-ui.js │ └── swagger-ui.min.js ├── manual ├── build.bat ├── build.sh ├── build_pdf.bat ├── manual.adoc ├── manual │ ├── dashboard_100ms.png │ ├── dashboard_10ms.png │ ├── dashboard_1500ms.png │ ├── dashboard_200ms.png │ └── dashboard_70ms.png ├── saltstack.adoc ├── update-gh-pages.sh └── vagrant.adoc └── tools ├── asciidoctor └── README.adoc ├── hystrix-dashboard ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── README.adoc ├── maven-package-deploy.bat ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ └── main │ └── webapp │ ├── index.html │ ├── js │ └── underscore-min.js │ └── monitor │ └── monitor.html ├── jmeter ├── .gitignore ├── README.adoc ├── hystrixSaveAccount.jmx ├── manual │ ├── jmeter-clean.png │ ├── jmeter-play.png │ ├── jmeter-stop.png │ └── jmeterwelcome.png ├── run-jmeter.bat └── run-jmeter.ps1 ├── maven └── README.adoc ├── riemann ├── .gitignore ├── README.adoc ├── Vagrantfile ├── manual │ └── riemann_dashboard.png └── salt │ ├── minion │ └── roots │ ├── pillar │ └── top.sls │ └── salt │ ├── _modules │ └── rvm.py │ ├── riemann │ ├── dashboard │ │ ├── conf.sls │ │ └── init.sls │ ├── files │ │ └── default │ │ │ ├── etc │ │ │ ├── init.d │ │ │ │ └── riemann-dash │ │ │ └── riemann │ │ │ │ └── riemann.config │ │ │ └── home │ │ │ └── rvm │ │ │ ├── config.rb │ │ │ ├── custom │ │ │ └── config.json │ │ │ └── riemann-dash │ └── server │ │ ├── conf.sls │ │ └── init.sls │ ├── rvm │ └── init.sls │ └── top.sls ├── tomcat ├── .gitignore ├── README.adoc ├── archaius.properties ├── files │ ├── index.jsp │ └── setenv.bat ├── manual │ └── tomcatwelcome.png ├── run-tomcat.bat └── run-tomcat.ps1 ├── travis └── README.adoc ├── turbine ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── README.adoc ├── maven-package-deploy.bat ├── mvnw ├── mvnw.cmd └── pom.xml └── zabbix ├── README.adoc ├── Vagrantfile ├── hystrix_template.xml ├── manual └── requestcount_zabbix.png └── salt ├── minion └── roots ├── pillar └── top.sls └── salt ├── LICENSE ├── apache ├── conf.sls ├── files │ └── default │ │ └── etc │ │ ├── apache2 │ │ ├── apache2.conf.jinja │ │ ├── envvars.jinja │ │ ├── mods-available │ │ │ ├── mpm_event.conf.jinja │ │ │ ├── mpm_prefork.conf.jinja │ │ │ └── mpm_worker.conf.jinja │ │ └── sites-available │ │ │ └── minimal.jinja │ │ └── logrotate.d │ │ └── minimal.jinja ├── init.sls ├── logrotate.sls ├── map.jinja ├── mod_actions.sls ├── mod_headers.sls ├── mod_mpm.sls ├── mod_pagespeed.sls ├── mod_proxy.sls ├── mod_proxy_fcgi.sls ├── mod_rewrite.sls ├── repo.sls └── users.sls ├── mysql ├── client │ ├── conf.sls │ └── init.sls ├── conf.sls ├── files │ └── default │ │ └── etc │ │ └── mysql │ │ └── only_pillar.cnf.jinja ├── map.jinja ├── python.sls └── server │ ├── conf.sls │ └── init.sls ├── php5 ├── curl.sls ├── files │ └── default │ │ └── etc │ │ ├── logrotate.d │ │ └── minimal.jinja │ │ └── php5 │ │ └── fpm │ │ └── pool.d │ │ └── minimal.jinja ├── fpm │ ├── conf.sls │ ├── init.sls │ ├── logrotate.sls │ └── repo.sls ├── gd.sls ├── init.sls ├── map.jinja ├── mysql.sls └── repo.sls ├── readme.txt ├── top.sls └── zabbix ├── agent ├── conf.sls ├── init.sls └── repo.sls ├── files └── default │ ├── etc │ ├── php.d │ │ └── zabbix.ini │ └── zabbix │ │ ├── web │ │ └── zabbix.conf.php.jinja │ │ ├── zabbix_agentd.conf.jinja │ │ └── zabbix_server.conf.jinja │ └── usr │ └── share │ └── zabbix-server-mysql │ ├── data.sql │ ├── images.sql │ └── schema.sql ├── frontend ├── conf.sls ├── init.sls └── repo.sls ├── map.jinja ├── mysql ├── conf.sls └── schema.sls ├── repo.sls ├── server ├── conf.sls ├── init.sls └── repo.sls └── users.sls /.gitignore: -------------------------------------------------------------------------------- 1 | .vagrant 2 | /eclipse 3 | /workspace 4 | /vagrant 5 | .classpath 6 | .project 7 | .settings 8 | .idea 9 | *.iml -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 1.9.3 4 | script: ./manual/build.sh 5 | after_success: ./manual/update-gh-pages.sh 6 | env: 7 | global: 8 | secure: XsGE9f9tLzIdqzKVCf6HyULznWPgw2k3Ghve+TAACsmSu1N1CpuNUdjfMS/9IdDncoP+AWV2aYZUAKImE/WyBvvXrgy8n3VpcCe13efU3fEXRkPQNBIZZOL1+/P7jeVTjX4cTe2ptemtJ2d4oFBcslJAX/c4D5HSu2/GMAfhe74= 9 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # this is used by Travis CI to build the online manual 2 | source 'https://rubygems.org' 3 | gem 'asciidoctor' 4 | gem 'coderay' 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Hystrix Examples Project 2 | =============== 3 | 4 | This is a showcase for Netflix' Hystrix. But it also shows other useful tools related to RESTful web services, load testing, monitoring and development automation. 5 | 6 | The latest new will be posted on [http://ahus1.github.io/hystrix-examples/](http://ahus1.github.io/hystrix-examples/). 7 | 8 | You can read the full tutorial at [https://ahus1.github.io/hystrix-examples/manual.html](https://ahus1.github.io/hystrix-examples/manual.html). 9 | 10 | You will also find the content of this manual in each subfolder in a `README.adoc`. 11 | 12 | Please consider contributing. 13 | 14 | Thanks! 15 | 16 | 17 | License 18 | ==== 19 | 20 | Copyright 2014 Alexander Schwartz 21 | 22 | Licensed under the Apache License, Version 2.0 (the "License"); 23 | you may not use this file except in compliance with the License. 24 | You may obtain a copy of the License at 25 | 26 | 27 | 28 | Unless required by applicable law or agreed to in writing, software 29 | distributed under the License is distributed on an "AS IS" BASIS, 30 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 31 | See the License for the specific language governing permissions and 32 | limitations under the License. 33 | 34 | -------------------------------------------------------------------------------- /hystrix-application/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /hystrix-application/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahus1/hystrix-examples/083327c17c31b57ed4a96078e0fbcf3e19f7d6b4/hystrix-application/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /hystrix-application/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.3/apache-maven-3.3.3-bin.zip -------------------------------------------------------------------------------- /hystrix-application/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | hystrix-application 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.wst.jsdt.core.javascriptValidator 10 | 11 | 12 | 13 | 14 | org.eclipse.wst.common.project.facet.core.builder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | org.eclipse.wst.validation.validationbuilder 25 | 26 | 27 | 28 | 29 | org.eclipse.m2e.core.maven2Builder 30 | 31 | 32 | 33 | 34 | 35 | org.eclipse.jem.workbench.JavaEMFNature 36 | org.eclipse.wst.common.modulecore.ModuleCoreNature 37 | org.eclipse.jdt.core.javanature 38 | org.eclipse.m2e.core.maven2Nature 39 | org.eclipse.wst.common.project.facet.core.nature 40 | org.eclipse.wst.jsdt.core.jsNature 41 | 42 | 43 | -------------------------------------------------------------------------------- /hystrix-application/README.adoc: -------------------------------------------------------------------------------- 1 | :source-highlighter: coderay 2 | :javasourcedir: src/main/java 3 | :imagesdir: manual 4 | 5 | == Writing a real application with JAX-RS 6 | 7 | === JAX-RS as a standard for enterprise RESTful web application 8 | 9 | JAX-RS is part of the JavaEE Standard. It defines how a JavaEE 10 | application needs to be structured to respond to HTTP-REST-Calls. 11 | 12 | REST calls have the following advantages: 13 | 14 | . With their JSON-interface they can be interfaced easily from JavaScript clients. 15 | . The REST API can also be easily tested for functional and load testing (see <> below). 16 | 17 | === RESTeasy as portable JAX-RS implementation 18 | 19 | http://resteasy.jboss.org/[RESTEasy] by JBoss is a portable implementation of the standard. It adds also several enterprise 20 | features like authentication and signatures. 21 | 22 | As a portable implementation I can easily deploy it to a Tomcat 23 | application server later. 24 | 25 | === Overview of classes to implement a JAX-RS service 26 | 27 | You find the example application in the folder `hystrix-application`. 28 | 29 | ==== Application as the starting point 30 | 31 | JAX-RS requires you to name all classes related to the REST part of your application. This class needs to extend `javax.ws.rs.core.Application`: 32 | 33 | [source,java,indent=0] 34 | .HystrixApplication.java 35 | ---- 36 | include::{javasourcedir}/de/ahus1/hystrix/base/HystrixApplication.java[tags=classdef] 37 | ---- 38 | 39 | This very basic setup lists the two REST endpoints `SimpleSaveAccount` and `HystrixSaveAccount` we will 40 | look at later plus two exception handlers `ValidationExceptionMapper` and `InterruptedExceptionMapper`. 41 | 42 | It also defines that the URL `/api` will be used for all JAX-RS requests relative to the application. 43 | 44 | ==== SimpleSaveAccount as REST endpoint 45 | 46 | JAX-RS requires you to name all classes related to the REST part of your application. This class needs to extend `javax.ws.rs.core.Application`: 47 | 48 | [source,java,indent=0] 49 | .SimpleSaveAccount.java 50 | ---- 51 | include::{javasourcedir}/de/ahus1/hystrix/rest/SimpleSaveAccount.java[tags=classdef] 52 | ---- 53 | 54 | This defines for the URL `/simple` relative to the application defined above how to react on `GET` and `POST` requests. 55 | 56 | A `GET`-Request will return with an empty `200 OK` response. This enables us to use a simple browser request to test the successful deployment of our application. 57 | 58 | A `POST`-Request will have a parameter of type `Account`. If the account is invalid, it will throw an exception. Otherwise it will save the account. In our sample application the save operation is a dummy implementation that does nothing. After the save returned, the response is `200 OK`. 59 | 60 | ==== ExceptionMappers to handle Exceptions 61 | 62 | Unhandled exceptions result in the application server to present a standard `500` error page that (depending on the application servers's configuration) might also include a stack trace of the application. 63 | 64 | To avoid this and to return REST-ful error messages exceptions are mapped by an `ExceptionMapper`. 65 | 66 | [source,java,indent=0] 67 | .ValidationExceptionMapper.java 68 | ---- 69 | include::{javasourcedir}/de/ahus1/hystrix/base/ValidationExceptionMapper.java[tags=classdef] 70 | ---- 71 | 72 | == Equip your application with Hystrix 73 | 74 | === Ensuring a clean start up and shut down of Hystrix 75 | 76 | When you want to run code at the start and at the end of a JEE Web application, the place for this is `@WebListener`. The servlet container will scan for classes with this annotation and run their `contextInitialized()` and `contextDestroyed()` methods. 77 | 78 | To start up Hystrix there is nothing to do; you can just go ahead and use it. 79 | 80 | I recommend a shut down of Hystrix as it starts several thread pools to do its job. Just add the line 81 | 82 | [source,java,indent=0] 83 | .HystrixSetupListener.java 84 | ---- 85 | include::{javasourcedir}/de/ahus1/hystrix/util/HystrixSetupListener.java[tags=hystrixstop] 86 | ---- 87 | 88 | As Hystrix uses Archaius as a default for runtime configuration, we should shut down it as well. 89 | 90 | [source,java,indent=0] 91 | .HystrixSetupListener.java 92 | ---- 93 | include::{javasourcedir}/de/ahus1/hystrix/util/HystrixSetupListener.java[tags=archaiusstop] 94 | ---- 95 | 96 | === Wrap external interfaces as a Hystrix Command 97 | 98 | The core of the application is now set up. To benefit from Hystrix each call needs to be wrapped as a Hystrix command. 99 | 100 | [source,java,indent=0] 101 | .HystrixSaveAccount.java 102 | ---- 103 | include::{javasourcedir}/de/ahus1/hystrix/rest/HystrixSaveAccount.java[tags=hystrix] 104 | ---- 105 | <1> constructing the wrapper 106 | <2> memorizing the parameters 107 | <3> calling the original code 108 | <4> taking care of the additional runtime exception that originates from an exception of the services, or from the resilience functionality of Hystrix 109 | 110 | When there is a problem with the Hystrix command there will be a `HystrixRuntimeException`. This will occur in two cases: 111 | 112 | . Hystrix circuit breaker or time out handler are activated. 113 | . The original command throws an exception. 114 | 115 | [TIP] 116 | If you want to handle the exceptions of your service as before, you will need to unwrap them. 117 | 118 | == Live API documentation 119 | 120 | === Swagger creates a live API at runtime 121 | 122 | http://swagger.io/[Swagger] allows you to annotate your REST endpoints. The information from the JAX-RS annotation and the Swagger annotations is collected at runtime. 123 | 124 | === Adding Swagger 125 | 126 | To add Swagger to your project, annotate your REST endpoints with `@ApiOperation` and `@Api` annotations. 127 | 128 | Add the following dependency to your Maven configuration: 129 | 130 | [source,xml,indent=0] 131 | .pom.xml 132 | ---- 133 | include::pom.xml[tags=swagger] 134 | ---- 135 | 136 | The following snipped is needed in your web configuration: 137 | 138 | [source,xml,indent=0] 139 | .web.xml 140 | ---- 141 | include::src/main/webapp/WEB-INF/web.xml[tags=swagger] 142 | ---- 143 | 144 | === Accessing the Live API 145 | 146 | The Live API will be deployed as part of the application. You can access it with your browser using the following URL: http://localhost:8080/hystrixapp/swagger/ 147 | 148 | image::swagger.png[Swagger Overview] 149 | -------------------------------------------------------------------------------- /hystrix-application/manual/swagger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahus1/hystrix-examples/083327c17c31b57ed4a96078e0fbcf3e19f7d6b4/hystrix-application/manual/swagger.png -------------------------------------------------------------------------------- /hystrix-application/maven-package-deploy.bat: -------------------------------------------------------------------------------- 1 | call %~dp0mvnw clean package cargo:redeploy 2 | -------------------------------------------------------------------------------- /hystrix-application/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | set MAVEN_CMD_LINE_ARGS=%MAVEN_CONFIG% %* 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | 121 | set WRAPPER_JAR=""%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"" 122 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 123 | 124 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS% 125 | if ERRORLEVEL 1 goto error 126 | goto end 127 | 128 | :error 129 | set ERROR_CODE=1 130 | 131 | :end 132 | @endlocal & set ERROR_CODE=%ERROR_CODE% 133 | 134 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 135 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 136 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 137 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 138 | :skipRcPost 139 | 140 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 141 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 142 | 143 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 144 | 145 | exit /B %ERROR_CODE% 146 | -------------------------------------------------------------------------------- /hystrix-application/src/main/java/de/ahus1/hystrix/base/AbstractSaveAccount.java: -------------------------------------------------------------------------------- 1 | package de.ahus1.hystrix.base; 2 | 3 | public class AbstractSaveAccount { 4 | 5 | public void saveToDatabase(Account account) { 6 | // NOP 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /hystrix-application/src/main/java/de/ahus1/hystrix/base/Account.java: -------------------------------------------------------------------------------- 1 | package de.ahus1.hystrix.base; 2 | 3 | import javax.xml.bind.annotation.XmlRootElement; 4 | 5 | @XmlRootElement 6 | public class Account { 7 | private String iban; 8 | private String bic; 9 | 10 | public String getIban() { 11 | return iban; 12 | } 13 | 14 | public void setIban(String iban) { 15 | this.iban = iban; 16 | } 17 | 18 | public String getBic() { 19 | return bic; 20 | } 21 | 22 | public void setBic(String bic) { 23 | this.bic = bic; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /hystrix-application/src/main/java/de/ahus1/hystrix/base/HystrixApplication.java: -------------------------------------------------------------------------------- 1 | package de.ahus1.hystrix.base; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | import javax.ws.rs.ApplicationPath; 7 | import javax.ws.rs.core.Application; 8 | 9 | import de.ahus1.hystrix.rest.HystrixSaveAccount; 10 | import de.ahus1.hystrix.rest.SimpleSaveAccount; 11 | 12 | // tag::classdef[] 13 | @ApplicationPath("/api") 14 | public class HystrixApplication extends Application { 15 | private Set singletons = new HashSet(); 16 | 17 | public HystrixApplication() { 18 | singletons.add(new SimpleSaveAccount()); 19 | singletons.add(new HystrixSaveAccount()); 20 | singletons.add(new ValidationExceptionMapper()); 21 | singletons.add(new InterruptedExceptionMapper()); 22 | } 23 | 24 | @Override 25 | public Set getSingletons() { 26 | return singletons; 27 | } 28 | } 29 | // end::classdef[] 30 | -------------------------------------------------------------------------------- /hystrix-application/src/main/java/de/ahus1/hystrix/base/IBANValidator.java: -------------------------------------------------------------------------------- 1 | package de.ahus1.hystrix.base; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import com.netflix.config.DynamicLongProperty; 7 | import com.netflix.config.DynamicPropertyFactory; 8 | 9 | // tag::classdef[] 10 | public class IBANValidator { 11 | 12 | private static Logger LOG = LoggerFactory.getLogger(IBANValidator.class); 13 | 14 | // tag::dynprop[] 15 | private static DynamicLongProperty timeToWait = DynamicPropertyFactory 16 | .getInstance().getLongProperty("hystrixdemo.sleep", 100); 17 | 18 | // end::dynprop[] 19 | 20 | public static synchronized boolean isValid(Account account) 21 | throws InterruptedException { 22 | if (Thread.currentThread().isInterrupted()) { 23 | throw new InterruptedException(); 24 | } 25 | long t = timeToWait.get(); 26 | LOG.info("waiting {} ms", t); 27 | if (t > 0) { 28 | Thread.sleep(t); 29 | } 30 | return true; 31 | } 32 | } 33 | // end::classdef[] -------------------------------------------------------------------------------- /hystrix-application/src/main/java/de/ahus1/hystrix/base/InterruptedExceptionMapper.java: -------------------------------------------------------------------------------- 1 | package de.ahus1.hystrix.base; 2 | 3 | import javax.ws.rs.core.Context; 4 | import javax.ws.rs.core.HttpHeaders; 5 | import javax.ws.rs.core.Response; 6 | import javax.ws.rs.core.Response.Status; 7 | import javax.ws.rs.ext.ExceptionMapper; 8 | import javax.ws.rs.ext.Provider; 9 | 10 | @Provider 11 | public class InterruptedExceptionMapper implements 12 | ExceptionMapper { 13 | 14 | @Context 15 | private HttpHeaders headers; 16 | 17 | @Override 18 | public Response toResponse(InterruptedException e) { 19 | return Response.status(Status.INTERNAL_SERVER_ERROR) 20 | .entity(new Message(e.getMessage())) 21 | .type(headers.getMediaType()).build(); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /hystrix-application/src/main/java/de/ahus1/hystrix/base/Message.java: -------------------------------------------------------------------------------- 1 | package de.ahus1.hystrix.base; 2 | 3 | import javax.xml.bind.annotation.XmlRootElement; 4 | 5 | @XmlRootElement 6 | public class Message { 7 | private String message; 8 | 9 | public Message() { 10 | // no-arg constructor to satisfy JAXB 11 | } 12 | 13 | public Message(String message) { 14 | this.message = message; 15 | } 16 | 17 | public String getMessage() { 18 | return message; 19 | } 20 | 21 | public void setMessage(String message) { 22 | this.message = message; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /hystrix-application/src/main/java/de/ahus1/hystrix/base/ValidationException.java: -------------------------------------------------------------------------------- 1 | package de.ahus1.hystrix.base; 2 | 3 | public class ValidationException extends Exception { 4 | 5 | public ValidationException(String string) { 6 | super(string); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /hystrix-application/src/main/java/de/ahus1/hystrix/base/ValidationExceptionMapper.java: -------------------------------------------------------------------------------- 1 | package de.ahus1.hystrix.base; 2 | 3 | import javax.ws.rs.core.Context; 4 | import javax.ws.rs.core.HttpHeaders; 5 | import javax.ws.rs.core.Response; 6 | import javax.ws.rs.core.Response.Status; 7 | import javax.ws.rs.ext.ExceptionMapper; 8 | import javax.ws.rs.ext.Provider; 9 | 10 | // tag::classdef[] 11 | @Provider 12 | public class ValidationExceptionMapper implements 13 | ExceptionMapper { 14 | 15 | @Context 16 | private HttpHeaders headers; 17 | 18 | @Override 19 | public Response toResponse(ValidationException e) { 20 | return Response.status(Status.BAD_REQUEST) 21 | .entity(new Message(e.getMessage())) 22 | .type(headers.getMediaType()).build(); 23 | } 24 | 25 | } 26 | // end::classdef[] 27 | -------------------------------------------------------------------------------- /hystrix-application/src/main/java/de/ahus1/hystrix/rest/HystrixFutureSaveAccount.java: -------------------------------------------------------------------------------- 1 | package de.ahus1.hystrix.rest; 2 | 3 | import java.util.concurrent.ExecutionException; 4 | import java.util.concurrent.Future; 5 | 6 | import javax.ws.rs.POST; 7 | import javax.ws.rs.Path; 8 | import javax.ws.rs.core.Response; 9 | import javax.ws.rs.core.Response.Status; 10 | 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import com.netflix.hystrix.HystrixCommand; 15 | import com.netflix.hystrix.HystrixCommandGroupKey; 16 | import com.wordnik.swagger.annotations.Api; 17 | import com.wordnik.swagger.annotations.ApiOperation; 18 | 19 | import de.ahus1.hystrix.base.AbstractSaveAccount; 20 | import de.ahus1.hystrix.base.Account; 21 | import de.ahus1.hystrix.base.IBANValidator; 22 | import de.ahus1.hystrix.base.ValidationException; 23 | 24 | @Path("/future") 25 | @Api("/future") 26 | public class HystrixFutureSaveAccount extends AbstractSaveAccount { 27 | 28 | private static Logger LOG = LoggerFactory 29 | .getLogger(HystrixFutureSaveAccount.class); 30 | 31 | private static class IBANValidatorCommand extends HystrixCommand { 32 | private Account account; 33 | 34 | protected IBANValidatorCommand(Account account) { 35 | super(Setter.withGroupKey(HystrixCommandGroupKey.Factory 36 | .asKey("iban"))); 37 | this.account = account; 38 | } 39 | 40 | @Override 41 | protected Boolean run() throws Exception { 42 | return IBANValidator.isValid(account); 43 | } 44 | 45 | } 46 | 47 | @POST 48 | @Path("/future") 49 | @ApiOperation("save account data") 50 | public Response saveFuture(Account account) throws ValidationException, 51 | InterruptedException, ExecutionException { 52 | 53 | Future result = new IBANValidatorCommand(account).queue(); 54 | if (result.isDone()) { 55 | // yeah! 56 | } 57 | if (!result.get()) { 58 | throw new ValidationException("invalid"); 59 | } 60 | 61 | super.saveToDatabase(account); 62 | return Response.status(Status.OK).build(); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /hystrix-application/src/main/java/de/ahus1/hystrix/rest/HystrixObservableSaveAccount.java: -------------------------------------------------------------------------------- 1 | package de.ahus1.hystrix.rest; 2 | 3 | import java.util.List; 4 | 5 | import javax.ws.rs.POST; 6 | import javax.ws.rs.Path; 7 | import javax.ws.rs.core.Response; 8 | import javax.ws.rs.core.Response.Status; 9 | 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import rx.Observable; 14 | import rx.Subscriber; 15 | import rx.functions.Action1; 16 | 17 | import com.netflix.hystrix.HystrixCommandGroupKey; 18 | import com.netflix.hystrix.HystrixObservableCommand; 19 | import com.wordnik.swagger.annotations.Api; 20 | import com.wordnik.swagger.annotations.ApiOperation; 21 | 22 | import de.ahus1.hystrix.base.AbstractSaveAccount; 23 | import de.ahus1.hystrix.base.Account; 24 | import de.ahus1.hystrix.base.IBANValidator; 25 | import de.ahus1.hystrix.base.ValidationException; 26 | 27 | @Path("/observable") 28 | @Api("/observable") 29 | public class HystrixObservableSaveAccount extends AbstractSaveAccount { 30 | 31 | private static Logger LOG = LoggerFactory 32 | .getLogger(HystrixObservableSaveAccount.class); 33 | 34 | private static class IBANValidatorCommand extends 35 | HystrixObservableCommand { 36 | private List accounts; 37 | 38 | protected IBANValidatorCommand(List accounts) { 39 | super(Setter.withGroupKey(HystrixCommandGroupKey.Factory 40 | .asKey("iban"))); 41 | this.accounts = accounts; 42 | } 43 | 44 | @Override 45 | protected Observable construct() { 46 | return Observable.create(new Observable.OnSubscribe() { 47 | @Override 48 | public void call(Subscriber observer) { 49 | try { 50 | if (!observer.isUnsubscribed()) { 51 | for (Account account : accounts) { 52 | observer.onNext(IBANValidator.isValid(account)); 53 | } 54 | observer.onCompleted(); 55 | } 56 | } catch (Exception e) { 57 | observer.onError(e); 58 | } 59 | } 60 | 61 | }); 62 | } 63 | } 64 | 65 | @POST 66 | @Path("/observable") 67 | @ApiOperation("save account data") 68 | public Response nonsenseObservable(List accounts) 69 | throws ValidationException, InterruptedException { 70 | 71 | Observable result = 72 | new IBANValidatorCommand(accounts).observe(); 73 | 74 | result.subscribe(new Action1() { 75 | @Override 76 | public void call(Boolean b) { 77 | LOG.info("say hi to b:" + b); 78 | } 79 | }); 80 | 81 | result.subscribe(b -> LOG.info("say hi to b:" + b)); 82 | 83 | return Response.status(Status.OK).build(); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /hystrix-application/src/main/java/de/ahus1/hystrix/rest/HystrixSaveAccount.java: -------------------------------------------------------------------------------- 1 | package de.ahus1.hystrix.rest; 2 | 3 | import javax.ws.rs.GET; 4 | import javax.ws.rs.POST; 5 | import javax.ws.rs.Path; 6 | import javax.ws.rs.Produces; 7 | import javax.ws.rs.core.Response; 8 | import javax.ws.rs.core.Response.Status; 9 | 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import com.netflix.hystrix.HystrixCommand; 14 | import com.netflix.hystrix.HystrixCommandGroupKey; 15 | import com.netflix.hystrix.exception.HystrixRuntimeException; 16 | import com.wordnik.swagger.annotations.Api; 17 | import com.wordnik.swagger.annotations.ApiOperation; 18 | 19 | import de.ahus1.hystrix.base.AbstractSaveAccount; 20 | import de.ahus1.hystrix.base.Account; 21 | import de.ahus1.hystrix.base.IBANValidator; 22 | import de.ahus1.hystrix.base.ValidationException; 23 | 24 | @Path("/hystrix") 25 | @Api("/hystrix") 26 | public class HystrixSaveAccount extends AbstractSaveAccount { 27 | 28 | private static Logger LOG = LoggerFactory 29 | .getLogger(HystrixSaveAccount.class); 30 | 31 | @GET 32 | @Produces("text/plain") 33 | @ApiOperation("simple hello") 34 | public Response hello() { 35 | return Response.status(Status.OK).entity("Hello world").build(); 36 | } 37 | 38 | // tag::hystrix[] 39 | private static class IBANValidatorCommand extends HystrixCommand { 40 | private Account account; 41 | 42 | protected IBANValidatorCommand(Account account) { 43 | super(Setter.withGroupKey(HystrixCommandGroupKey.Factory 44 | .asKey("iban"))); 45 | this.account = account; // <2> 46 | } 47 | 48 | @Override 49 | protected Boolean run() throws Exception { 50 | return IBANValidator.isValid(account); // <3> 51 | } 52 | 53 | } 54 | 55 | @POST 56 | @ApiOperation("save account data") 57 | public Response save(Account account) throws ValidationException, 58 | InterruptedException { 59 | try { 60 | if (!new IBANValidatorCommand(account).execute()) { // <1> 61 | throw new ValidationException("invalid"); 62 | } 63 | } catch (HystrixRuntimeException e) { // <4> 64 | if (e.getCause() instanceof InterruptedException) { 65 | throw (InterruptedException) e.getCause(); 66 | } 67 | LOG.error("problem with command: {}", e.getMessage()); 68 | return Response.status(Status.SERVICE_UNAVAILABLE).build(); 69 | } 70 | super.saveToDatabase(account); 71 | return Response.status(Status.OK).build(); 72 | } 73 | // end::hystrix[] 74 | } 75 | -------------------------------------------------------------------------------- /hystrix-application/src/main/java/de/ahus1/hystrix/rest/SimpleSaveAccount.java: -------------------------------------------------------------------------------- 1 | package de.ahus1.hystrix.rest; 2 | 3 | import javax.ws.rs.GET; 4 | import javax.ws.rs.POST; 5 | import javax.ws.rs.Path; 6 | import javax.ws.rs.Produces; 7 | import javax.ws.rs.core.Response; 8 | import javax.ws.rs.core.Response.Status; 9 | 10 | import de.ahus1.hystrix.base.AbstractSaveAccount; 11 | import de.ahus1.hystrix.base.Account; 12 | import de.ahus1.hystrix.base.IBANValidator; 13 | import de.ahus1.hystrix.base.ValidationException; 14 | 15 | // tag::classdef[] 16 | @Path("/simple") 17 | public class SimpleSaveAccount extends AbstractSaveAccount { 18 | 19 | @GET 20 | @Produces("text/plain") 21 | public Response hello() { 22 | return Response.status(Status.OK).entity("Hello world").build(); 23 | } 24 | 25 | @POST 26 | public Response save(Account account) throws ValidationException, 27 | InterruptedException { 28 | if (!IBANValidator.isValid(account)) { 29 | throw new ValidationException("invalid"); 30 | } 31 | super.saveToDatabase(account); 32 | return Response.status(Status.OK).build(); 33 | } 34 | } 35 | // tag::classdef[] 36 | -------------------------------------------------------------------------------- /hystrix-application/src/main/java/de/ahus1/hystrix/util/prometheus/PrometheusMetricsServlet.java: -------------------------------------------------------------------------------- 1 | package de.ahus1.hystrix.util.prometheus; 2 | 3 | import io.prometheus.client.exporter.MetricsServlet; 4 | import io.prometheus.client.hotspot.DefaultExports; 5 | 6 | import javax.servlet.annotation.WebServlet; 7 | 8 | /** 9 | * @author Alexander Schwartz 2016 10 | */ 11 | @WebServlet(urlPatterns = "/metrics") 12 | public class PrometheusMetricsServlet extends MetricsServlet { 13 | 14 | public PrometheusMetricsServlet() { 15 | super(); 16 | DefaultExports.initialize(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /hystrix-application/src/main/java/de/ahus1/hystrix/util/riemann/HystrixRiemannEventNotifier.java: -------------------------------------------------------------------------------- 1 | package de.ahus1.hystrix.util.riemann; 2 | 3 | import java.io.IOException; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | import java.util.Timer; 7 | import java.util.TimerTask; 8 | import java.util.concurrent.LinkedTransferQueue; 9 | import java.util.concurrent.atomic.AtomicInteger; 10 | 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import com.aphyr.riemann.Proto.Event; 15 | import com.aphyr.riemann.client.RiemannClient; 16 | import com.netflix.hystrix.HystrixCommandKey; 17 | import com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStrategy; 18 | import com.netflix.hystrix.HystrixEventType; 19 | import com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier; 20 | 21 | import de.ahus1.hystrix.base.IBANValidator; 22 | 23 | /** 24 | * The Events are queued and sent from a second thread every 100 ms. 25 | */ 26 | public class HystrixRiemannEventNotifier extends HystrixEventNotifier { 27 | 28 | private static final int SEND_INTERVAL = 100; 29 | 30 | private static final int MAX_SIZE_EVENT_QUEUE = 10000; 31 | 32 | private static final int MAX_CHUNK_SIZE = 100; 33 | 34 | private static Logger LOG = LoggerFactory.getLogger(IBANValidator.class); 35 | 36 | private volatile RiemannClient c; 37 | 38 | private volatile boolean started; 39 | 40 | private final AtomicInteger bufferSize = new AtomicInteger(); 41 | 42 | private final LinkedTransferQueue buffer = 43 | new java.util.concurrent.LinkedTransferQueue(); 44 | 45 | private Timer timer; 46 | 47 | /** 48 | * Put an event in the event queue (if riemann has been started and there is 49 | * space in the queue). Otherwise the event is discarded silently. 50 | */ 51 | @Override 52 | public void markEvent(HystrixEventType eventType, HystrixCommandKey key) { 53 | if (started && c != null) { 54 | if (bufferSize.get() < MAX_SIZE_EVENT_QUEUE) { 55 | buffer.add(c.event().service(key.name()).time( 56 | System.currentTimeMillis() / 1000).state( 57 | eventType.name()).build()); 58 | bufferSize.incrementAndGet(); 59 | } 60 | } 61 | } 62 | 63 | /** 64 | * Put an event in the event queue (if riemann has been started and there is 65 | * space in the queue). Otherwise the event is discarded silently. 66 | */ 67 | @Override 68 | public void markCommandExecution(HystrixCommandKey key, 69 | ExecutionIsolationStrategy isolationStrategy, int duration, 70 | List eventsDuringExecution) { 71 | if (started && c != null) { 72 | if (bufferSize.get() < MAX_SIZE_EVENT_QUEUE) { 73 | buffer.add(c.event().service(key.name()).metric(duration).time( 74 | System.currentTimeMillis() / 1000).build()); 75 | bufferSize.incrementAndGet(); 76 | } 77 | } 78 | } 79 | 80 | /** 81 | * Start the scheduler to transmit events to Riemann. 82 | */ 83 | public synchronized void start() { 84 | TimerTask timerTask = new SenderTask(); 85 | // running timer task as daemon thread 86 | timer = new Timer(true); 87 | timer.schedule(timerTask, 0, SEND_INTERVAL); 88 | started = true; 89 | } 90 | 91 | /** 92 | * Stop the scheduler to transmit events to Riemann and also the Riemann 93 | * client. 94 | */ 95 | public synchronized void stop() throws IOException { 96 | try { 97 | if (started) { 98 | started = false; 99 | timer.cancel(); 100 | timer = null; 101 | if (c != null) { 102 | c.disconnect(); 103 | } 104 | c = null; 105 | } 106 | } catch (IOException e) { 107 | throw new RuntimeException(e); 108 | } 109 | } 110 | 111 | /** 112 | * Loc-kfree check if connection to Riemann server has already been created. 113 | * If it doesn't exist yet, will try to establish it. 114 | * 115 | * @return RiemannClient that is readily connected. 116 | * @throws IOException 117 | * on problems 118 | */ 119 | private RiemannClient getClient() throws IOException { 120 | RiemannClient localClient = c; 121 | if (localClient == null || !localClient.isConnected()) { 122 | localClient = connect(); 123 | } 124 | return localClient; 125 | } 126 | 127 | /** 128 | * Synchronized method to connect to Riemann server. 129 | * 130 | * @return RiemannClient that is readily connected. 131 | * @throws IOException 132 | * on problems 133 | */ 134 | private synchronized RiemannClient connect() throws IOException { 135 | if (c == null) { 136 | c = RiemannClient.tcp("localhost", 5555); 137 | } 138 | if (!c.isConnected()) { 139 | c.connect(); 140 | } 141 | return c; 142 | } 143 | 144 | /** 145 | * Send over events to Riemann in batches. 146 | */ 147 | class SenderTask extends TimerTask { 148 | 149 | @Override 150 | public void run() { 151 | if (started) { 152 | try { 153 | RiemannClient c = getClient(); 154 | do { 155 | final int chunkSize = 156 | Math.min(MAX_CHUNK_SIZE, bufferSize.get()); 157 | if (chunkSize > 0) { 158 | // Allocate space for writes 159 | final ArrayList events = 160 | new ArrayList(chunkSize); 161 | // Suck down elements from queue 162 | buffer.drainTo(events, chunkSize); 163 | // Update count 164 | bufferSize.addAndGet(-1 * events.size()); 165 | c.sendEvents(events); 166 | } 167 | } while (bufferSize.get() > MAX_CHUNK_SIZE); 168 | } catch (IOException e) { 169 | LOG.error("unable to connect to riemann"); 170 | } 171 | } 172 | } 173 | 174 | } 175 | 176 | } 177 | -------------------------------------------------------------------------------- /hystrix-application/src/main/java/de/ahus1/hystrix/util/zabbix/HystrixZabbixMetricsPublisher.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed under the Apache License, Version 2.0 (the "License"); 3 | * you may not use this file except in compliance with the License. 4 | * You may obtain a copy of the License at 5 | * 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Unless required by applicable law or agreed to in writing, software 9 | * distributed under the License is distributed on an "AS IS" BASIS, 10 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | * See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | package de.ahus1.hystrix.util.zabbix; 15 | 16 | import java.net.InetAddress; 17 | 18 | import com.netflix.hystrix.HystrixCircuitBreaker; 19 | import com.netflix.hystrix.HystrixCommandGroupKey; 20 | import com.netflix.hystrix.HystrixCommandKey; 21 | import com.netflix.hystrix.HystrixCommandMetrics; 22 | import com.netflix.hystrix.HystrixCommandProperties; 23 | import com.netflix.hystrix.HystrixThreadPoolKey; 24 | import com.netflix.hystrix.HystrixThreadPoolMetrics; 25 | import com.netflix.hystrix.HystrixThreadPoolProperties; 26 | import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisher; 27 | import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherCommand; 28 | import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherThreadPool; 29 | import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherThreadPoolDefault; 30 | import com.quigley.zabbixj.agent.ZabbixAgent; 31 | 32 | /** 33 | * Zabbix implementation of {@link HystrixMetricsPublisher}. 34 | */ 35 | public class HystrixZabbixMetricsPublisher extends HystrixMetricsPublisher { 36 | private ZabbixAgent agent; 37 | private ZabbixCommandMetricsProvider commandProvider; 38 | boolean started; 39 | 40 | public HystrixZabbixMetricsPublisher() throws Exception { 41 | agent = new ZabbixAgent(); 42 | agent.setEnableActive(true); 43 | agent.setRefreshInterval(10); 44 | agent.setEnablePassive(false); 45 | agent.setHostName("hystrix"); 46 | agent.setServerAddress(InetAddress.getByName("127.0.0.1")); 47 | agent.setServerPort(10051); 48 | 49 | commandProvider = new ZabbixCommandMetricsProvider(); 50 | agent.addProvider(ZabbixCommandMetricsProvider.PROVIDER, 51 | commandProvider); 52 | 53 | } 54 | 55 | public synchronized void start() throws Exception { 56 | if (!started) { 57 | agent.start(); 58 | started = true; 59 | } 60 | } 61 | 62 | public synchronized void stop() { 63 | if (started) { 64 | agent.stop(); 65 | started = false; 66 | } 67 | } 68 | 69 | @Override 70 | public HystrixMetricsPublisherCommand getMetricsPublisherForCommand( 71 | HystrixCommandKey commandKey, 72 | HystrixCommandGroupKey commandGroupKey, 73 | HystrixCommandMetrics metrics, 74 | HystrixCircuitBreaker circuitBreaker, 75 | HystrixCommandProperties properties) { 76 | return new HystrixZabbixMetricsPublisherCommand(commandKey, 77 | commandGroupKey, metrics, circuitBreaker, properties, 78 | commandProvider); 79 | } 80 | 81 | @Override 82 | public HystrixMetricsPublisherThreadPool getMetricsPublisherForThreadPool( 83 | HystrixThreadPoolKey threadPoolKey, 84 | HystrixThreadPoolMetrics metrics, 85 | HystrixThreadPoolProperties properties) { 86 | return new HystrixMetricsPublisherThreadPoolDefault(threadPoolKey, 87 | metrics, properties); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /hystrix-application/src/main/java/de/ahus1/hystrix/util/zabbix/HystrixZabbixMetricsPublisherCommand.java: -------------------------------------------------------------------------------- 1 | package de.ahus1.hystrix.util.zabbix; 2 | 3 | import com.netflix.hystrix.HystrixCircuitBreaker; 4 | import com.netflix.hystrix.HystrixCommandGroupKey; 5 | import com.netflix.hystrix.HystrixCommandKey; 6 | import com.netflix.hystrix.HystrixCommandMetrics; 7 | import com.netflix.hystrix.HystrixCommandProperties; 8 | import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisherCommand; 9 | 10 | public class HystrixZabbixMetricsPublisherCommand implements 11 | HystrixMetricsPublisherCommand { 12 | 13 | private final HystrixCommandKey key; 14 | private final HystrixCommandGroupKey commandGroupKey; 15 | private final HystrixCommandMetrics metrics; 16 | private final HystrixCircuitBreaker circuitBreaker; 17 | private final HystrixCommandProperties properties; 18 | private final ZabbixCommandMetricsProvider commandProvider; 19 | 20 | public HystrixZabbixMetricsPublisherCommand(HystrixCommandKey commandKey, 21 | HystrixCommandGroupKey commandGroupKey, 22 | HystrixCommandMetrics metrics, 23 | HystrixCircuitBreaker circuitBreaker, 24 | HystrixCommandProperties properties, 25 | ZabbixCommandMetricsProvider commandProvider) { 26 | this.key = commandKey; 27 | this.commandGroupKey = commandGroupKey; 28 | this.metrics = metrics; 29 | this.circuitBreaker = circuitBreaker; 30 | this.properties = properties; 31 | this.commandProvider = commandProvider; 32 | } 33 | 34 | @Override 35 | public void initialize() { 36 | commandProvider.register(this); 37 | } 38 | 39 | public HystrixCommandKey getKey() { 40 | return key; 41 | } 42 | 43 | public HystrixCommandGroupKey getCommandGroupKey() { 44 | return commandGroupKey; 45 | } 46 | 47 | public HystrixCommandMetrics getMetrics() { 48 | return metrics; 49 | } 50 | 51 | public HystrixCircuitBreaker getCircuitBreaker() { 52 | return circuitBreaker; 53 | } 54 | 55 | public HystrixCommandProperties getProperties() { 56 | return properties; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /hystrix-application/src/main/java/de/ahus1/hystrix/util/zabbix/ZabbixCommandMetricsProvider.java: -------------------------------------------------------------------------------- 1 | package de.ahus1.hystrix.util.zabbix; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import org.json.JSONArray; 7 | import org.json.JSONException; 8 | import org.json.JSONObject; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import com.netflix.hystrix.util.HystrixRollingNumberEvent; 13 | import com.quigley.zabbixj.metrics.MetricsException; 14 | import com.quigley.zabbixj.metrics.MetricsKey; 15 | import com.quigley.zabbixj.metrics.MetricsProvider; 16 | 17 | public class ZabbixCommandMetricsProvider implements MetricsProvider { 18 | 19 | public static String PROVIDER = "hystrixCommand"; 20 | 21 | private static Logger LOG = LoggerFactory 22 | .getLogger(ZabbixCommandMetricsProvider.class); 23 | 24 | Map numberEvents = new HashMap<>(); 25 | { 26 | numberEvents.put("CollapsedRequests", 27 | HystrixRollingNumberEvent.COLLAPSED); 28 | numberEvents.put("ExceptionsThrown", 29 | HystrixRollingNumberEvent.EXCEPTION_THROWN); 30 | numberEvents.put("Failure", HystrixRollingNumberEvent.FAILURE); 31 | numberEvents.put("FallbackFailure", 32 | HystrixRollingNumberEvent.FALLBACK_FAILURE); 33 | numberEvents.put("FallbackRejection", 34 | HystrixRollingNumberEvent.FALLBACK_REJECTION); 35 | numberEvents.put("FallbackSuccess", 36 | HystrixRollingNumberEvent.FALLBACK_SUCCESS); 37 | numberEvents.put("ResponsesFromCache", 38 | HystrixRollingNumberEvent.RESPONSE_FROM_CACHE); 39 | numberEvents.put("SemaphoreRejected", 40 | HystrixRollingNumberEvent.SEMAPHORE_REJECTED); 41 | numberEvents.put("ShortCircuited", 42 | HystrixRollingNumberEvent.SHORT_CIRCUITED); 43 | numberEvents.put("Success", HystrixRollingNumberEvent.SUCCESS); 44 | numberEvents.put("ThreadPoolRejected", 45 | HystrixRollingNumberEvent.THREAD_POOL_REJECTED); 46 | numberEvents.put("Timeout", HystrixRollingNumberEvent.TIMEOUT); 47 | } 48 | 49 | Map map = new HashMap<>(); 50 | 51 | /** 52 | * Return a metric for a given key. If the command is unknown, return 0 as a 53 | * neutral value, as Hystrix will register them only at the first command 54 | * run. 55 | */ 56 | @Override 57 | public Object getValue(MetricsKey key) throws MetricsException { 58 | if (key.getKey().equals("discovery")) { 59 | try { 60 | JSONObject discovery = new JSONObject(); 61 | JSONArray array = new JSONArray(); 62 | discovery.put("data", array); 63 | for (String command : map.keySet()) { 64 | JSONObject element = new JSONObject(); 65 | element.put("{#COMMAND}", command); 66 | array.put(element); 67 | } 68 | LOG.info("discovery: {}", discovery); 69 | return discovery; 70 | } catch (JSONException e) { 71 | throw new MetricsException(e); 72 | } 73 | } else if (key.getKey().startsWith("count")) { 74 | HystrixRollingNumberEvent event = 75 | numberEvents.get(key.getKey().replaceFirst("count", "")); 76 | if (event == null) { 77 | throw new MetricsException("unknown key " + key); 78 | } 79 | HystrixZabbixMetricsPublisherCommand command = 80 | map.get(key.getParameters()[0]); 81 | if (command == null) { 82 | return 0; 83 | } 84 | return command.getMetrics().getCumulativeCount(event); 85 | } else if (key.getKey().equals("latencyExecute")) { 86 | HystrixZabbixMetricsPublisherCommand command = 87 | map.get(key.getParameters()[0]); 88 | if (command == null) { 89 | return 0; 90 | } 91 | String percentile = key.getParameters()[1]; 92 | if (percentile.equalsIgnoreCase("mean")) { 93 | return command.getMetrics().getTotalTimeMean(); 94 | } else { 95 | return command.getMetrics().getTotalTimePercentile( 96 | Double.parseDouble(percentile)); 97 | } 98 | } else if (key.getKey().equals("latencyTotal")) { 99 | HystrixZabbixMetricsPublisherCommand command = 100 | map.get(key.getParameters()[0]); 101 | if (command == null) { 102 | return 0; 103 | } 104 | String percentile = key.getParameters()[1]; 105 | if (percentile.equalsIgnoreCase("mean")) { 106 | return command.getMetrics().getTotalTimeMean(); 107 | } else { 108 | return command.getMetrics().getTotalTimePercentile( 109 | Double.parseDouble(percentile)); 110 | } 111 | } else if (key.getKey().equals("latencyExecute")) { 112 | HystrixZabbixMetricsPublisherCommand command = 113 | map.get(key.getParameters()[0]); 114 | if (command == null) { 115 | return 0; 116 | } 117 | String percentile = key.getParameters()[1]; 118 | if (percentile.equalsIgnoreCase("mean")) { 119 | return command.getMetrics().getExecutionTimeMean(); 120 | } else { 121 | return command.getMetrics().getExecutionTimePercentile( 122 | Double.parseDouble(percentile)); 123 | } 124 | } else { 125 | throw new MetricsException("unknown key " + key); 126 | } 127 | } 128 | 129 | public void register(HystrixZabbixMetricsPublisherCommand command) { 130 | map.put(command.getKey().name(), command); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /hystrix-application/src/main/resources/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 7 | 8 | 9 | 10 | 12 | 13 | 14 | 15 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /hystrix-application/src/main/webapp/WEB-INF/ibm-web-ext.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /hystrix-application/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | HystrixMetricsStreamServlet 10 | HystrixMetricsStreamServlet 11 | com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet 12 | 13 | 14 | 15 | 16 | HystrixMetricsStreamServlet 17 | /hystrix.stream 18 | 19 | 20 | 21 | 22 | resteasy.resources 23 | com.wordnik.swagger.jaxrs.listing.ApiListingResourceJSON 24 | 25 | 26 | resteasy.providers 27 | com.wordnik.swagger.jaxrs.json.JacksonJsonProvider,com.wordnik.swagger.jaxrs.listing.ApiDeclarationProvider,com.wordnik.swagger.jaxrs.listing.ResourceListingProvider 28 | 29 | 30 | DefaultJaxrsConfig 31 | com.wordnik.swagger.jaxrs.config.DefaultJaxrsConfig 32 | 33 | api.version 34 | 1.0.0 35 | 36 | 37 | swagger.api.basepath 38 | http://localhost:8080/hystrixapp/api 39 | 40 | 2 41 | 42 | 43 | -------------------------------------------------------------------------------- /hystrix-application/src/main/webapp/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Hystrix example application 4 | 5 | 6 | Hystrix example application
7 | Hello world
8 | Swagger API
9 | Prometheus Metrics
10 | Monitor with Turbine
11 | Monitor directly 12 | 13 | -------------------------------------------------------------------------------- /hystrix-application/src/main/webapp/swagger/css/reset.css: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ v2.0 | 20110126 */ 2 | html, 3 | body, 4 | div, 5 | span, 6 | applet, 7 | object, 8 | iframe, 9 | h1, 10 | h2, 11 | h3, 12 | h4, 13 | h5, 14 | h6, 15 | p, 16 | blockquote, 17 | pre, 18 | a, 19 | abbr, 20 | acronym, 21 | address, 22 | big, 23 | cite, 24 | code, 25 | del, 26 | dfn, 27 | em, 28 | img, 29 | ins, 30 | kbd, 31 | q, 32 | s, 33 | samp, 34 | small, 35 | strike, 36 | strong, 37 | sub, 38 | sup, 39 | tt, 40 | var, 41 | b, 42 | u, 43 | i, 44 | center, 45 | dl, 46 | dt, 47 | dd, 48 | ol, 49 | ul, 50 | li, 51 | fieldset, 52 | form, 53 | label, 54 | legend, 55 | table, 56 | caption, 57 | tbody, 58 | tfoot, 59 | thead, 60 | tr, 61 | th, 62 | td, 63 | article, 64 | aside, 65 | canvas, 66 | details, 67 | embed, 68 | figure, 69 | figcaption, 70 | footer, 71 | header, 72 | hgroup, 73 | menu, 74 | nav, 75 | output, 76 | ruby, 77 | section, 78 | summary, 79 | time, 80 | mark, 81 | audio, 82 | video { 83 | margin: 0; 84 | padding: 0; 85 | border: 0; 86 | font-size: 100%; 87 | font: inherit; 88 | vertical-align: baseline; 89 | } 90 | /* HTML5 display-role reset for older browsers */ 91 | article, 92 | aside, 93 | details, 94 | figcaption, 95 | figure, 96 | footer, 97 | header, 98 | hgroup, 99 | menu, 100 | nav, 101 | section { 102 | display: block; 103 | } 104 | body { 105 | line-height: 1; 106 | } 107 | ol, 108 | ul { 109 | list-style: none; 110 | } 111 | blockquote, 112 | q { 113 | quotes: none; 114 | } 115 | blockquote:before, 116 | blockquote:after, 117 | q:before, 118 | q:after { 119 | content: ''; 120 | content: none; 121 | } 122 | table { 123 | border-collapse: collapse; 124 | border-spacing: 0; 125 | } 126 | -------------------------------------------------------------------------------- /hystrix-application/src/main/webapp/swagger/images/explorer_icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahus1/hystrix-examples/083327c17c31b57ed4a96078e0fbcf3e19f7d6b4/hystrix-application/src/main/webapp/swagger/images/explorer_icons.png -------------------------------------------------------------------------------- /hystrix-application/src/main/webapp/swagger/images/logo_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahus1/hystrix-examples/083327c17c31b57ed4a96078e0fbcf3e19f7d6b4/hystrix-application/src/main/webapp/swagger/images/logo_small.png -------------------------------------------------------------------------------- /hystrix-application/src/main/webapp/swagger/images/pet_store_api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahus1/hystrix-examples/083327c17c31b57ed4a96078e0fbcf3e19f7d6b4/hystrix-application/src/main/webapp/swagger/images/pet_store_api.png -------------------------------------------------------------------------------- /hystrix-application/src/main/webapp/swagger/images/throbber.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahus1/hystrix-examples/083327c17c31b57ed4a96078e0fbcf3e19f7d6b4/hystrix-application/src/main/webapp/swagger/images/throbber.gif -------------------------------------------------------------------------------- /hystrix-application/src/main/webapp/swagger/images/wordnik_api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahus1/hystrix-examples/083327c17c31b57ed4a96078e0fbcf3e19f7d6b4/hystrix-application/src/main/webapp/swagger/images/wordnik_api.png -------------------------------------------------------------------------------- /hystrix-application/src/main/webapp/swagger/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Swagger UI 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 65 | 66 | 67 | 68 | 84 | 85 |
 
86 |
87 | 88 | 89 | -------------------------------------------------------------------------------- /hystrix-application/src/main/webapp/swagger/lib/highlight.7.3.pack.js: -------------------------------------------------------------------------------- 1 | var hljs=new function(){function l(o){return o.replace(/&/gm,"&").replace(//gm,">")}function b(p){for(var o=p.firstChild;o;o=o.nextSibling){if(o.nodeName=="CODE"){return o}if(!(o.nodeType==3&&o.nodeValue.match(/\s+/))){break}}}function h(p,o){return Array.prototype.map.call(p.childNodes,function(q){if(q.nodeType==3){return o?q.nodeValue.replace(/\n/g,""):q.nodeValue}if(q.nodeName=="BR"){return"\n"}return h(q,o)}).join("")}function a(q){var p=(q.className+" "+q.parentNode.className).split(/\s+/);p=p.map(function(r){return r.replace(/^language-/,"")});for(var o=0;o"}while(x.length||v.length){var u=t().splice(0,1)[0];y+=l(w.substr(p,u.offset-p));p=u.offset;if(u.event=="start"){y+=s(u.node);r.push(u.node)}else{if(u.event=="stop"){var o,q=r.length;do{q--;o=r[q];y+=("")}while(o!=u.node);r.splice(q,1);while(q'+L[0]+""}else{r+=L[0]}N=A.lR.lastIndex;L=A.lR.exec(K)}return r+K.substr(N)}function z(){if(A.sL&&!e[A.sL]){return l(w)}var r=A.sL?d(A.sL,w):g(w);if(A.r>0){v+=r.keyword_count;B+=r.r}return''+r.value+""}function J(){return A.sL!==undefined?z():G()}function I(L,r){var K=L.cN?'':"";if(L.rB){x+=K;w=""}else{if(L.eB){x+=l(r)+K;w=""}else{x+=K;w=r}}A=Object.create(L,{parent:{value:A}});B+=L.r}function C(K,r){w+=K;if(r===undefined){x+=J();return 0}var L=o(r,A);if(L){x+=J();I(L,r);return L.rB?0:r.length}var M=s(A,r);if(M){if(!(M.rE||M.eE)){w+=r}x+=J();do{if(A.cN){x+=""}A=A.parent}while(A!=M.parent);if(M.eE){x+=l(r)}w="";if(M.starts){I(M.starts,"")}return M.rE?0:r.length}if(t(r,A)){throw"Illegal"}w+=r;return r.length||1}var F=e[D];f(F);var A=F;var w="";var B=0;var v=0;var x="";try{var u,q,p=0;while(true){A.t.lastIndex=p;u=A.t.exec(E);if(!u){break}q=C(E.substr(p,u.index-p),u[0]);p=u.index+q}C(E.substr(p));return{r:B,keyword_count:v,value:x,language:D}}catch(H){if(H=="Illegal"){return{r:0,keyword_count:0,value:l(E)}}else{throw H}}}function g(s){var o={keyword_count:0,r:0,value:l(s)};var q=o;for(var p in e){if(!e.hasOwnProperty(p)){continue}var r=d(p,s);r.language=p;if(r.keyword_count+r.r>q.keyword_count+q.r){q=r}if(r.keyword_count+r.r>o.keyword_count+o.r){q=o;o=r}}if(q.language){o.second_best=q}return o}function i(q,p,o){if(p){q=q.replace(/^((<[^>]+>|\t)+)/gm,function(r,v,u,t){return v.replace(/\t/g,p)})}if(o){q=q.replace(/\n/g,"
")}return q}function m(r,u,p){var v=h(r,p);var t=a(r);if(t=="no-highlight"){return}var w=t?d(t,v):g(v);t=w.language;var o=c(r);if(o.length){var q=document.createElement("pre");q.innerHTML=w.value;w.value=j(o,c(q),v)}w.value=i(w.value,u,p);var s=r.className;if(!s.match("(\\s|^)(language-)?"+t+"(\\s|$)")){s=s?(s+" "+t):t}r.innerHTML=w.value;r.className=s;r.result={language:t,kw:w.keyword_count,re:w.r};if(w.second_best){r.second_best={language:w.second_best.language,kw:w.second_best.keyword_count,re:w.second_best.r}}}function n(){if(n.called){return}n.called=true;Array.prototype.map.call(document.getElementsByTagName("pre"),b).filter(Boolean).forEach(function(o){m(o,hljs.tabReplace)})}function k(){window.addEventListener("DOMContentLoaded",n,false);window.addEventListener("load",n,false)}var e={};this.LANGUAGES=e;this.highlight=d;this.highlightAuto=g;this.fixMarkup=i;this.highlightBlock=m;this.initHighlighting=n;this.initHighlightingOnLoad=k;this.IR="[a-zA-Z][a-zA-Z0-9_]*";this.UIR="[a-zA-Z_][a-zA-Z0-9_]*";this.NR="\\b\\d+(\\.\\d+)?";this.CNR="(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)";this.BNR="\\b(0b[01]+)";this.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|\\.|-|-=|/|/=|:|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";this.BE={b:"\\\\[\\s\\S]",r:0};this.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[this.BE],r:0};this.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[this.BE],r:0};this.CLCM={cN:"comment",b:"//",e:"$"};this.CBLCLM={cN:"comment",b:"/\\*",e:"\\*/"};this.HCM={cN:"comment",b:"#",e:"$"};this.NM={cN:"number",b:this.NR,r:0};this.CNM={cN:"number",b:this.CNR,r:0};this.BNM={cN:"number",b:this.BNR,r:0};this.inherit=function(q,r){var o={};for(var p in q){o[p]=q[p]}if(r){for(var p in r){o[p]=r[p]}}return o}}();hljs.LANGUAGES.xml=function(a){var c="[A-Za-z0-9\\._:-]+";var b={eW:true,c:[{cN:"attribute",b:c,r:0},{b:'="',rB:true,e:'"',c:[{cN:"value",b:'"',eW:true}]},{b:"='",rB:true,e:"'",c:[{cN:"value",b:"'",eW:true}]},{b:"=",c:[{cN:"value",b:"[^\\s/>]+"}]}]};return{cI:true,c:[{cN:"pi",b:"<\\?",e:"\\?>",r:10},{cN:"doctype",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},{cN:"comment",b:"",r:10},{cN:"cdata",b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"tag",b:"|$)",e:">",k:{title:"style"},c:[b],starts:{e:"",rE:true,sL:"css"}},{cN:"tag",b:"|$)",e:">",k:{title:"script"},c:[b],starts:{e:"<\/script>",rE:true,sL:"javascript"}},{b:"<%",e:"%>",sL:"vbscript"},{cN:"tag",b:"",c:[{cN:"title",b:"[^ />]+"},b]}]}}(hljs);hljs.LANGUAGES.json=function(a){var e={literal:"true false null"};var d=[a.QSM,a.CNM];var c={cN:"value",e:",",eW:true,eE:true,c:d,k:e};var b={b:"{",e:"}",c:[{cN:"attribute",b:'\\s*"',e:'"\\s*:\\s*',eB:true,eE:true,c:[a.BE],i:"\\n",starts:c}],i:"\\S"};var f={b:"\\[",e:"\\]",c:[a.inherit(c,{cN:null})],i:"\\S"};d.splice(d.length,0,b,f);return{c:d,k:e,i:"\\S"}}(hljs); -------------------------------------------------------------------------------- /hystrix-application/src/main/webapp/swagger/lib/jquery.ba-bbq.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery BBQ: Back Button & Query Library - v1.2.1 - 2/17/2010 3 | * http://benalman.com/projects/jquery-bbq-plugin/ 4 | * 5 | * Copyright (c) 2010 "Cowboy" Ben Alman 6 | * Dual licensed under the MIT and GPL licenses. 7 | * http://benalman.com/about/license/ 8 | */ 9 | (function($,p){var i,m=Array.prototype.slice,r=decodeURIComponent,a=$.param,c,l,v,b=$.bbq=$.bbq||{},q,u,j,e=$.event.special,d="hashchange",A="querystring",D="fragment",y="elemUrlAttr",g="location",k="href",t="src",x=/^.*\?|#.*$/g,w=/^.*\#/,h,C={};function E(F){return typeof F==="string"}function B(G){var F=m.call(arguments,1);return function(){return G.apply(this,F.concat(m.call(arguments)))}}function n(F){return F.replace(/^[^#]*#?(.*)$/,"$1")}function o(F){return F.replace(/(?:^[^?#]*\?([^#]*).*$)?.*/,"$1")}function f(H,M,F,I,G){var O,L,K,N,J;if(I!==i){K=F.match(H?/^([^#]*)\#?(.*)$/:/^([^#?]*)\??([^#]*)(#?.*)/);J=K[3]||"";if(G===2&&E(I)){L=I.replace(H?w:x,"")}else{N=l(K[2]);I=E(I)?l[H?D:A](I):I;L=G===2?I:G===1?$.extend({},I,N):$.extend({},N,I);L=a(L);if(H){L=L.replace(h,r)}}O=K[1]+(H?"#":L||!K[1]?"?":"")+L+J}else{O=M(F!==i?F:p[g][k])}return O}a[A]=B(f,0,o);a[D]=c=B(f,1,n);c.noEscape=function(G){G=G||"";var F=$.map(G.split(""),encodeURIComponent);h=new RegExp(F.join("|"),"g")};c.noEscape(",/");$.deparam=l=function(I,F){var H={},G={"true":!0,"false":!1,"null":null};$.each(I.replace(/\+/g," ").split("&"),function(L,Q){var K=Q.split("="),P=r(K[0]),J,O=H,M=0,R=P.split("]["),N=R.length-1;if(/\[/.test(R[0])&&/\]$/.test(R[N])){R[N]=R[N].replace(/\]$/,"");R=R.shift().split("[").concat(R);N=R.length-1}else{N=0}if(K.length===2){J=r(K[1]);if(F){J=J&&!isNaN(J)?+J:J==="undefined"?i:G[J]!==i?G[J]:J}if(N){for(;M<=N;M++){P=R[M]===""?O.length:R[M];O=O[P]=M').hide().insertAfter("body")[0].contentWindow;q=function(){return a(n.document[c][l])};o=function(u,s){if(u!==s){var t=n.document;t.open().close();t[c].hash="#"+u}};o(a())}}m.start=function(){if(r){return}var t=a();o||p();(function s(){var v=a(),u=q(t);if(v!==t){o(t=v,u);$(i).trigger(d)}else{if(u!==t){i[c][l]=i[c][l].replace(/#.*/,"")+"#"+u}}r=setTimeout(s,$[d+"Delay"])})()};m.stop=function(){if(!n){r&&clearTimeout(r);r=0}};return m})()})(jQuery,this); -------------------------------------------------------------------------------- /hystrix-application/src/main/webapp/swagger/lib/jquery.slideto.min.js: -------------------------------------------------------------------------------- 1 | (function(b){b.fn.slideto=function(a){a=b.extend({slide_duration:"slow",highlight_duration:3E3,highlight:true,highlight_color:"#FFFF99"},a);return this.each(function(){obj=b(this);b("body").animate({scrollTop:obj.offset().top},a.slide_duration,function(){a.highlight&&b.ui.version&&obj.effect("highlight",{color:a.highlight_color},a.highlight_duration)})})}})(jQuery); 2 | -------------------------------------------------------------------------------- /hystrix-application/src/main/webapp/swagger/lib/jquery.wiggle.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | jQuery Wiggle 3 | Author: WonderGroup, Jordan Thomas 4 | URL: http://labs.wondergroup.com/demos/mini-ui/index.html 5 | License: MIT (http://en.wikipedia.org/wiki/MIT_License) 6 | */ 7 | jQuery.fn.wiggle=function(o){var d={speed:50,wiggles:3,travel:5,callback:null};var o=jQuery.extend(d,o);return this.each(function(){var cache=this;var wrap=jQuery(this).wrap('
').css("position","relative");var calls=0;for(i=1;i<=o.wiggles;i++){jQuery(this).animate({left:"-="+o.travel},o.speed).animate({left:"+="+o.travel*2},o.speed*2).animate({left:"-="+o.travel},o.speed,function(){calls++;if(jQuery(cache).parent().hasClass('wiggle-wrap')){jQuery(cache).parent().replaceWith(cache);} 8 | if(calls==o.wiggles&&jQuery.isFunction(o.callback)){o.callback();}});}});}; -------------------------------------------------------------------------------- /hystrix-application/src/main/webapp/swagger/o2c.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /manual/build.bat: -------------------------------------------------------------------------------- 1 | mkdir ..\..\hystrix-pages\manual 2 | copy ..\tools\tomcat\manual\*.png ..\..\hystrix-pages\manual 3 | copy ..\tools\jmeter\manual\*.png ..\..\hystrix-pages\manual 4 | copy ..\tools\riemann\manual\*.png ..\..\hystrix-pages\manual 5 | copy ..\tools\zabbix\manual\*.png ..\..\hystrix-pages\manual 6 | copy ..\hystrix-application\manual\*.png ..\..\hystrix-pages\manual 7 | copy manual\*.png ..\..\hystrix-pages\manual 8 | asciidoctor manual.adoc -d book -D ..\..\hystrix-pages 9 | -------------------------------------------------------------------------------- /manual/build.sh: -------------------------------------------------------------------------------- 1 | mkdir -p $HOME/pages/manual 2 | BASEDIR=$(dirname $0) 3 | cd $BASEDIR 4 | cp ../tools/tomcat/manual/*.png $HOME/pages/manual 5 | cp ../tools/jmeter/manual/*.png $HOME/pages/manual 6 | cp ../tools/riemann/manual/*.png $HOME/pages/manual 7 | cp ../tools/zabbix/manual/*.png $HOME/pages/manual 8 | cp ../hystrix-application/manual/*.png $HOME/pages/manual 9 | cp manual/*.png $HOME/pages/manual 10 | asciidoctor manual.adoc -d book -D $HOME/pages 11 | -------------------------------------------------------------------------------- /manual/build_pdf.bat: -------------------------------------------------------------------------------- 1 | mkdir ..\..\asciidoctor-fopub\manual 2 | copy ..\tools\tomcat\manual\*.png ..\..\asciidoctor-fopub\manual 3 | copy ..\tools\jmeter\manual\*.png ..\..\asciidoctor-fopub\manual 4 | copy manual\*.png ..\..\asciidoctor-fopub\manual 5 | call asciidoctor -b docbook -d article manual.adoc 6 | copy manual.xml ..\..\asciidoctor-fopub 7 | -------------------------------------------------------------------------------- /manual/manual/dashboard_100ms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahus1/hystrix-examples/083327c17c31b57ed4a96078e0fbcf3e19f7d6b4/manual/manual/dashboard_100ms.png -------------------------------------------------------------------------------- /manual/manual/dashboard_10ms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahus1/hystrix-examples/083327c17c31b57ed4a96078e0fbcf3e19f7d6b4/manual/manual/dashboard_10ms.png -------------------------------------------------------------------------------- /manual/manual/dashboard_1500ms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahus1/hystrix-examples/083327c17c31b57ed4a96078e0fbcf3e19f7d6b4/manual/manual/dashboard_1500ms.png -------------------------------------------------------------------------------- /manual/manual/dashboard_200ms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahus1/hystrix-examples/083327c17c31b57ed4a96078e0fbcf3e19f7d6b4/manual/manual/dashboard_200ms.png -------------------------------------------------------------------------------- /manual/manual/dashboard_70ms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahus1/hystrix-examples/083327c17c31b57ed4a96078e0fbcf3e19f7d6b4/manual/manual/dashboard_70ms.png -------------------------------------------------------------------------------- /manual/saltstack.adoc: -------------------------------------------------------------------------------- 1 | [[saltstack]] 2 | == Automatic provisioning of machines 3 | 4 | === Saltstack installation automation 5 | 6 | In order to provide reproducable and easy to setup development and test environments, you can script the installation of the software. 7 | 8 | There are different tools available to install and configure software once the base operating system is installed. Some of the tools used for this are Chef, Puppet, Saltstack and Ansible. 9 | 10 | I've chosen Saltstack here as it concentrates on its task to install and configure software - nothing more. For this it takes input as simple YAML files with only very little scripting. 11 | 12 | Vagrant already knowns about different provisioners, also about Saltstack. To hand over control to Saltstack only the following few lines are necessary in the `Vagrantfile` of the virtual machine you want to provision: 13 | 14 | [source,indent=0] 15 | .Vagrantfile 16 | ---- 17 | config.vm.provision :salt do |salt| 18 | salt.minion_config = "salt/minion" 19 | salt.run_highstate = true 20 | end 21 | ---- 22 | 23 | Vagrant will first check if Saltstack is already installed on the virtual machine. If not, it will install the latest version of Saltstack. Once this is complete it hands over control to Saltstack to install all the configured packages. 24 | 25 | To find out more about Saltstack please visit its website http://saltstack.com. 26 | 27 | === Running Saltstack in standalone mode 28 | 29 | Saltstack can be run in two modes: 30 | 31 | . *Centrally managed configuration*: a master server stores all configuration and passes it to the clients (the clients are called "minions"). 32 | . *Locally stored configuration*: A client will have all configuration files necessary stored locally. This setup is called "masterless" setup. 33 | 34 | The scripts will not differ in the two setups. But it simlifies development and also the setup we use here to have a masterless setup. To do this, I specied `file_client: local` in the `minion` file. 35 | 36 | (Note: this masterless setup is not unique to Saltstack, it is also available for other provisioning tools.) 37 | 38 | === Configuration files for automatic installation 39 | 40 | You will find the configuration files in `salt/roots/salt`. They are plain text files. You can open them in a plain text editor to get a first impression. Please refer to the Salstack documentation find out more. 41 | 42 | === Saltstack commands 43 | 44 | Provisioning via saltstack is run automatically. To run salt stack provisioning manually again (for example after you have changed a configuration file) use the following command as user `root`: 45 | 46 | salt-call --local state.highstate 47 | 48 | Please refer to the Salstack documentation find out more. 49 | -------------------------------------------------------------------------------- /manual/update-gh-pages.sh: -------------------------------------------------------------------------------- 1 | # Take from and modified http://sleepycoders.blogspot.de/2013/03/sharing-travis-ci-generated-files.html?_escaped_fragment_#! 2 | if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then 3 | echo -e "Starting to update gh-pages\n" 4 | 5 | #go to home and setup git 6 | cd $HOME 7 | git config --global user.email "travis@travis-ci.org" 8 | git config --global user.name "Travis" 9 | 10 | #using token clone gh-pages branch 11 | git clone --quiet --branch=gh-pages https://${GH_TOKEN}@github.com/ahus1/hystrix-examples.git gh-pages > /dev/null 12 | 13 | #go into diractory and copy data we're interested in to that directory 14 | cd gh-pages 15 | cp -Rf $HOME/pages/* . 16 | 17 | #add, commit and push files 18 | git add -f . 19 | git commit -m "Travis build $TRAVIS_BUILD_NUMBER pushed to gh-pages" 20 | git push -fq origin gh-pages > /dev/null 21 | 22 | echo -e "Done publishing to gh-pages.\n" 23 | fi 24 | -------------------------------------------------------------------------------- /manual/vagrant.adoc: -------------------------------------------------------------------------------- 1 | 2 | [[vagrant]] 3 | == Running virtual machines for test and development 4 | 5 | === Vagrant manages virtual machines 6 | 7 | Virtual machines make development and test easier, as they can be started and stoped as you need them. You re-use the CPU, RAM and hard disk space on your PC. When you don't need them you shut them down and they will use only some hard drive space. Once your test or development are over you can wipe them from your hard disk. 8 | 9 | A software to provide this virtualization is the free http://virtualbox.org/[Oracle's Virtualbox^]. You can spin up as many machines as you have RAM, CPU and hard disk space on your local machine. You can set up custom networking and interact with the machines either via screen or network. 10 | 11 | But setting up a test environment would still be a manual process if you would use only Virtualbox. http://vagrantup.com[Vagrant^] builds on top of it and provides a command line and scripting for you. It also allows you to create local test instances from centrally managed ready made boxes, so you don't need to install an operating system manually. 12 | 13 | === Installing Vagrant and useful plugins 14 | 15 | To use Vagrant please use the following steps: 16 | 17 | . Download and install Oracle's Virtualbox from http://virtualbox.org/. 18 | . Download and install Hashicorp's Vagrant from http://vagrantup.com. 19 | . Install the Vagrant Cachier Plugin (https://github.com/fgrehm/vagrant-cachier) to cache all downloaded software packages locally. This will speed up future installations. Do this by starting from the command line: 20 | 21 | vagrant plugin install vagrant-cachier 22 | 23 | . Install the Vagrant Guest Additions Plugin (https://github.com/dotless-de/vagrant-vbguest) to be able to update the virtual box tools on the downloaded images automatically. Do this by starting from the command line: 24 | 25 | vagrant plugin install vagrant-vbguest 26 | 27 | . Install the Vagrant proxy plugin (https://github.com/tmatilai/vagrant-proxyconf) to configure the downloaded image automatically regarding its proxy settings. Do this by starting from the command line 28 | 29 | vagrant plugin install vagrant-proxyconf 30 | 31 | === Proxy configuration for Vagrant 32 | 33 | To be able to install any vagrant plugin behind a proxy, set the `http_proxy` environment variable. The this syntax assumes you are running a Microsoft Windows system: 34 | 35 | ---- 36 | SET HTTP_PROXY="http://username:password@proxyhost:proxyport/ 37 | SET HTTPS_PROXY="http://username:password@proxyhost:proxyport/ 38 | ---- 39 | 40 | Vagrant will not re-use your system's proxy settings. You'll need to specify them again. 41 | 42 | I recommend that you set up a common configuration for all your boxes (not individually for each box). Create (or ammend) the file `Vagrantfile` in your `%USERPROFILE%\.vagrant.d` folder. 43 | 44 | [source] 45 | .Vagrantfile 46 | ---- 47 | # URI of the local (caching) HTTP proxy 48 | # LOCAL_HTTP_PROXY = 'http://proxyhost:proxyport' 49 | LOCAL_HTTP_PROXY = 50 | 51 | # Configures vagrant-cachier and vagrant-proxyconf. 52 | # Should be called only on "local machine" providers. 53 | def configure_caching(config) 54 | if Vagrant.has_plugin?('vagrant-cachier') 55 | config.cache.enable :gem 56 | config.cache.enable :npm 57 | end 58 | 59 | if Vagrant.has_plugin?('vagrant-proxyconf') 60 | config.proxy.http = LOCAL_HTTP_PROXY 61 | config.proxy.https = LOCAL_HTTP_PROXY 62 | config.proxy.no_proxy = 'localhost,127.0.0.1' 63 | end 64 | end 65 | 66 | Vagrant.configure('2') do |config| 67 | config.vm.provider :virtualbox do |vbox, override| 68 | configure_caching(override) 69 | end 70 | end 71 | ---- 72 | 73 | Alternatively you can set the environment variables `VAGRANT_HTTP_PROXY`, `VAGRANT_HTTPS_PROXY` and `VAGRANT_NO_PROXY`. 74 | 75 | === Managing virtual machines from the command line 76 | 77 | You can start a box with: 78 | 79 | vagrant up 80 | 81 | You can stop a box with: 82 | 83 | vagrant suspend 84 | 85 | You can log in to the box using: 86 | 87 | vagrant ssh 88 | 89 | For a list of other commands start 90 | 91 | vagrant -h 92 | 93 | By default a user `vagrant` with password `vagrant` exists every machine. You can use `ssh` to access a console. From the `vagrant` user you can use the `sudo` command to acquire root access. 94 | -------------------------------------------------------------------------------- /tools/asciidoctor/README.adoc: -------------------------------------------------------------------------------- 1 | [[asciidoctor]] 2 | == Writing an online manual 3 | 4 | === Asciidoctor is a lean tool for technical documentation 5 | 6 | This manual is written in Asciidoc format. Asciidoctor is used to create an online documentation from it. 7 | 8 | To find out more about Asciidoctor see the http://asciidoctor.org/. It is a clone of the original Asciidoc using Ruby. Compiled versions are available for Java and JavaScript. This allows you to easily integrate it into your build process. 9 | 10 | You can create from a single source of documentation formats like HTML5, PDF and epub. 11 | 12 | === Editors to work on Asciidoctor 13 | 14 | Asciidoctor files are plain text files with an easy to learn syntax. You can use any text editor to write the files. 15 | 16 | You might want to try the https://github.com/asciidoctor/atom-asciidoc-preview[Asciidoctor preview plugin^] and https://atom.io/packages/language-asciidoc[Asciidoctor language plugin^] for https://atom.io/[GitHub's Atom^] editor. As the time of writing this provides you the best authoring experience. 17 | -------------------------------------------------------------------------------- /tools/hystrix-dashboard/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /build/ 3 | /overlays -------------------------------------------------------------------------------- /tools/hystrix-dashboard/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahus1/hystrix-examples/083327c17c31b57ed4a96078e0fbcf3e19f7d6b4/tools/hystrix-dashboard/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /tools/hystrix-dashboard/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.3/apache-maven-3.3.3-bin.zip -------------------------------------------------------------------------------- /tools/hystrix-dashboard/README.adoc: -------------------------------------------------------------------------------- 1 | == Displaying Hystrix runtime information in a browser 2 | 3 | === Hystrix Dashboard displays a Realtime Dashboard 4 | 5 | https://github.com/Netflix/Hystrix/tree/master/hystrix-dashboard[Hystrix Dashboard^] is part of the Hystrix distribution. It displays runtime information about every Hystrix command and thread pool for the last few minutes. 6 | 7 | === Installing and running Hystrix Dashboard 8 | 9 | The installation has been scripted: you need to run `tools/hystrix-dashboard/maven-package-deploy`. 10 | 11 | Open your browser on http://localhost:8080/hystrix-dashboard/. Press btn:[Monitor Stream] with the default setting to display the aggregated stream from the Turbine dashboard. 12 | 13 | Enter `http://localhost:8080/hystrixapp/hystrix.stream` to retrieve the information from the application directly. 14 | -------------------------------------------------------------------------------- /tools/hystrix-dashboard/maven-package-deploy.bat: -------------------------------------------------------------------------------- 1 | call %~dp0mvnw clean package cargo:redeploy 2 | -------------------------------------------------------------------------------- /tools/hystrix-dashboard/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | set MAVEN_CMD_LINE_ARGS=%MAVEN_CONFIG% %* 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | 121 | set WRAPPER_JAR=""%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"" 122 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 123 | 124 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS% 125 | if ERRORLEVEL 1 goto error 126 | goto end 127 | 128 | :error 129 | set ERROR_CODE=1 130 | 131 | :end 132 | @endlocal & set ERROR_CODE=%ERROR_CODE% 133 | 134 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 135 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 136 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 137 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 138 | :skipRcPost 139 | 140 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 141 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 142 | 143 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 144 | 145 | exit /B %ERROR_CODE% 146 | -------------------------------------------------------------------------------- /tools/hystrix-dashboard/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | de.ahus1.hystrix 4 | hystrix-dashboard 5 | war 6 | 1.4.0.1-SNAPSHOT 7 | 8 | Hystrix Dashboard 9 | 10 | 11 | 12 | com.netflix.hystrix 13 | hystrix-dashboard 14 | 1.5.12 15 | war 16 | 17 | 18 | 19 | 20 | hystrix-dashboard 21 | 22 | 23 | 24 | org.apache.maven.plugins 25 | maven-compiler-plugin 26 | 27 | 1.7 28 | 1.7 29 | 30 | 31 | 32 | org.codehaus.cargo 33 | cargo-maven2-plugin 34 | 1.4.2 35 | 36 | 37 | tomcat7x 38 | remote 39 | 40 | 41 | runtime 42 | 43 | 44 | http://localhost:8080/manager/text 45 | 46 | 47 | deploy 48 | 49 | 50 | deploy 51 | 52 | 53 | 54 | 55 | remote 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | org.apache.maven.plugins 66 | maven-war-plugin 67 | 2.4 68 | 69 | 70 | 71 | 72 | 73 | 74 | com.netflix.hystrix 75 | hystrix-dashboard 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /tools/jmeter/.gitignore: -------------------------------------------------------------------------------- 1 | /apache-jmeter-* 2 | /jmeter.log 3 | -------------------------------------------------------------------------------- /tools/jmeter/README.adoc: -------------------------------------------------------------------------------- 1 | :imagesdir: manual 2 | 3 | [[jmeter]] 4 | == Putting your application under load 5 | 6 | === Apache JMeter is free and open source load testing 7 | 8 | http://jmeter.apache.org/[Apache JMeter^] allows you to create 9 | and run load tests simulating the load of multiple users using 10 | a single PC. 11 | 12 | === Installing Apache JMeter 13 | 14 | This process has been automated for you. The first time you start `tools/maven/run-jmeter.bat` JMeter is downloaded and installed. 15 | 16 | The following defaults are applied: 17 | 18 | . Whenever you run JMeter using the script above, the load testing script `hystrixSaveAccount.jmx` is opened. 19 | 20 | You will see the <>. 21 | 22 | [[img-jmeterwelcome]] 23 | .Apache JMeter Start Screen 24 | image::jmeterwelcome.png[JMeter Start Screen] 25 | 26 | === Simulating multiple users 27 | 28 | You can vary the number of simulated users by changing the number of threads. In this script the number of users is configured to be 20. 29 | 30 | A test with JMeter has the following steps: 31 | 32 | . choose the number of users (aka threads) 33 | . press the play image:jmeter-play.png[Play, title="Play"] button to start the workers 34 | . press the stop image:jmeter-stop.png[Stop, title="Stop"] button to stop the workers 35 | . Watch the summary report to see the timing of the requests and how many requests succeed and fail 36 | . Watch the log file of Apache Tomcat for exceptions and other log messages 37 | . Change the Archaius runtime configuration and see how the behaviour of the system changes (see section <> for the details). 38 | . press the clean image:jmeter-clean.png[Clean, title="Clean"] button to clear the results from JMeter 39 | 40 | [IMPORTANT] 41 | When you change the number of users (aka threads) it will become effective only after you stop/start the workers. 42 | -------------------------------------------------------------------------------- /tools/jmeter/manual/jmeter-clean.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahus1/hystrix-examples/083327c17c31b57ed4a96078e0fbcf3e19f7d6b4/tools/jmeter/manual/jmeter-clean.png -------------------------------------------------------------------------------- /tools/jmeter/manual/jmeter-play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahus1/hystrix-examples/083327c17c31b57ed4a96078e0fbcf3e19f7d6b4/tools/jmeter/manual/jmeter-play.png -------------------------------------------------------------------------------- /tools/jmeter/manual/jmeter-stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahus1/hystrix-examples/083327c17c31b57ed4a96078e0fbcf3e19f7d6b4/tools/jmeter/manual/jmeter-stop.png -------------------------------------------------------------------------------- /tools/jmeter/manual/jmeterwelcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahus1/hystrix-examples/083327c17c31b57ed4a96078e0fbcf3e19f7d6b4/tools/jmeter/manual/jmeterwelcome.png -------------------------------------------------------------------------------- /tools/jmeter/run-jmeter.bat: -------------------------------------------------------------------------------- 1 | powershell set-executionpolicy remotesigned 2 | powershell %~dp0run-jmeter.ps1 -t hystrixSaveAccount.jmx -------------------------------------------------------------------------------- /tools/jmeter/run-jmeter.ps1: -------------------------------------------------------------------------------- 1 | # change version number and hash code as shown on Apache download page 2 | # http://jmeter.apache.org/download_jmeter.cgi 3 | $version="2.11" 4 | $masterhash = "14b6dfc04f912e45b482e4563fdf1c3a" 5 | 6 | $url = "https://archive.apache.org/dist/jmeter/binaries/apache-jmeter-$version.zip" 7 | 8 | $scriptPath = split-path -parent $MyInvocation.MyCommand.Definition 9 | 10 | # see if folder has been created 11 | If (-not (Test-Path "$scriptPath/apache-jmeter-$version")) { 12 | 13 | # see if ZIP file exists 14 | If (-not (Test-Path "$scriptPath/apache-jmeter-$version.zip")) { 15 | "downloading installation archive from $url" 16 | $webclient = New-Object System.Net.WebClient 17 | $webclient.DownloadFile($url,"$scriptPath/apache-jmeter-$version.zip") 18 | } 19 | 20 | # create a md5 hash code from ZIP file and normalize it 21 | "verifying hash code" 22 | $md5 = new-object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider 23 | $hash = [System.BitConverter]::ToString($md5.ComputeHash([System.IO.File]::ReadAllBytes("apache-jmeter-$version.zip"))) 24 | $hash = $hash.replace("-","").toLower() 25 | 26 | # check if hash codes match 27 | If ($hash -ne $masterhash) { 28 | "Hash of master file $masterhash doesn't match downloaded file $hash. ZIP file is possibly corrupted" 29 | exit 30 | } 31 | 32 | "install jmeter" 33 | $shell_app=new-object -com shell.application 34 | $zip_file = $shell_app.namespace("$scriptPath\apache-jmeter-$version.zip") 35 | $destination = $shell_app.namespace($scriptPath) 36 | $destination.Copyhere($zip_file.items()) 37 | 38 | } 39 | 40 | 41 | "starting jmeter" 42 | start-process $scriptPath/apache-jmeter-$version/bin/jmeter.bat -ArgumentList $args -NoNewWindow -Wait 43 | 44 | -------------------------------------------------------------------------------- /tools/maven/README.adoc: -------------------------------------------------------------------------------- 1 | 2 | == Building and deploying the application 3 | 4 | === Build Configuration based on conventions with Apache Maven 5 | 6 | http://maven.apache.org/[Apache Maven^] as a build system you the following advantages: 7 | 8 | . Project layout based on conventions (i.e. your source files are in `src/main/java`) 9 | . Management of binary artefacts including transitive dependencies 10 | . A lot of plugins to automate your build 11 | 12 | === Installing Apache Maven 13 | 14 | This process has been automated for you, as all projects include https://github.com/takari/maven-wrapper[Maven Wrapper^]. This will download and install maven automatically. 15 | 16 | === Packaging and deploying your application to Apache Tomcat 17 | 18 | To do this run `hystrix-application/maven-package-deploy`. *Please ensure that your Apache Tomcat is running,* as Maven will deploy your application into the running Apache Tomcat. 19 | 20 | The steps executed by Maven `mvn clean package cargo:redeploy` included in the Batch-file: 21 | 22 | . Clean up the build folder `target`, 23 | . download all dependencies from public Maven repositories if they haven't been downloaded yet, + 24 | (this might take a while on the first run depending on the speed of your Internet connection) 25 | . compile all Java sources, 26 | . package a WAR file in the `target` folder, 27 | . deploy it to your running Tomcat instance. 28 | 29 | To test that your application has been deployed successfully, open the URL http://localhost:8080/hystrixapp/api/simple[http://localhost:8080/hystrixapp/api/simple^] in your browser. 30 | You should get the response `Hello world` to show you that everything has been set up correctly. 31 | -------------------------------------------------------------------------------- /tools/riemann/.gitignore: -------------------------------------------------------------------------------- 1 | /.vagrant -------------------------------------------------------------------------------- /tools/riemann/README.adoc: -------------------------------------------------------------------------------- 1 | // using experimental to support btn: macro 2 | :experimental: 3 | 4 | == Real time monitoring of Hystrix metrics 5 | 6 | === Riemann as cutting edge realtime event processing 7 | 8 | http://www.riemann.io/[Riemann^] is a a modern event management system. It has been designed with with performance in mind for montoring complex systems. To process the data fast it keeps the last few minutes of data in memory. All events are processed in a streaming mode. 9 | 10 | The events can be aggregated and filtered. You can also start actions like notifying IT operations of problems. 11 | 12 | Riemann comes with its own dashboard that can show you can use to show real time graphs and statistics. 13 | 14 | So far both the Hystrix Dashboard and Zabbix have been presented. You could consider Riemann for the following: 15 | 16 | . Zabbix polls existing metrics from Hystrix. You can aggregate events to deliver your own metrics using Riemann. This all happens outside of the application. This gives you a lot of flexibility. 17 | 18 | . While the Hystrix Dashboard is a great start for a dashboard, it is not configurable. The Riemann Dashboard is highly configurable (once you understand its keyboard shortcuts) and might delivery you additional insights you might need to administer your cluster. 19 | 20 | . Assuming that Zabbix receives information every minute, this means that you will receive alerts with a delay of one minute. After a problem disappeared (for example after you have restarted a service, or fixed a configuration problem) you will see this only after a minute or two in the Zabbix graphs. Riemann gives you the options to be notified immediately by a channel of your choice (email, SMS, chat) when the problem occurs and when it is fixed. 21 | 22 | Filtered events can be forwarded to systems like InfluxDB to be stored. These can be displayed later using tools like Grafana. But lets start with Riemann first. 23 | 24 | === Installing and running Riemann 25 | 26 | The installation has been scripted as a http://vagrantup.com[Vagrant^] script. This will first download a linux image of CentOS and spin it up in http://virtualbox.org/[Virtualbox^]. Then it will hand over to a provisioner, in our case this is http://saltstack.com/[Saltstack^]. 27 | 28 | To install Vagrant please see <>. Once it is installed, 29 | run the follwing command in `tools/riemann`: 30 | 31 | ---- 32 | vagrant up 33 | ---- 34 | 35 | This will take a while to download all the files necessary. Once it is up and running point your browser at your local Riemann installation: http://localhost:4567/. 36 | 37 | === How Events are captures for Riemann 38 | 39 | In the example application the `HystrixSetupListener` registers the class `HystrixRiemannEventNotifier` with Hystrix. This will be notified with the detailed timinings of each run command and with the outcome of each command (successful, timeout, etc.). 40 | 41 | These events are queued in a bounded queue. The result will be forwarded to Riemann in batches every 100 ms. 42 | 43 | In order to activate the forwarding of events, you'll need to change `hystrixdemo.enableriemann` to `true` in `archaius.properties`. 44 | This change will be active immediately. 45 | 46 | === Configuring Riemann Server 47 | 48 | In this setup the information about Hystrix commands is forwarded on a level of a single command execution. 49 | 50 | We can present it on this level, but usually you want to create aggreation on top of the event stream. The first listing aggregates the timings of the service `IBANValidatorCommand`. 51 | 52 | [source,closure,indent=0] 53 | .Percentiles with riemann.config 54 | ---- 55 | include::salt/roots/salt/riemann/files/default/etc/riemann/riemann.config[tags=percentile] 56 | ---- 57 | 58 | The second listing counts the different outcomes (SUCCESS, TIMEOUT, etc.) in every five second interval. This statement contains a statement for logging the aggregated events in the Riemann server log. 59 | 60 | [source,closure,indent=0] 61 | .Counting with riemann.config 62 | ---- 63 | include::salt/roots/salt/riemann/files/default/etc/riemann/riemann.config[tags=count] 64 | ---- 65 | 66 | === Configuring Riemann Dashboard 67 | 68 | You can configure the frontend of Riemann in your browser. This setup installs a dashboard that shows some useful information about the example application. 69 | 70 | [[img-riemanndashboard]] 71 | .Riemann Dashboard 72 | image::riemann_dashboard.png[Riemann Dashboard] 73 | 74 | In the lower part of the screen you will see a guide how to use keyboard shortcuts to customize the dashboard. 75 | 76 | As with the Zabbix monitoring, this will only show useful information once some commands are run. Please use the JMeter load test for this. 77 | -------------------------------------------------------------------------------- /tools/riemann/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | # Vagrantfile API/syntax version. Don't touch unless you know what you're doing! 5 | VAGRANTFILE_API_VERSION = "2" 6 | 7 | Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| 8 | # All Vagrant configuration is done here. The most common configuration 9 | # options are documented and commented below. For a complete reference, 10 | # please see the online documentation at vagrantup.com. 11 | 12 | # Every Vagrant virtual environment requires a box to build off of. 13 | config.vm.box = "bento/centos-6.7" 14 | 15 | if Vagrant.has_plugin?("vagrant-cachier") 16 | config.cache.scope = :box 17 | end 18 | 19 | # The url from where the 'config.vm.box' box will be fetched if it 20 | # doesn't already exist on the user's system. 21 | # config.vm.box_url = "http://domain.com/path/to/above.box" 22 | 23 | # Create a forwarded port mapping which allows access to a specific port 24 | # within the machine from a port on the host machine. 25 | 26 | # Riemann event port 27 | config.vm.network :forwarded_port, guest: 5555, host: 5555 28 | 29 | # Riemann Web Socket port 30 | config.vm.network :forwarded_port, guest: 5556, host: 5556 31 | 32 | # Riemann dashboard 33 | config.vm.network :forwarded_port, guest: 4567, host: 4567 34 | 35 | # Create a private network, which allows host-only access to the machine 36 | # using a specific IP. 37 | # config.vm.network :private_network, ip: "192.168.33.10" 38 | 39 | # Create a public network, which generally matched to bridged network. 40 | # Bridged networks make the machine appear as another physical device on 41 | # your network. 42 | # config.vm.network :public_network 43 | 44 | # If true, then any SSH connections made will enable agent forwarding. 45 | # Default value: false 46 | # config.ssh.forward_agent = true 47 | 48 | config.ssh.username = "root" 49 | config.ssh.password = "vagrant" 50 | 51 | # Provider-specific configuration so you can fine-tune various 52 | # backing providers for Vagrant. These expose provider-specific options. 53 | # Example for VirtualBox: 54 | # 55 | config.vm.provider :virtualbox do |vb| 56 | # Don't boot with headless mode 57 | # vb.gui = true 58 | # Use VBoxManage to customize the VM. For example to change memory: 59 | vb.customize ["modifyvm", :id, "--memory", "1024"] 60 | end 61 | # 62 | # View the documentation for the provider you're using for more 63 | # information on available options. 64 | 65 | if Vagrant.has_plugin?("vagrant-vbguest") 66 | # https://github.com/dotless-de/vagrant-vbguest 67 | # set auto_update to false, if you do NOT want to check the correct 68 | # additions version when booting this machine 69 | config.vbguest.auto_update = false 70 | 71 | # do NOT download the iso file from a webserver 72 | config.vbguest.no_remote = true 73 | end 74 | 75 | ## For masterless, mount your salt file root 76 | config.vm.synced_folder "salt/roots/", "/srv/" 77 | 78 | config.vm.provision :salt do |salt| 79 | salt.minion_config = "salt/minion" 80 | salt.run_highstate = true 81 | end 82 | 83 | end 84 | -------------------------------------------------------------------------------- /tools/riemann/manual/riemann_dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahus1/hystrix-examples/083327c17c31b57ed4a96078e0fbcf3e19f7d6b4/tools/riemann/manual/riemann_dashboard.png -------------------------------------------------------------------------------- /tools/riemann/salt/minion: -------------------------------------------------------------------------------- 1 | file_client: local 2 | master: localhost 3 | -------------------------------------------------------------------------------- /tools/riemann/salt/roots/pillar/top.sls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahus1/hystrix-examples/083327c17c31b57ed4a96078e0fbcf3e19f7d6b4/tools/riemann/salt/roots/pillar/top.sls -------------------------------------------------------------------------------- /tools/riemann/salt/roots/salt/riemann/dashboard/conf.sls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahus1/hystrix-examples/083327c17c31b57ed4a96078e0fbcf3e19f7d6b4/tools/riemann/salt/roots/salt/riemann/dashboard/conf.sls -------------------------------------------------------------------------------- /tools/riemann/salt/roots/salt/riemann/dashboard/init.sls: -------------------------------------------------------------------------------- 1 | riemann-dash: 2 | gem.installed: 3 | - user: rvm 4 | - require: 5 | - gem: riemann-client 6 | - gem: riemann-tools 7 | - gem: thin 8 | service: 9 | - running 10 | - enable: True 11 | - require: 12 | - file: /etc/init.d/riemann-dash 13 | 14 | /etc/init.d/riemann-dash: 15 | file: 16 | - managed 17 | - mode: 755 18 | - source: 19 | - salt://riemann/files/default/etc/init.d/riemann-dash 20 | - require: 21 | - file: /home/rvm 22 | - gem: riemann-dash 23 | 24 | /home/rvm: 25 | file.recurse: 26 | - source: salt://riemann/files/default/home/rvm 27 | - file_mode: 755 28 | 29 | gcc-c++: 30 | pkg.installed 31 | 32 | thin: 33 | gem.installed: 34 | - user: rvm 35 | - require: 36 | - pkg: gcc-c++ 37 | 38 | riemann-client: 39 | gem.installed: 40 | - user: rvm 41 | 42 | riemann-tools: 43 | gem.installed: 44 | - user: rvm 45 | 46 | -------------------------------------------------------------------------------- /tools/riemann/salt/roots/salt/riemann/files/default/etc/init.d/riemann-dash: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | ### BEGIN INIT INFO 3 | # Provides: riemann-dash 4 | # Required-Start: $all 5 | # Required-Stop: $all 6 | # Default-Start: 7 | # Default-Stop: 0 1 6 8 | # Short-Description: Starts Riemann 9 | # chkconfig: - 80 15 10 | # Description: Riemann event monitoring server. 11 | ### END INIT INFO 12 | 13 | # Source function library. 14 | . /etc/rc.d/init.d/functions 15 | 16 | # Pull in sysconfig settings 17 | [ -f /etc/sysconfig/riemann-dash ] && . /etc/sysconfig/riemann-dash 18 | 19 | RIEMANN_USER=rvm 20 | 21 | DAEMON=/home/rvm/riemann-dash 22 | NAME=riemann-dash 23 | PID_FILE=${PIDFILE:-/var/run/${NAME}.pid} 24 | LOCK_FILE=${LOCKFILE:-/var/lock/subsys/${NAME}} 25 | NFILES=${NFILES:-32768} 26 | 27 | start() { 28 | echo -n $"Starting ${NAME}: " 29 | ulimit -n $NFILES 30 | daemonize -u $RIEMANN_USER -c /home/rvm -p $PID_FILE -l $LOCK_FILE $DAEMON 31 | RETVAL=$? 32 | echo 33 | [ $RETVAL -eq 0 ] && touch $LOCK_FILE 34 | return $RETVAL 35 | } 36 | 37 | stop() { 38 | echo -n $"Stopping ${NAME}: " 39 | # killproc -p ${PID_FILE} -d 10 $DAEMON 40 | killall -u rvm 41 | RETVAL=$? 42 | echo 43 | [ $RETVAL = 0 ] && rm -f ${LOCK_FILE} ${PID_FILE} 44 | return $RETVAL 45 | } 46 | 47 | case "$1" in 48 | start) 49 | start 50 | ;; 51 | stop) 52 | stop 53 | ;; 54 | status) 55 | status -p ${PID_FILE} $DAEMON 56 | RETVAL=$? 57 | ;; 58 | restart|reload|fore-reload) 59 | stop 60 | start 61 | ;; 62 | *) 63 | N=/etc/init.d/${NAME} 64 | echo "Usage: $N {start|stop|status|restart|force-reload}" >&2 65 | RETVAL=2 66 | ;; 67 | esac 68 | 69 | exit $RETVAL 70 | -------------------------------------------------------------------------------- /tools/riemann/salt/roots/salt/riemann/files/default/etc/riemann/riemann.config: -------------------------------------------------------------------------------- 1 | ; -*- mode: clojure; -*- 2 | ; vim: filetype=clojure 3 | 4 | (logging/init {:file "/var/log/riemann/riemann.log"}) 5 | 6 | ; Listen on the local interface over TCP (5555), UDP (5555), and websockets 7 | ; (5556) 8 | ; (let [host "127.0.0.1"] 9 | (let [host "0.0.0.0"] 10 | (tcp-server {:host host}) 11 | (udp-server {:host host}) 12 | (ws-server {:host host})) 13 | 14 | ; Expire old events from the index every 5 seconds. 15 | (periodically-expire 5) 16 | 17 | (let [index (index)] 18 | ; Inbound events will be passed to these streams: 19 | (streams 20 | (default :ttl 60 21 | ; Index all events immediately. 22 | index 23 | 24 | ; log all events 25 | ; #(info "received event" %) 26 | 27 | ; Log expired events. 28 | (expired 29 | (fn [event] (info "expired" event)) 30 | ) 31 | ) 32 | ) 33 | ) 34 | 35 | 36 | ; tag::percentile[] 37 | (let [index (index)] 38 | (streams 39 | (where (and (= service "IBANValidatorCommand") (not (= metric nil)) ) 40 | 41 | ; Now, we'll calculate the 50th, 95th, and 99th percentile for all 42 | ; requests in each 5-second interval. 43 | 44 | (percentiles 5 [0.5 0.95 0.99] 45 | 46 | ; Percentiles will emit events like 47 | ; {:service "api req 0.5" :metric 0.12} 48 | ; We'll add them to the index, so they can show up 49 | ; on our dashboard. 50 | 51 | index) 52 | ) 53 | ) 54 | ) 55 | ; end::percentile[] 56 | 57 | ; tag::count[] 58 | (let [index (index)] 59 | (streams 60 | (where (and (= service "IBANValidatorCommand") (= metric nil) ) 61 | 62 | (by :state 63 | (with :metric 1 (with :service "IBAN Count" 64 | (rate 5 65 | ; log all events (for debugging) 66 | #(info "received event" %) 67 | index 68 | ) 69 | )) 70 | ) 71 | 72 | ) 73 | ) 74 | ) 75 | ; end::count[] 76 | -------------------------------------------------------------------------------- /tools/riemann/salt/roots/salt/riemann/files/default/home/rvm/config.rb: -------------------------------------------------------------------------------- 1 | set :port, 4567 # HTTP server on port 6000 2 | set :bind, "0.0.0.0" # Bind to a different interface 3 | config[:ws_config] = 'custom/config.json' 4 | 5 | -------------------------------------------------------------------------------- /tools/riemann/salt/roots/salt/riemann/files/default/home/rvm/custom/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "server": "127.0.0.1:5556", 3 | "server_type": "ws", 4 | "workspaces": [ 5 | { 6 | "name": "Riemann", 7 | "view": { 8 | "type": "Balloon", 9 | "weight": 1, 10 | "id": "7fff064a3a9a3b0f32f5b4012ac691fb7c1721a8", 11 | "version": 26, 12 | "child": { 13 | "type": "VStack", 14 | "weight": 1, 15 | "id": "170f34d010f5b4ae081a056469aaf4307d3994f1", 16 | "version": 26, 17 | "children": [ 18 | { 19 | "type": "HStack", 20 | "weight": 1, 21 | "id": "d3270ce28c19785f0e48c781caab19ed0b5a2d5f", 22 | "version": 26, 23 | "children": [ 24 | { 25 | "type": "Log", 26 | "weight": 1, 27 | "id": "c01bf747ea8874b01335e5db3bf5eea741fe00c5", 28 | "version": 7, 29 | "title": "Riemann", 30 | "query": "(service = \"IBANValidatorCommand\" and metric = nil)", 31 | "lines": "50" 32 | }, 33 | { 34 | "type": "Flot", 35 | "weight": 1, 36 | "id": "b7b1e435989847d91d3f28356ad9484e03644242", 37 | "version": 7, 38 | "title": "5 sec percentiles", 39 | "query": "(service ~= \"IBANValidatorCommand .*\" and metric != nil)", 40 | "max": null, 41 | "timeRange": 300, 42 | "graphType": "line", 43 | "stackMode": "false" 44 | }, 45 | { 46 | "type": "VStack", 47 | "weight": 1, 48 | "id": "26c22e129d89e8373acfcf7d0a408f16f2b6e8f8", 49 | "version": 2, 50 | "children": [ 51 | { 52 | "type": "Grid", 53 | "weight": 1, 54 | "id": "885c1bd19d44c9040014bcd7d2eb657a3d87cc3c", 55 | "version": 11, 56 | "title": "", 57 | "query": "(service = \"IBAN Count\")", 58 | "max": "all", 59 | "rows": "service", 60 | "cols": "state", 61 | "row_sort": "lexical", 62 | "col_sort": "lexical" 63 | }, 64 | { 65 | "type": "Gauge", 66 | "weight": 1, 67 | "id": "9956b2bb62422bc22a28a2908723591d59438683", 68 | "version": 1, 69 | "title": "Time (ms)", 70 | "query": "(service = \"IBANValidatorCommand\" and metric != nil)" 71 | } 72 | ] 73 | } 74 | ] 75 | }, 76 | { 77 | "type": "Help" 78 | } 79 | ] 80 | } 81 | }, 82 | "id": "cd55ccfec88fc1d947ed706dbf8d6fb1d275c0e5" 83 | } 84 | ] 85 | } -------------------------------------------------------------------------------- /tools/riemann/salt/roots/salt/riemann/files/default/home/rvm/riemann-dash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Get the aliases and functions 4 | if [ -f ~/.bashrc ]; then 5 | . ~/.bashrc 6 | fi 7 | 8 | # User specific environment and startup programs 9 | 10 | PATH=$PATH:$HOME/bin 11 | 12 | export PATH 13 | 14 | [[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm" # Load RVM into a shell session *as a function* 15 | 16 | riemann-dash 17 | -------------------------------------------------------------------------------- /tools/riemann/salt/roots/salt/riemann/server/conf.sls: -------------------------------------------------------------------------------- 1 | include: 2 | - riemann.server 3 | 4 | {% set files_switch = salt['pillar.get']('riemann-server:files_switch', ['id']) %} 5 | 6 | /etc/riemann/riemann.config: 7 | file: 8 | - managed 9 | - source: 10 | {% for grain in files_switch if salt['grains.get'](grain) is defined -%} 11 | - salt://riemann/files/{{ salt['grains.get'](grain) }}/etc/riemann/riemann.config 12 | {% endfor -%} 13 | - salt://riemann/files/default/etc/riemann/riemann.config 14 | - require: 15 | - pkg: riemann-server 16 | - watch_in: 17 | - service: riemann-server 18 | -------------------------------------------------------------------------------- /tools/riemann/salt/roots/salt/riemann/server/init.sls: -------------------------------------------------------------------------------- 1 | daemonize: 2 | pkg.installed 3 | 4 | java: 5 | pkg.installed: 6 | - pkgs: 7 | - java-1.7.0-openjdk-devel 8 | 9 | riemann-server: 10 | pkg.installed: 11 | - sources: 12 | - riemann: http://aphyr.com/riemann/riemann-0.2.6-1.noarch.rpm 13 | - require: 14 | - pkg: daemonize 15 | - pkg: java 16 | service: 17 | - name: riemann 18 | - running 19 | - enable: True 20 | - require: 21 | - pkg: riemann-server 22 | -------------------------------------------------------------------------------- /tools/riemann/salt/roots/salt/rvm/init.sls: -------------------------------------------------------------------------------- 1 | rvm: 2 | group: 3 | - present 4 | user.present: 5 | - gid: rvm 6 | - home: /home/rvm 7 | - require: 8 | - group: rvm 9 | 10 | rvm-deps: 11 | pkg.installed: 12 | - refresh: False 13 | - names: 14 | - bash 15 | - coreutils 16 | - gzip 17 | - bzip2 18 | - gawk 19 | - sed 20 | - curl 21 | - subversion 22 | 23 | mri-deps: 24 | pkg.installed: 25 | - refresh: False 26 | - names: 27 | - openssl 28 | - curl 29 | - autoconf 30 | - automake 31 | - libtool 32 | - bison 33 | - subversion 34 | - ruby 35 | - zlib-devel 36 | - patch 37 | - openssl-devel 38 | - libxml2 39 | - libxml2-devel 40 | - readline 41 | - readline-devel 42 | 43 | 44 | gpg-import-D39DC0E3: 45 | cmd.run: 46 | - user: rvm 47 | - require: 48 | - user: rvm 49 | - name: gpg --keyserver hkp://keys.gnupg.net:80 --recv-keys D39DC0E3 50 | - unless: gpg --fingerprint |fgrep 'Key fingerprint = 409B 6B17 96C2 7546 2A17 0311 3804 BB82 D39D C0E3' 51 | 52 | ruby-2.0.0: 53 | rvm.installed: 54 | - default: True 55 | - user: rvm 56 | - require: 57 | - pkg: rvm-deps 58 | - pkg: mri-deps 59 | - user: rvm 60 | - failhard: True 61 | - require: 62 | - cmd: gpg-import-D39DC0E3 63 | -------------------------------------------------------------------------------- /tools/riemann/salt/roots/salt/top.sls: -------------------------------------------------------------------------------- 1 | base: 2 | '*': 3 | - riemann.server.conf 4 | - rvm 5 | - riemann.dashboard -------------------------------------------------------------------------------- /tools/tomcat/.gitignore: -------------------------------------------------------------------------------- 1 | /apache-tomcat-* 2 | -------------------------------------------------------------------------------- /tools/tomcat/README.adoc: -------------------------------------------------------------------------------- 1 | :imagesdir: manual 2 | :javasourcedir: ../hystrix-application/src/main/java 3 | 4 | == Starting up the application container 5 | 6 | === Apache Tomcat is is an easy to use servlet container 7 | 8 | http://tomcat.apache.org[Apache Tomcat] is a servlet container. It can run JavaEE Web applications like our JAX-RS applications. 9 | 10 | Tomcat Version 8 is implementing the JavaEE 7 standard supporting 11 | the latest APIs. 12 | 13 | === Installing and running Apache Tomcat 14 | 15 | Installation is straight forward: After the download only few 16 | configuration steps are necessary. 17 | 18 | All of these have been prepared in the script `tools/tomcat/run-tomcat.bat`. When you start it the first time, the the script will download the installation archive, unzip it and update the configuration. 19 | 20 | ==== Activated Apache Tomcat features 21 | 22 | The following features are being set up using the automatic installation: 23 | 24 | In `setenv.bat`: 25 | 26 | . Allow Java remote debugging on port 1044 + 27 | [source] 28 | -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1044 29 | 30 | In `context.xml`: 31 | 32 | . Activate `antiResourceLocking` to allow hot-deployment of applications when running Microsoft Windows as operating system 33 | 34 | In `tomcat-users.xml`: 35 | 36 | . Setup an user `deploy` with password `deploy` to automatically deploy an application. 37 | . Setup an user `tomcat` with password `tomcat` to allow login on the management GUI. 38 | 39 | ==== Testing the Apache Tomcat installation 40 | 41 | To test the application point your browser at http://localhost:8080. You should see an Apache Tomcat start page with the welcome message (see figure <>). 42 | 43 | [[img-tomcatwelcome]] 44 | .Apache Tomcat Welcome Message 45 | image::tomcatwelcome.png[Tomcat Welcome Message] 46 | 47 | Click on the button *Manager App* and you will be asked for a user name and password. Use the user `tomcat` with the password stated above to log in. 48 | 49 | [[archaius]] 50 | == Using runtime configuration 51 | 52 | === Runtime configuration will get you credits 53 | 54 | If you would write applications that would require a restart every 55 | time you change a setting, it will deter your users as you will have 56 | a downtime. 57 | 58 | How nice if you could change all your settings at runtime! No more night shifts for IT operating to change parameters and restart the services! 59 | 60 | === Netflix Archaius to the rescue 61 | 62 | Hystrix is integrated already with https://github.com/Netflix/archaius[Archaius^] that handles runtime 63 | configuration for you. When implementing `IBANValidator` you've seen the dynamic property being introduced: 64 | 65 | [source,java,indent=0] 66 | .IBANValidator.java 67 | ---- 68 | include::../{javasourcedir}/de/ahus1/hystrix/base/IBANValidator.java[tags=dynprop] 69 | ---- 70 | 71 | This will create a dynamic property. When it's being accessed, it will always return the most up to date value for it. When the external configuration doesn't define a value the default of 100 will be returned. 72 | 73 | In more advanced situations you can also register a callback to be notified whenever a configuration changes. Please refer to the https://github.com/Netflix/archaius/wiki[Archaius Wiki^] to find out more about it. 74 | 75 | === How runtime configuration works in this project 76 | 77 | Archaius supports multiple back ends to store configuration data. In this setup all configuration is stored in a Java properties file. Archaius checks this file every second. 78 | 79 | This is configured as follows: 80 | 81 | [source] 82 | .setenv.bat 83 | ---- 84 | -Darchaius.configurationSource.additionalUrls=file:///%CATALINA_HOME%/../archaius.properties 85 | -Darchaius.fixedDelayPollingScheduler.delayMills=1000 86 | -Darchaius.fixedDelayPollingScheduler.initialDelayMills=1000 87 | ---- 88 | 89 | This allows you to change the dynamic: 90 | 91 | [source] 92 | .archaius.properties 93 | hystrixdemo.sleep=10 94 | 95 | This will override the default setting with 10. 96 | 97 | === Configuring the Hystrix command via Archaius 98 | 99 | All Hystrix settings can be configured on default and on command level. Please refer to the https://github.com/Netflix/Hystrix/wiki/Configuration[Configuration Wiki of Hystrix] for an in-depth discussion. This will now show the core parameters and configure them on default level: 100 | 101 | [source] 102 | .archaius.properties 103 | ---- 104 | include::archaius.properties[tags=hystrixcommand] 105 | ---- 106 | 107 | To give these parameters a try you should set up a load test. You'll see in the next chapter how you can do this. But first deploy the application to this freshly installed Tomcat! 108 | -------------------------------------------------------------------------------- /tools/tomcat/archaius.properties: -------------------------------------------------------------------------------- 1 | 2 | # sleep 100 ms => 25% rejected; 3 | # sleep 200 ms => 60% rejected, will trip errorThresholdPercentage 4 | hystrixdemo.sleep=100 5 | 6 | # tag::turbine[] 7 | turbine.instanceUrlSuffix=:8080/hystrixapp/hystrix.stream 8 | turbine.ConfigPropertyBasedDiscovery.default.instances=localhost 9 | turbine.ConfigPropertyBasedDiscovery.localhost.instances=localhost 10 | # end::turbine[] 11 | 12 | hystrixdemo.enablezabbix=false 13 | 14 | hystrixdemo.enableriemann=false 15 | 16 | # See 17 | # https://github.com/Netflix/Hystrix/wiki/Configuration 18 | # for all configuration options of Hystrix 19 | 20 | # How Hystrix decouples the program from the command 21 | # default: THREAD 22 | # other: SEMAPHORE 23 | hystrix.command.default.execution.isolation.strategy=THREAD 24 | 25 | # What is the timeout for a Hystrix command? 26 | # default: 1000 27 | hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=1000 28 | 29 | # tag::hystrixcommand[] 30 | # Should Hystrix interrupt a command that is overdue? 31 | # default: true 32 | hystrix.command.default.execution.isolation.thread.interruptOnTimeout=true 33 | 34 | # How many errors are allowed before the circuit breaker is activated? 35 | # default: 50 (must be greater than 0, 36 | # 100 means no breaking despite of errors) 37 | hystrix.command.default.circuitBreaker.errorThresholdPercentage=50 38 | 39 | # How many requests are needed in the time span to trigger the circuit breaker? 40 | # default: 20 41 | hystrix.command.default.circuitBreaker.requestVolumeThreshold=20 42 | 43 | # After what time (in ms) should the circuit breaker try a single request? 44 | # default: 5000 45 | hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=5000 46 | 47 | # end::hystrixcommand[] 48 | -------------------------------------------------------------------------------- /tools/tomcat/files/index.jsp: -------------------------------------------------------------------------------- 1 | 2 | 3 | /hystrixapp 4 | 5 | -------------------------------------------------------------------------------- /tools/tomcat/files/setenv.bat: -------------------------------------------------------------------------------- 1 | set CATALINA_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=1044 -Darchaius.configurationSource.additionalUrls=file:///%CATALINA_HOME%/../archaius.properties -Darchaius.fixedDelayPollingScheduler.delayMills=1000 -Darchaius.fixedDelayPollingScheduler.initialDelayMills=1000 -------------------------------------------------------------------------------- /tools/tomcat/manual/tomcatwelcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahus1/hystrix-examples/083327c17c31b57ed4a96078e0fbcf3e19f7d6b4/tools/tomcat/manual/tomcatwelcome.png -------------------------------------------------------------------------------- /tools/tomcat/run-tomcat.bat: -------------------------------------------------------------------------------- 1 | powershell set-executionpolicy remotesigned 2 | powershell ./run-tomcat.ps1 -------------------------------------------------------------------------------- /tools/tomcat/run-tomcat.ps1: -------------------------------------------------------------------------------- 1 | # change version number and hash code as shown on Apache download page 2 | # http://tomcat.apache.org/download-80.cgi 3 | $version="8.0.45" 4 | $masterhash = "ffa9b438c8b74d03aa6fd5255e80bbc9" 5 | 6 | $url = "http://www.eu.apache.org/dist/tomcat/tomcat-8/v$version/bin/apache-tomcat-$version.zip" 7 | 8 | # see if folder has been created 9 | If (-not (Test-Path "apache-tomcat-$version")) { 10 | 11 | # see if ZIP file exists 12 | If (-not (Test-Path "apache-tomcat-$version.zip")) { 13 | "downloading installation archive from $url" 14 | # proxy setting not needed, will do this automatically 15 | # $proxy = [System.Net.WebRequest]::GetSystemWebProxy() 16 | # $proxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials # 17 | $webclient = New-Object System.Net.WebClient 18 | # $webclient.proxy = $proxy 19 | $webclient.DownloadFile($url,"apache-tomcat-$version.zip") 20 | } 21 | 22 | # create a md5 hash code from ZIP file and normalize it 23 | "verifying hash code" 24 | $md5 = new-object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider 25 | $hash = [System.BitConverter]::ToString($md5.ComputeHash([System.IO.File]::ReadAllBytes("apache-tomcat-$version.zip"))) 26 | $hash = $hash.replace("-","").toLower() 27 | 28 | # check if hash codes match 29 | If ($hash -ne $masterhash) { 30 | "Hash of master file $masterhash doesn't match downloaded file $hash. ZIP file is possibly corrupted" 31 | exit 32 | } 33 | 34 | "install tomcat" 35 | $shell_app=new-object -com shell.application 36 | (Get-Location).Path + "\apache-tomcat-$version.zip" 37 | $zip_file = $shell_app.namespace((Get-Location).Path + "\apache-tomcat-$version.zip") 38 | (Get-Location).Path 39 | $destination = $shell_app.namespace((Get-Location).Path) 40 | $destination.Copyhere($zip_file.items()) 41 | } 42 | 43 | "configuring tomcat" 44 | # setup parameters used for hystrix and remote debugging 45 | copy files/setenv.bat "apache-tomcat-$version/bin" 46 | 47 | # patch tomcat users 48 | $xml = [xml](Get-Content ./apache-tomcat-$version/conf/tomcat-users.xml) 49 | $xml.'tomcat-users'.set_InnerXML("") 50 | $xml.Save("./apache-tomcat-$version/conf/tomcat-users.xml") 51 | 52 | # patch context 53 | $xml = [xml](Get-Content ./apache-tomcat-$version/conf/context.xml) 54 | $xml.Context.SetAttribute("antiResourceLocking", "true") 55 | $xml.Save("./apache-tomcat-$version/conf/context.xml") 56 | 57 | "starting tomcat" 58 | cp "files/index.jsp" "apache-tomcat-$version/webapps/root" 59 | cd "apache-tomcat-$version/bin" 60 | start-process startup.bat 61 | 62 | -------------------------------------------------------------------------------- /tools/travis/README.adoc: -------------------------------------------------------------------------------- 1 | == Building the documentation automatically 2 | 3 | === Things that need maintenance 4 | 5 | This manual is written in Asciidoc format. Asciidoctor is used to create an online documentation from it. 6 | 7 | This can be done manually by calling `manual/build.bat`. The changes then need to be published to the `gh-pages` branch. 8 | 9 | To find out more about Asciidoc and Asciidoctor see see section <>. To find out more about GitHub Pages see https://pages.github.com/. 10 | 11 | === Travis CI as a service in the cloud 12 | 13 | Travis CI is a build service in the clould that is free to all open source projects. It integrates well with GitHub. A new build is triggered on every push to your repository. 14 | 15 | The following bit's and pieces are needed: 16 | 17 | . Hook up http://travis-ci.org/ to your repository. 18 | . Add a file `.travis.yml` to the root of the repository. In our case this indicates to Travis that we want to use Ruby. 19 | . Add a file `Gemfile` to the root of the repository to specify the dependencies of Asciidoctor. 20 | . Add a file `manual/build.sh` to the project to copy images in the proper place, and run asciidoctor. 21 | . Add a file `manual/update-gh-pages.sh` to store the created Asciidoctor output to the repositories GitHub pages branch. 22 | 23 | You can see the current status of the build here: https://travis-ci.org/ahus1/hystrix-examples. 24 | -------------------------------------------------------------------------------- /tools/turbine/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /tools/turbine/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahus1/hystrix-examples/083327c17c31b57ed4a96078e0fbcf3e19f7d6b4/tools/turbine/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /tools/turbine/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.3/apache-maven-3.3.3-bin.zip -------------------------------------------------------------------------------- /tools/turbine/README.adoc: -------------------------------------------------------------------------------- 1 | == Aggregating Hystrix runtime information in a cluster 2 | 3 | === Turbine aggregates runtime information 4 | 5 | https://github.com/Netflix/Turbine[Netflix Turbine] is a web application that connects to instances of your Hystrix application in a cluster and aggregates the information. 6 | 7 | It does this in real time. The results will be updated every 0.5 seconds. 8 | 9 | === Installing and running Turbine 10 | 11 | The installation has been scripted for you: You need to run `tools/turbine/maven-package-deploy.bat`. 12 | 13 | The current installation will re-package the 0.4 version of Turbine and add to it the latest (yet unreleased) changes to allow easy re-deployment. Please have a look into `pom.xml` to see how you can adopt an already packaged WAR file to your environment. 14 | 15 | You can open the URL http://localhost:8080/turbine/turbine.stream in a Google Chrome browser to see the stream of events. If there are no Hystrix requests, you'll see only "ping" messages. You can't test this with Mozilla Firefox or Microsoft Internet Explorer as they will open only a file download dialogue. 16 | 17 | === Configuration for Turbine 18 | 19 | ==== Configuration Turbine metadata 20 | 21 | Turbine uses the same configuration mechanism as Hystrix: Archaius. See chapter "<> for more information. The following configuration has already been set up for you in `archaius.properties`: 22 | 23 | [source] 24 | .archaius.properties 25 | ---- 26 | include::../tomcat/archaius.properties[tags=turbine] 27 | ---- 28 | 29 | `turbine.instanceUrlSuffix`: This URL suffix needs to be the same for all applications in the cluster. Turbine uses this endpoint to receive a stream of runtime information. 30 | 31 | `turbine.ConfigPropertyBasedDiscovery.default.instances`: This lists the hosts Turbine should poll information from. In a production system there are mechanisms to discover hosts automatically. In our test scenario a list is sufficient as we have only one host. 32 | 33 | ==== Preparing your application for Turbine 34 | 35 | To have your application publishing the information on the URL suffix above, you'll need to add a servlet to your application. This has already been packaged for you. You'll just need to include as a dependency of your application in `pom.xml`: 36 | 37 | [source,xml,indent=0] 38 | .pom.xml 39 | ---- 40 | include::../../hystrix-application/pom.xml[tags=turbine] 41 | ---- 42 | 43 | Then you register it in `web.xml` as a servlet: 44 | 45 | [source,xml,indent=0] 46 | .web.xml 47 | ---- 48 | include::../../hystrix-application/src/main/webapp/WEB-INF/web.xml[tags=turbine] 49 | ---- 50 | 51 | You can open the URL http://localhost:8080/hystrixapp/hystrix.stream in a Google Chrome browser to see the stream of events. If there are no Hystrix requests, you'll see only "ping" messages. You can't test this with Mozilla Firefox or Microsoft Internet Explorer as they will open only a file download dialogue. 52 | 53 | To visualize it, see the next chapter about Hystrix dashboard. 54 | -------------------------------------------------------------------------------- /tools/turbine/maven-package-deploy.bat: -------------------------------------------------------------------------------- 1 | call %~dp0mvnw clean package cargo:redeploy 2 | -------------------------------------------------------------------------------- /tools/turbine/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | set MAVEN_CMD_LINE_ARGS=%MAVEN_CONFIG% %* 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | 121 | set WRAPPER_JAR=""%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"" 122 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 123 | 124 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS% 125 | if ERRORLEVEL 1 goto error 126 | goto end 127 | 128 | :error 129 | set ERROR_CODE=1 130 | 131 | :end 132 | @endlocal & set ERROR_CODE=%ERROR_CODE% 133 | 134 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 135 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 136 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 137 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 138 | :skipRcPost 139 | 140 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 141 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 142 | 143 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 144 | 145 | exit /B %ERROR_CODE% 146 | -------------------------------------------------------------------------------- /tools/turbine/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | de.ahus1.hystrix 4 | turbine 5 | 0.4.2-SNAPSHOT 6 | war 7 | 8 | Turbine 9 | 10 | 11 | 12 | com.netflix.turbine 13 | turbine-web 14 | war 15 | 1.0.0 16 | 17 | 18 | com.netflix.turbine 19 | turbine-core 20 | 1.0.0 21 | 22 | 23 | servlet-api 24 | javax.servlet 25 | 2.5 26 | provided 27 | 28 | 29 | 30 | 31 | 32 | turbine 33 | 34 | 35 | 36 | org.codehaus.cargo 37 | cargo-maven2-plugin 38 | 1.4.2 39 | 40 | 41 | tomcat7x 42 | remote 43 | 44 | 45 | runtime 46 | 47 | 48 | http://localhost:8080/manager/text 49 | 50 | 51 | deploy 52 | 53 | 54 | deploy 55 | 56 | 57 | 58 | 59 | remote 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | org.apache.maven.plugins 70 | maven-war-plugin 71 | 2.4 72 | 73 | 74 | 75 | 76 | 77 | 78 | com.netflix.turbine 79 | turbine-web 80 | 81 | 82 | WEB-INF/lib/servlet-api-2.5.jar 83 | 84 | WEB-INF/classes/config.properties 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | org.slf4j 97 | slf4j-api 98 | 1.6.4 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /tools/zabbix/README.adoc: -------------------------------------------------------------------------------- 1 | // using experimental to support btn: macro 2 | :experimental: 3 | 4 | == Long term monitoring of Hystrix metrics 5 | 6 | === Zabbix as classic long term monitoring and notification 7 | 8 | http://zabbix.com/[Zabbix^] is a classic monitoring system. It is stable and it has grown over several iterations. It supports a REST API out of the box. 9 | 10 | All data is stored in a database. The server polls information from clients, runs commands or receives information from agents. 11 | 12 | A frontend service will provide a web interface that includes configuration, monitoring and graphing capabilities. 13 | 14 | === Installing and running Zabbix 15 | 16 | The installation has been scripted as a http://vagrantup.com[Vagrant^] script. This will first download a linux image of CentOS and spin it up in http://virtualbox.org/[Virtualbox^]. Then it will hand over to a provisioner, in our case this is http://saltstack.com/[Saltstack^]. 17 | 18 | To install Vagrant please see <>. Once it is installed, 19 | run the follwing command in `tools/zabbix`: 20 | 21 | ---- 22 | vagrant up 23 | ---- 24 | 25 | This will take a while to download all the files necessary. Once it is up and running point your browser at your local Zabbix installation: http://localhost:2280/zabbix. 26 | 27 | Use Username `Admin` password `zabbix` to log in (please note the capital *A* in the user name) 28 | 29 | === Configuration of Zabbix 30 | 31 | All configuration items could be automated using the REST API. This will be a future task for this tutorial. 32 | 33 | // TODO 34 | 35 | For now these are the manual steps: 36 | 37 | . In menu:Configuration[Templates] click on btn:[Import]. Pick the file `hystrix_template.xml` from `tools\zabbix`. Click on btn:[Import]. 38 | . Choose menu:Configuration[Templates] again. You see a `hystrixTemplate` here. Click on this template to edit it. Include the host `hystrix` in group `Discovered Hosts` in the shuttle view to put it on the left side. This will apply the template to the host. Click on btn:[Save]. 39 | . In menu:Configuration[Host] click on btn:[Create Host]. Enter `hystrix` as host name here. Pick `Discovered Hosts` as the Host group. Now btn:[Save]. 40 | 41 | This is all configuration that is needed: You have created a host, and you have associated it with a template that will autodiscover all Hystrix comamnds. 42 | 43 | === Configuration of the example application 44 | 45 | As default the Zabbix agent in the application is disabled. To enable it, go to the file `archaius.properties`. Change the `hystrixdemo.enablezabbix` to be true. 46 | 47 | The change is active at runtime. This will trigger the activation in `HystrixSetupListener`. 48 | 49 | === Zabbix autodiscovery at work 50 | 51 | The following steps will now happen automatically: 52 | 53 | . The Zabbix agent will connect to `127.0.0.1:10051` and identifies itself as host `hystrix`. In our example this is hardcoded. 54 | . The Zabbix agent asks the server for any scheduled checks. The only check that is configured for the host `hystrix` is the `hystrixCommand.discovery` in the template. 55 | . The agent runs the check and delivers all active Hystrix commands as a JSON object to the server. 56 | . This will trigger the auto discovery. For every command Zabbix will create 20 items and three graphs. 57 | . When the Zabbix agent reloads the list of checks after a minute, there will be a lot more checks. It will run them as specified in the interval of the template we imported to Zabbix. 58 | 59 | The auto discovery rule is set to run every five seconds. Please note that the auto discovery will only find commands that have been triggered at least once during the runtime of the application. Hystrix will only notify our Zabbix agent at the first created command. 60 | 61 | Please choose menu:Configuration[Hosts] and you should see the number of Items change for the host `hystrix`. Please refresh your browser if necessary. 62 | 63 | Now choose menu:Monitoring[Graphs] and choose the host `hystrix` and any of the three graphs. After a few minutes you should see the first graphs appearing. The following screen shows a service that was answering successfully first. After a short time the response time was changed to 250 ms. Soon lots of rejected and timeout requests appear. 64 | 65 | .Zabbix counting Hystrix requests 66 | image::requestcount_zabbix.png[Zabbix counting Hystrix requests] 67 | 68 | Zabbix polls for the command data every minute. Change the timing in `archaius.properties` to see information about failed requests. 69 | 70 | Click on menu:Monitoring[Latest data] to see the latest values that the agent has sent. 71 | 72 | === Java classes to forward information from Hystrix to Zabbix 73 | 74 | In order to activate the forwarding of events, you'll need to change `hystrixdemo.enablezabbix` to `true` in `archaius.properties`. 75 | This change will be active immediately. 76 | 77 | The property `hystrixdemo.enablezabbix` in `archaius.properties` is evaluated in the class `HystrixSetupListener`. When this property is enabled, the Zabbix agent is started. 78 | 79 | You find all additional classes in the package `de.ahus1.hystrix.util.zabbix` in the example application. The following classes work together to forward the information to Zabbix: 80 | 81 | . `ZabbixCommandMetricsProvider` is registered with Zabbix. It handles the connection to Zabbix. It creates a callback `ZabbixCommandMetricsProvider` that will be called by the agent when it requires data for the provider `hystrixCommand`. It creates for Zabbix on request a `HystrixZabbixMetricsPublisherCommand` when a command is created for the first time. 82 | . Once the `HystrixZabbixMetricsPublisherCommand` initialized, it registers itself with the `ZabbixCommandMetricsProvider`. 83 | . The `ZabbixCommandMetricsProvider` will provide a list of HystrixCommand keys when it is called with `hystrixCommand.discovery` When it is called `hystrixCommand.countSuccess[{#COMMAND}]` it returns the current count of successful Hystrix command calls. 84 | 85 | The current implementation doesn't return any information about thread pools yet. 86 | 87 | === Working with templates in Zabbix 88 | 89 | When you change your template, the changes are applied to all hosts assigned to the template. This makes it easy to ensure a common configuration of all Hystrix commands throughout your infrastructure. 90 | 91 | You can also choose to setup triggers automatically. 92 | 93 | When a command is no longer used in your application, the auto discovery will no longer return it to Hystrix. Hystrix will remove all items that are no longer needed after 30 days. You can simulate this behaviour by stopping/starting the tomcat server and not sending any requests via JMeter. As now commands will be triggered, the list of auto-discovered commands is empty. A few seconds later Zabbix will add a yellow exclamation mark to your items and will start the 30 day countdown. 94 | -------------------------------------------------------------------------------- /tools/zabbix/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | # Vagrantfile API/syntax version. Don't touch unless you know what you're doing! 5 | VAGRANTFILE_API_VERSION = "2" 6 | 7 | Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| 8 | # All Vagrant configuration is done here. The most common configuration 9 | # options are documented and commented below. For a complete reference, 10 | # please see the online documentation at vagrantup.com. 11 | 12 | # Every Vagrant virtual environment requires a box to build off of. 13 | config.vm.box = "bento/centos-6.7" 14 | 15 | if Vagrant.has_plugin?("vagrant-cachier") 16 | config.cache.scope = :box 17 | end 18 | 19 | # The url from where the 'config.vm.box' box will be fetched if it 20 | # doesn't already exist on the user's system. 21 | # config.vm.box_url = "http://domain.com/path/to/above.box" 22 | 23 | # Create a forwarded port mapping which allows access to a specific port 24 | # within the machine from a port on the host machine. 25 | 26 | # Zabbix web frontend 27 | config.vm.network :forwarded_port, guest: 80, host: 2280 28 | 29 | # Zabbix agent port 30 | config.vm.network :forwarded_port, guest: 10051, host: 10051 31 | 32 | # Create a private network, which allows host-only access to the machine 33 | # using a specific IP. 34 | # config.vm.network :private_network, ip: "192.168.33.10" 35 | 36 | # Create a public network, which generally matched to bridged network. 37 | # Bridged networks make the machine appear as another physical device on 38 | # your network. 39 | # config.vm.network :public_network 40 | 41 | # If true, then any SSH connections made will enable agent forwarding. 42 | # Default value: false 43 | # config.ssh.forward_agent = true 44 | 45 | # Provider-specific configuration so you can fine-tune various 46 | # backing providers for Vagrant. These expose provider-specific options. 47 | # Example for VirtualBox: 48 | # 49 | config.vm.provider :virtualbox do |vb| 50 | # Don't boot with headless mode 51 | # vb.gui = true 52 | # Use VBoxManage to customize the VM. For example to change memory: 53 | vb.customize ["modifyvm", :id, "--memory", "1024"] 54 | end 55 | # 56 | # View the documentation for the provider you're using for more 57 | # information on available options. 58 | 59 | if Vagrant.has_plugin?("vagrant-vbguest") 60 | # https://github.com/dotless-de/vagrant-vbguest 61 | # set auto_update to false, if you do NOT want to check the correct 62 | # additions version when booting this machine 63 | config.vbguest.auto_update = false 64 | 65 | # do NOT download the iso file from a webserver 66 | config.vbguest.no_remote = true 67 | end 68 | 69 | ## For masterless, mount your salt file root 70 | config.vm.synced_folder "salt/roots/", "/srv/" 71 | 72 | config.vm.provision :salt do |salt| 73 | salt.minion_config = "salt/minion" 74 | salt.run_highstate = true 75 | # https://github.com/mitchellh/vagrant/issues/5973 76 | # "Failed to upload a file to the guest VM..." 77 | salt.bootstrap_options = '-F -c /tmp/ -P' 78 | end 79 | 80 | end 81 | -------------------------------------------------------------------------------- /tools/zabbix/manual/requestcount_zabbix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahus1/hystrix-examples/083327c17c31b57ed4a96078e0fbcf3e19f7d6b4/tools/zabbix/manual/requestcount_zabbix.png -------------------------------------------------------------------------------- /tools/zabbix/salt/minion: -------------------------------------------------------------------------------- 1 | file_client: local 2 | master: localhost 3 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/pillar/top.sls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahus1/hystrix-examples/083327c17c31b57ed4a96078e0fbcf3e19f7d6b4/tools/zabbix/salt/roots/pillar/top.sls -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Allenta Consulting 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/apache/conf.sls: -------------------------------------------------------------------------------- 1 | {% from "apache/map.jinja" import apache with context %} 2 | 3 | 4 | include: 5 | - apache 6 | 7 | 8 | # This is a state file to configure apache. As there is a high variety of needs 9 | # I just choose a way to organize the confs. This state file is prone to be 10 | # forked to suit each one needs. Hopefully, as it is, should be enough for most 11 | # needs. 12 | 13 | 14 | {% set files_switch = salt['pillar.get']('apache:files_switch', ['id']) %} 15 | 16 | 17 | {{ apache.config }}: 18 | file: 19 | - managed 20 | - template: jinja 21 | - source: 22 | {% for grain in files_switch if salt['grains.get'](grain) is defined -%} 23 | - salt://apache/files/{{ salt['grains.get'](grain) }}/etc/apache2/apache2.conf.jinja 24 | {% endfor -%} 25 | - salt://apache/files/default/etc/apache2/apache2.conf.jinja 26 | - require: 27 | - pkg: apache 28 | - watch_in: 29 | - service: apache 30 | 31 | {%- if salt['grains.get']('os_family') == 'Debian' %} 32 | /etc/apache2/envvars: 33 | file: 34 | - managed 35 | - template: jinja 36 | - source: 37 | {% for grain in files_switch if salt['grains.get'](grain) is defined -%} 38 | - salt://apache/files/{{ salt['grains.get'](grain) }}/etc/apache2/envvars.jinja 39 | {% endfor -%} 40 | - salt://apache/files/default/etc/apache2/envvars.jinja 41 | - require: 42 | - pkg: apache 43 | - watch_in: 44 | - service: apache 45 | {% endif %} 46 | 47 | 48 | {% for site in salt['pillar.get']('apache:sites', []) %} 49 | 50 | {% set site_attr = salt['pillar.get']('apache:sites:' ~ site) %} 51 | 52 | {% if site_attr['conf_filename'] is defined %} 53 | {% set conf_filename = site_attr['conf_filename'] %} 54 | {% else %} 55 | {% set conf_filename = site ~ '.conf' %} 56 | {% endif %} 57 | 58 | {% if site_attr['template'] is defined %} 59 | {% set template = site_attr['template'] %} 60 | {% else %} 61 | {% set template = 'minimal' %} 62 | {% endif %} 63 | 64 | 65 | {% if site_attr['state'] is not defined or 66 | site_attr['state'] == 'enabled' %} 67 | /etc/apache2/sites-available/{{ conf_filename }}: 68 | file: 69 | - managed 70 | - source: 71 | {% for grain in files_switch if salt['grains.get'](grain) is defined -%} 72 | - salt://apache/files/{{ salt['grains.get'](grain) }}/etc/apache2/sites-available/{{ template }}.jinja 73 | {% endfor -%} 74 | - salt://apache/files/default/etc/apache2/sites-available/{{ template }}.jinja 75 | - template: jinja 76 | - context: 77 | site: {{ site }} 78 | - require: 79 | - pkg: apache 80 | - watch_in: 81 | - service: apache 82 | 83 | 84 | /etc/apache2/sites-enabled/{{ conf_filename }}: 85 | file: 86 | - symlink 87 | - target: /etc/apache2/sites-available/{{ conf_filename }} 88 | - require: 89 | - pkg: apache 90 | - watch_in: 91 | - service: apache 92 | 93 | 94 | {% if site_attr['create_dirs'] is defined and site_attr['create_dirs'] %} 95 | {% if site_attr['document_root'] is defined %} 96 | {{ site_attr['document_root'] }}: 97 | file: 98 | - directory 99 | - makedirs: true 100 | - user: {{ site_attr['user'] | d('www-data') }} 101 | - group: {{ site_attr['group'] | d('www-data') }} 102 | - mode: 2755 103 | - require: 104 | - user: {{ site_attr['user'] | d('www-data') }} 105 | - group: {{ site_attr['group'] | d('www-data') }} 106 | - require_in: 107 | - service: apache 108 | {% endif %} 109 | 110 | 111 | {% if site_attr['log_dir'] is defined %} 112 | {{ site_attr['log_dir'] }}: 113 | file: 114 | - directory 115 | - makedirs: true 116 | - user: {{ site_attr['user'] | d('www-data') }} 117 | - group: {{ site_attr['group'] | d('www-data') }} 118 | - mode: 775 119 | - require: 120 | - user: {{ site_attr['user'] | d('www-data') }} 121 | - group: {{ site_attr['group'] | d('www-data') }} 122 | - require_in: 123 | - service: apache 124 | {% endif %} 125 | {% endif %} 126 | 127 | 128 | {% elif site_attr['state'] == "disabled" %} 129 | /etc/apache2/sites-enabled/{{ conf_filename }}: 130 | file: 131 | - absent 132 | - require: 133 | - pkg: apache 134 | - watch_in: 135 | - service: apache 136 | 137 | 138 | {% elif site_attr['state'] == 'absent' %} 139 | /etc/apache2/sites-enabled/{{ conf_filename }}: 140 | file: 141 | - absent 142 | - require: 143 | - pkg: apache 144 | - watch_in: 145 | - service: apache 146 | 147 | 148 | /etc/apache2/sites-available/{{ conf_filename }}: 149 | file: 150 | - absent 151 | - require: 152 | - pkg: apache 153 | - watch_in: 154 | - service: apache 155 | 156 | 157 | {% endif %} 158 | {% endfor %} 159 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/apache/files/default/etc/apache2/envvars.jinja: -------------------------------------------------------------------------------- 1 | # Managed by saltstack 2 | 3 | # envvars - default environment variables for apache2ctl 4 | 5 | # this won't be correct after changing uid 6 | unset HOME 7 | 8 | # for supporting multiple apache2 instances 9 | if [ "${APACHE_CONFDIR##/etc/apache2-}" != "${APACHE_CONFDIR}" ] ; then 10 | SUFFIX="-${APACHE_CONFDIR##/etc/apache2-}" 11 | else 12 | SUFFIX= 13 | fi 14 | 15 | # Since there is no sane way to get the parsed apache2 config in scripts, some 16 | # settings are defined via environment variables and then used in apache2ctl, 17 | # /etc/init.d/apache2, /etc/logrotate.d/apache2, etc. 18 | export APACHE_RUN_USER={{ salt['pillar.get']('apache:user', 'www-data') }} 19 | export APACHE_RUN_GROUP={{ salt['pillar.get']('apache:group', 'www-data') }} 20 | # temporary state file location. This might be changed to /run in Wheezy+1 21 | export APACHE_PID_FILE=/var/run/apache2/apache2$SUFFIX.pid 22 | export APACHE_RUN_DIR=/var/run/apache2$SUFFIX 23 | export APACHE_LOCK_DIR=/var/lock/apache2$SUFFIX 24 | # Only /var/log/apache2 is handled by /etc/logrotate.d/apache2. 25 | export APACHE_LOG_DIR=/var/log/apache2$SUFFIX 26 | 27 | ## The locale used by some modules like mod_dav 28 | export LANG=C 29 | ## Uncomment the following line to use the system default locale instead: 30 | #. /etc/default/locale 31 | 32 | export LANG 33 | 34 | ## The command to get the status for 'apache2ctl status'. 35 | ## Some packages providing 'www-browser' need '--dump' instead of '-dump'. 36 | #export APACHE_LYNX='www-browser -dump' 37 | 38 | ## If you need a higher file descriptor limit, uncomment and adjust the 39 | ## following line (default is 8192): 40 | #APACHE_ULIMIT_MAX_FILES='ulimit -n 65536' 41 | 42 | ## If you would like to pass arguments to the web server, add them below 43 | ## to the APACHE_ARGUMENTS environment. 44 | #export APACHE_ARGUMENTS='' 45 | 46 | ## Enable the debug mode for maintainer scripts. 47 | ## This will produce a verbose output on package installations of web server modules and web application 48 | ## installations which interact with Apache 49 | #export APACHE2_MAINTSCRIPT_DEBUG=1 50 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/apache/files/default/etc/apache2/mods-available/mpm_event.conf.jinja: -------------------------------------------------------------------------------- 1 | # Managed by saltstack 2 | 3 | {%- set mpm_param = salt['pillar.get']('apache:mpm:params', {}) %} 4 | 5 | # event MPM 6 | # StartServers: initial number of server processes to start 7 | # MinSpareThreads: minimum number of worker threads which are kept spare 8 | # MaxSpareThreads: maximum number of worker threads which are kept spare 9 | # ThreadsPerChild: constant number of worker threads in each server process 10 | # MaxRequestWorkers: maximum number of worker threads 11 | # MaxConnectionsPerChild: maximum number of requests a server process serves 12 | 13 | StartServers {{ mpm_param['start_servers'] | d('2') }} 14 | MaxRequestWorkers {{ mpm_param['max_request_workers'] | d('150') }} 15 | MinSpareThreads {{ mpm_param['min_spare_threads'] | d('25') }} 16 | MaxSpareThreads {{ mpm_param['max_spare_threads'] | d('75') }} 17 | ThreadLimit {{ mpm_param['thread_limit'] | d('64') }} 18 | ThreadsPerChild {{ mpm_param['threads_per_child'] | d('25') }} 19 | MaxConnectionsPerChild {{ mpm_param['max_connections_per_child'] | d('0') }} 20 | 21 | 22 | # vim: syntax=apache ts=4 sw=4 sts=4 sr noet 23 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/apache/files/default/etc/apache2/mods-available/mpm_prefork.conf.jinja: -------------------------------------------------------------------------------- 1 | # Managed by saltstack 2 | 3 | {%- set mpm_param = salt['pillar.get']('apache:mpm:params', {}) %} 4 | 5 | # prefork MPM 6 | # StartServers: number of server processes to start 7 | # MinSpareServers: minimum number of server processes which are kept spare 8 | # MaxSpareServers: maximum number of server processes which are kept spare 9 | # MaxRequestWorkers: maximum number of server processes allowed to start 10 | # MaxConnectionsPerChild: maximum number of requests a server process serves 11 | 12 | 13 | StartServers {{ mpm_param['start_servers'] | d('5') }} 14 | MaxRequestWorkers {{ mpm_param['max_request_workers'] | d('150') }} 15 | MinSpareServers {{ mpm_param['min_spare_servers'] | d('5') }} 16 | MaxSpareServers {{ mpm_param['max_spare_servers'] | d('10') }} 17 | MaxConnectionsPerChild {{ mpm_param['max_connections_per_child'] | d('0') }} 18 | 19 | 20 | # vim: syntax=apache ts=4 sw=4 sts=4 sr noet 21 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/apache/files/default/etc/apache2/mods-available/mpm_worker.conf.jinja: -------------------------------------------------------------------------------- 1 | # Managed by saltstack 2 | 3 | {%- set mpm_param = salt['pillar.get']('apache:mpm:params', {}) %} 4 | 5 | # worker MPM 6 | # StartServers: initial number of server processes to start 7 | # MinSpareThreads: minimum number of worker threads which are kept spare 8 | # MaxSpareThreads: maximum number of worker threads which are kept spare 9 | # ThreadLimit: ThreadsPerChild can be changed to this maximum value during a 10 | # graceful restart. ThreadLimit can only be changed by stopping 11 | # and starting Apache. 12 | # ThreadsPerChild: constant number of worker threads in each server process 13 | # MaxRequestWorkers: maximum number of threads 14 | # MaxConnectionsPerChild: maximum number of requests a server process serves 15 | 16 | 17 | StartServers {{ mpm_param['start_servers'] | d('2') }} 18 | MaxRequestWorkers {{ mpm_param['max_request_workers'] | d('150') }} 19 | MinSpareThreads {{ mpm_param['min_spare_threads'] | d('25') }} 20 | MaxSpareThreads {{ mpm_param['max_spare_threads'] | d('75') }} 21 | ThreadLimit {{ mpm_param['thread_limit'] | d('64') }} 22 | ThreadsPerChild {{ mpm_param['threads_per_child'] | d('25') }} 23 | MaxConnectionsPerChild {{ mpm_param['max_connections_per_child'] | d('0') }} 24 | 25 | 26 | # vim: syntax=apache ts=4 sw=4 sts=4 sr noet 27 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/apache/files/default/etc/apache2/sites-available/minimal.jinja: -------------------------------------------------------------------------------- 1 | # Managed by saltstack 2 | 3 | {%- set site_attr = salt['pillar.get']('apache:sites:' ~ site) %} 4 | {%- set default_access_log = '/var/log/apache2/' ~ site ~ '_access.log combined' %} 5 | {%- set default_error_log = '/var/log/apache2/' ~ site ~ '_error.log' %} 6 | 7 | 8 | ServerName {{ site_attr['server_name'] }} 9 | {% if site_attr['server_alias'] is defined -%} 10 | ServerAlias {{ site_attr['server_alias'] }} 11 | {% endif -%} 12 | ServerAdmin {{ site_attr['server_admin'] }} 13 | DocumentRoot {{ site_attr['document_root'] }} 14 | 15 | Options Indexes FollowSymLinks 16 | AllowOverride None 17 | Order allow,deny 18 | allow from all 19 | 20 | ErrorLog {{ site_attr['error_log'] | d(default_error_log)}} 21 | LogLevel {{ site_attr['log_level'] | d('warn') }} 22 | 23 | {%- if site_attr['custom_logs'] is defined %} 24 | {%- for custom_log in site_attr['custom_logs'] %} 25 | CustomLog {{ custom_log }} 26 | {%- endfor %} 27 | {%- else %} 28 | CustomLog {{ default_access_log }} 29 | {%- endif %} 30 | 31 | {% if site_attr['fast_cgi_external_server'] -%} 32 | 33 | ProxyPassMatch ^/(.*\.php(/.*)?)$ {{ site_attr['fast_cgi_external_server'] }} 34 | 35 | {% endif -%} 36 | {{ site_attr['extra_conf'] | d('') }} 37 | 38 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/apache/files/default/etc/logrotate.d/minimal.jinja: -------------------------------------------------------------------------------- 1 | # Managed by saltstack 2 | {% set site_attr = salt['pillar.get']('apache:sites:' ~ site) %} 3 | 4 | {%- if site_attr['logrotate_files'] is defined %} 5 | {%- for logrotate_file in site_attr['logrotate_files'] %} 6 | {{ logrotate_file }} 7 | {%- endfor %} 8 | {%- else %} 9 | {{ '/var/log/apache2/' ~ site ~ '_access.log' }} 10 | {{ '/var/log/apache2/' ~ site ~ '_error.log' }} 11 | {%- endif %} 12 | { 13 | weekly 14 | missingok 15 | rotate 52 16 | compress 17 | delaycompress 18 | notifempty 19 | sharedscripts 20 | postrotate 21 | /etc/init.d/apache2 reload > /dev/null 22 | endscript 23 | } 24 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/apache/init.sls: -------------------------------------------------------------------------------- 1 | {% from "apache/map.jinja" import apache with context %} 2 | 3 | 4 | apache: 5 | pkg: 6 | - installed 7 | - name: {{ apache.pkg }} 8 | {% if apache.version is defined %} 9 | - version: {{ apache.version }} 10 | {% endif %} 11 | service: 12 | - running 13 | - name: {{ apache.service }} 14 | - enable: True 15 | - reload: True 16 | - require: 17 | - pkg: apache 18 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/apache/logrotate.sls: -------------------------------------------------------------------------------- 1 | {% from "apache/map.jinja" import apache with context %} 2 | 3 | 4 | # This configures the logrotate needed configurations for the log files. In 5 | # order to be useful, you need logrotate installed and minimally configured. 6 | 7 | 8 | {% set files_switch = salt['pillar.get']('apache:files_switch', ['id']) %} 9 | 10 | 11 | apache_logrotate: 12 | file: 13 | - directory 14 | - name: /etc/logrotate.d 15 | 16 | 17 | {% for site in salt['pillar.get']('apache:sites', []) %} 18 | 19 | {% set site_attr = salt['pillar.get']('apache:sites:' ~ site) %} 20 | 21 | {% set logrotate_filename = 'apache2-' ~ site %} 22 | 23 | {% if site_attr['logrotate_template'] is defined %} 24 | {% set template = site_attr['logrotate_template'] %} 25 | {% else %} 26 | {% set template = 'minimal' %} 27 | {% endif %} 28 | 29 | {% if site_attr['state'] is not defined or 30 | site_attr['state'] == 'enabled' %} 31 | /etc/logrotate.d/{{ logrotate_filename }}: 32 | file: 33 | - managed 34 | - source: 35 | {% for grain in files_switch if salt['grains.get'](grain) is defined -%} 36 | - salt://apache/files/{{ salt['grains.get'](grain) }}/etc/logrotate.d/{{ template }}.jinja 37 | {% endfor -%} 38 | - salt://apache/files/default/etc/logrotate.d/{{ template }}.jinja 39 | - template: jinja 40 | - context: 41 | site: {{ site }} 42 | - require: 43 | - pkg: apache 44 | 45 | 46 | {% else %} 47 | /etc/logrotate.d/{{ logrotate_filename }}: 48 | file: 49 | - absent 50 | - require: 51 | - pkg: apache 52 | 53 | 54 | {% endif %} 55 | {% endfor %} 56 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/apache/map.jinja: -------------------------------------------------------------------------------- 1 | # TODO: lookup table for additional os_family values 2 | 3 | {% set apache = salt['grains.filter_by']({ 4 | 'Debian': { 5 | 'pkg': 'apache2', 6 | 'service': 'apache2', 7 | 'config': '/etc/apache2/apache2.conf', 8 | }, 9 | 'RedHat': { 10 | 'pkg': 'httpd', 11 | 'service': 'httpd', 12 | 'config': '/etc/httpd/httpd.conf', 13 | }, 14 | }, merge=salt['pillar.get']('apache:lookup')) %} 15 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/apache/mod_actions.sls: -------------------------------------------------------------------------------- 1 | {% from "apache/map.jinja" import apache with context %} 2 | 3 | 4 | include: 5 | - apache 6 | 7 | 8 | {% if grains['os_family']=="Debian" %} 9 | a2enmod actions: 10 | cmd.run: 11 | - unless: ls /etc/apache2/mods-enabled/actions.load 12 | - require: 13 | - pkg: apache 14 | - watch_in: 15 | - service: apache 16 | {% endif %} 17 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/apache/mod_headers.sls: -------------------------------------------------------------------------------- 1 | {% from "apache/map.jinja" import apache with context %} 2 | 3 | 4 | include: 5 | - apache 6 | 7 | 8 | {% if grains['os_family']=="Debian" %} 9 | a2enmod headers: 10 | cmd.run: 11 | - unless: ls /etc/apache2/mods-enabled/headers.load 12 | - require: 13 | - pkg: apache 14 | - watch_in: 15 | - service: apache 16 | {% endif %} 17 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/apache/mod_mpm.sls: -------------------------------------------------------------------------------- 1 | {% from "apache/map.jinja" import apache with context %} 2 | 3 | 4 | include: 5 | - apache 6 | 7 | 8 | {% set files_switch = salt['pillar.get']('apache:files_switch', ['id']) %} 9 | {% set mpm_module = salt['pillar.get']('apache:mpm:module', 'mpm_worker') %} 10 | 11 | 12 | {% if grains['os_family']=="Debian" %} 13 | a2enmod {{ mpm_module }}: 14 | cmd: 15 | - run 16 | - unless: ls /etc/apache2/mods-enabled/{{ mpm_module }}.load 17 | - require: 18 | - pkg: apache 19 | - watch_in: 20 | - module: apache_mpm_restart 21 | file: 22 | - managed 23 | - name: /etc/apache2/mods-available/{{ mpm_module }}.conf 24 | - template: jinja 25 | - source: 26 | {% for grain in files_switch if salt['grains.get'](grain) is defined -%} 27 | - salt://apache/files/{{ salt['grains.get'](grain) }}/etc/apache2/mods-available/{{ mpm_module }}.conf.jinja 28 | {% endfor -%} 29 | - salt://apache/files/default/etc/apache2/mods-available/{{ mpm_module }}.conf.jinja 30 | - require: 31 | - pkg: apache 32 | - watch_in: 33 | - module: apache_mpm_restart 34 | # Deactivate the other mpm modules as a previous step 35 | {% for mod in ['mpm_prefork', 'mpm_worker', 'mpm_event'] if not mod == mpm_module %} 36 | a2dismod {{ mod }}: 37 | cmd: 38 | - run 39 | - onlyif: test -e /etc/apache2/mods-enabled/{{ mod }}.load 40 | - require: 41 | - pkg: apache 42 | - require_in: 43 | - cmd: a2enmod {{ mpm_module }} 44 | - watch_in: 45 | - module: apache_mpm_restart 46 | {% endfor %} 47 | 48 | 49 | # MPM change requires restart of apache 50 | apache_mpm_restart: 51 | module: 52 | - wait 53 | - name: service.restart 54 | - m_name: apache2 55 | 56 | 57 | {% endif %} 58 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/apache/mod_pagespeed.sls: -------------------------------------------------------------------------------- 1 | {% from "apache/map.jinja" import apache with context %} 2 | 3 | 4 | include: 5 | - apache 6 | - apache.users 7 | 8 | 9 | {% if grains['os_family']=="Debian" %} 10 | libapache2-mod-pagespeed: 11 | pkg: 12 | - installed 13 | - sources: 14 | - mod-pagespeed-stable: https://dl-ssl.google.com/dl/linux/direct/mod-pagespeed-stable_current_amd64.deb 15 | 16 | 17 | a2enmod pagespeed: 18 | cmd: 19 | - run 20 | - unless: ls /etc/apache2/mods-enabled/pagespeed.load 21 | - require: 22 | - pkg: libapache2-mod-pagespeed 23 | - watch_in: 24 | - service: apache 25 | 26 | 27 | {% for dir in ['/var/cache/mod_pagespeed', '/var/log/pagespeed'] %} 28 | {{ dir }}: 29 | file: 30 | - directory 31 | - makedirs: true 32 | - user: {{ salt['pillar.get']('apache:user', 'www-data') }} 33 | - group: {{ salt['pillar.get']('apache:group', 'www-data') }} 34 | - require: 35 | - pkg: libapache2-mod-pagespeed 36 | - user: {{ salt['pillar.get']('apache:user', 'www-data') }} 37 | - group: {{ salt['pillar.get']('apache:group', 'www-data') }} 38 | {% endfor %} 39 | 40 | 41 | # Here we hardcode a logrotate entry to take care of the logs 42 | /etc/logrorate.d/pagespeed: 43 | file: 44 | - managed 45 | - contents: | 46 | /var/log/pagespeed/*.log { 47 | weekly 48 | missingok 49 | rotate 52 50 | compress 51 | delaycompress 52 | notifempty 53 | sharedscripts 54 | postrotate 55 | if /etc/init.d/apache2 status > /dev/null ; then \ 56 | /etc/init.d/apache2 reload > /dev/null; \ 57 | fi; 58 | endscript 59 | } 60 | 61 | {% endif %} 62 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/apache/mod_proxy.sls: -------------------------------------------------------------------------------- 1 | {% from "apache/map.jinja" import apache with context %} 2 | 3 | 4 | include: 5 | - apache 6 | 7 | 8 | {% if grains['os_family']=="Debian" %} 9 | a2enmod proxy: 10 | cmd: 11 | - run 12 | - unless: ls /etc/apache2/mods-enabled/proxy.load 13 | - require: 14 | - pkg: apache 15 | - watch_in: 16 | - service: apache 17 | {% endif %} 18 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/apache/mod_proxy_fcgi.sls: -------------------------------------------------------------------------------- 1 | {% from "apache/map.jinja" import apache with context %} 2 | 3 | 4 | include: 5 | - apache 6 | - apache.mod_proxy 7 | 8 | 9 | {% if grains['os_family']=="Debian" %} 10 | a2enmod proxy_fcgi: 11 | cmd: 12 | - run 13 | - unless: ls /etc/apache2/mods-enabled/proxy_fcgi.load 14 | - require: 15 | - pkg: apache 16 | - cmd: a2enmod proxy 17 | - watch_in: 18 | - service: apache 19 | {% endif %} 20 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/apache/mod_rewrite.sls: -------------------------------------------------------------------------------- 1 | {% from "apache/map.jinja" import apache with context %} 2 | 3 | 4 | include: 5 | - apache 6 | 7 | 8 | {% if grains['os_family']=="Debian" %} 9 | a2enmod rewrite: 10 | cmd.run: 11 | - unless: ls /etc/apache2/mods-enabled/rewrite.load 12 | - require: 13 | - pkg: apache 14 | - watch_in: 15 | - service: apache 16 | {% endif %} 17 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/apache/repo.sls: -------------------------------------------------------------------------------- 1 | {% from "apache/map.jinja" import apache with context %} 2 | 3 | 4 | include: 5 | - apache 6 | 7 | 8 | # This adds a conveniently updated repo for apache 2.4.x 9 | {%if salt['grains.get']('os_family') == 'Debian' %} 10 | apache_repo: 11 | pkgrepo: 12 | - managed 13 | - ppa: ondrej/php5 14 | - require: 15 | - cmd: apache_repo 16 | - require_in: 17 | - pkg: apache 18 | cmd: 19 | - run 20 | - name: /usr/bin/apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E5267A6C 21 | - unless: /usr/bin/apt-key adv --list-key E5267A6C 22 | - user: root 23 | {% endif %} 24 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/apache/users.sls: -------------------------------------------------------------------------------- 1 | {% from "apache/map.jinja" import apache with context %} 2 | 3 | 4 | apache_user: 5 | user: 6 | - present 7 | - name: {{ salt['pillar.get']('apache:user', 'www-data') }} 8 | 9 | 10 | apache_group: 11 | group: 12 | - present 13 | - name: {{ salt['pillar.get']('apache:group', 'www-data') }} 14 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/mysql/client/conf.sls: -------------------------------------------------------------------------------- 1 | {% from "mysql/map.jinja" import mysql with context %} 2 | 3 | include: 4 | - mysql.client 5 | - mysql.conf 6 | 7 | extend: 8 | {{ mysql.config }}: 9 | file: 10 | - require: 11 | - pkg: mysql-client 12 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/mysql/client/init.sls: -------------------------------------------------------------------------------- 1 | {% from "mysql/map.jinja" import mysql with context %} 2 | 3 | 4 | # This included state is needed for the salt mysql modules to work, so we 5 | # assume that we always want it 6 | include: 7 | - mysql.python 8 | 9 | 10 | mysql-client: 11 | pkg: 12 | - installed 13 | - name: {{ mysql.client.pkg }} 14 | {% if mysql.client.version is defined %} 15 | - version: {{ mysql.client.version }} 16 | {% endif %} 17 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/mysql/conf.sls: -------------------------------------------------------------------------------- 1 | {% from "mysql/map.jinja" import mysql with context %} 2 | 3 | {% set files_switch = salt['pillar.get']('mysql:files_switch', ['id']) %} 4 | {% set cnf_template = salt['pillar.get']('mysql:cnf_template', 'only_pillar') %} 5 | 6 | {{ mysql.config }}: 7 | file: 8 | - managed 9 | - template: jinja 10 | - source: 11 | {% for grain in files_switch if salt['grains.get'](grain) is defined -%} 12 | - salt://mysql/files/{{ salt['grains.get'](grain) }}/etc/mysql/{{ cnf_template }}.cnf.jinja 13 | {% endfor -%} 14 | - salt://mysql/files/default/etc/mysql/{{ cnf_template }}.cnf.jinja 15 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/mysql/files/default/etc/mysql/only_pillar.cnf.jinja: -------------------------------------------------------------------------------- 1 | # Managed by saltstack 2 | {# This a template that creates a cnf file based just in pillar data structured 3 | this way: 4 | 5 | mysql: 6 | cnf: 7 | group01: 8 | opt_name01: value 9 | opt_name02: value 10 | opt_name03 11 | opt_name04: value 12 | group02: 13 | opt_name01: value 14 | opt_name02: value 15 | opt_name03 16 | opt_name04: value 17 | #} 18 | 19 | {%- for group in salt['pillar.get']('mysql:cnf',[]) %} 20 | {%- set opts = salt['pillar.get']('mysql:cnf:' ~ group, []) %} 21 | [{{ group }}] 22 | {%- for opt in opts %} 23 | {%- if opt is mapping %} 24 | {%- for key in opt %} 25 | {{ key }} = {{ opt[key] }} 26 | {%- endfor %} 27 | {%- else %} 28 | {{ opt }} 29 | {%- endif %} 30 | {%- endfor %} 31 | {% endfor %} 32 | 33 | 34 | {%- for include in salt['pillar.get']('mysql:cnf_include',[]) %} 35 | !include {{ include }} 36 | {%- endfor %} 37 | 38 | {%- for includedir in salt['pillar.get']('mysql:cnf_includedir',[]) %} 39 | !includedir {{ includedir }} 40 | {%- endfor %} 41 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/mysql/map.jinja: -------------------------------------------------------------------------------- 1 | {% set mysql = salt['grains.filter_by']({ 2 | 'RedHat': { 3 | 'config': '/etc/mysql/my.cnf', 4 | 'server': { 5 | 'pkg': 'mysql-server', 6 | 'service': 'mysqld' 7 | }, 8 | 'client': { 9 | 'pkg': 'mysql' 10 | }, 11 | 'python': { 12 | 'pkg': 'MySQL-python' 13 | }, 14 | }, 15 | 'default': { 16 | 'config': '/etc/mysql/my.cnf', 17 | 'server': { 18 | 'pkg': 'mysql-server', 19 | 'service': 'mysql' 20 | }, 21 | 'client': { 22 | 'pkg': 'mysql-client' 23 | }, 24 | 'python': { 25 | 'pkg': 'python-mysqldb' 26 | }, 27 | }, 28 | }, merge=salt['pillar.get']('mysql:lookup')) %} 29 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/mysql/python.sls: -------------------------------------------------------------------------------- 1 | {% from "mysql/map.jinja" import mysql with context %} 2 | 3 | 4 | python-mysqldb: 5 | pkg: 6 | - installed 7 | - name: {{ mysql.python.pkg }} 8 | {% if mysql.python.version is defined %} 9 | - version: {{ mysql.python.version }} 10 | {% endif %} 11 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/mysql/server/conf.sls: -------------------------------------------------------------------------------- 1 | {% from "mysql/map.jinja" import mysql with context %} 2 | 3 | include: 4 | - mysql.server 5 | - mysql.conf 6 | 7 | extend: 8 | {{ mysql.config }}: 9 | file: 10 | - require: 11 | - pkg: mysql-server 12 | - watch_in: 13 | - service: mysql-server 14 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/mysql/server/init.sls: -------------------------------------------------------------------------------- 1 | {% from "mysql/map.jinja" import mysql with context %} 2 | 3 | 4 | # This included state is needed for the salt mysql modules to work, so we 5 | # assume that we always want it 6 | include: 7 | - mysql.python 8 | 9 | 10 | mysql-server: 11 | pkg: 12 | - installed 13 | - name: {{ mysql.server.pkg }} 14 | {% if mysql.server.version is defined %} 15 | - version: {{ mysql.server.version }} 16 | {% endif %} 17 | service: 18 | - running 19 | - name: {{ mysql.server.service }} 20 | - enable: True 21 | - require: 22 | - pkg: mysql-server 23 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/php5/curl.sls: -------------------------------------------------------------------------------- 1 | {% from "php5/map.jinja" import php5 with context %} 2 | 3 | 4 | include: 5 | - php5 6 | 7 | 8 | php5-curl: 9 | pkg: 10 | - installed 11 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/php5/files/default/etc/logrotate.d/minimal.jinja: -------------------------------------------------------------------------------- 1 | # Managed by saltstack 2 | {% set pool_attr = salt['pillar.get']('php5-fpm:pools:' ~ pool) %} 3 | 4 | {%- if pool_attr['logrotate_files'] is defined %} 5 | {%- for logrotate_file in pool_attr['logrotate_files'] %} 6 | {{ logrotate_file }} 7 | {%- endfor %} 8 | {%- endif %} 9 | { 10 | weekly 11 | missingok 12 | rotate 52 13 | compress 14 | delaycompress 15 | notifempty 16 | sharedscripts 17 | postrotate 18 | kill -USR1 `cat {{ salt['pillar.get']('php5-fpm:pid_file', '/var/run/php5-fpm.pid') }}` > /dev/null 19 | endscript 20 | } 21 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/php5/files/default/etc/php5/fpm/pool.d/minimal.jinja: -------------------------------------------------------------------------------- 1 | ; Managed by saltstack 2 | 3 | {% set pool_attr = salt['pillar.get']('php5-fpm:pools:' + pool) -%} 4 | [{{ pool }}] 5 | ;prefix = /path/to/pools/$pool 6 | user = {{ pool_attr['user'] | d('www-data') }} 7 | group = {{ pool_attr['user'] | d('www-data') }} 8 | listen = {{ pool_attr['listen'] }} 9 | listen.owner = {{ pool_attr['listen.owner'] | d('www-data') }} 10 | listen.group = {{ pool_attr['listen.group'] | d('www-data') }} 11 | listen.mode = {{ pool_attr['listen.mode'] | d('0666') }} 12 | listen.allowed_clients = {{ pool_attr['listen_allowed_clients'] | d('127.0.0.1') }} 13 | pm = dynamic 14 | pm.max_children = {{ pool_attr['pm.max_children'] | d('10') }} 15 | pm.start_servers = {{ pool_attr['pm.start_servers'] | d('4') }} 16 | pm.min_spare_servers = {{ pool_attr['pm.min_spare_servers'] | d('2') }} 17 | pm.max_spare_servers = {{ pool_attr['pm.max_spare_servers'] | d('6') }} 18 | ;pm.process_idle_timeout = 10s; 19 | pm.max_requests = {{ pool_attr['pm.max_requests'] | d('500') }} 20 | ;pm.status_path = /status 21 | ;ping.path = /ping 22 | ;ping.response = pong 23 | ; access.log = /var/log/php5-fpm_$pool.access.log 24 | ;access.format = %R - %u %t "%m %r%Q%q" %s %f %{mili}d %{kilo}M %C%% 25 | ;slowlog = log/$pool.log.slow 26 | ;request_slowlog_timeout = 0 27 | ;request_terminate_timeout = 0 28 | ;rlimit_files = 1024 29 | ;rlimit_core = 0 30 | ;chroot = 31 | chdir = / 32 | catch_workers_output = yes 33 | ;security.limit_extensions = .php .php3 .php4 .php5 34 | env[HOSTNAME] = $HOSTNAME 35 | env[PATH] = /usr/local/bin:/usr/bin:/bin 36 | env[TMP] = /tmp 37 | env[TMPDIR] = /tmp 38 | env[TEMP] = /tmp 39 | ;php_flag[display_errors] = off 40 | php_admin_value[error_log] = {{ pool_attr['log_dir'] | d('/var/log') }}/php5-fpm_$pool.error.log 41 | php_admin_flag[log_errors] = on 42 | ;php_admin_value[memory_limit] = 32M 43 | {{ pool_attr['extra_conf'] | d('') }} 44 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/php5/fpm/conf.sls: -------------------------------------------------------------------------------- 1 | {% from "php5/map.jinja" import php5 with context %} 2 | 3 | 4 | include: 5 | - php5.fpm 6 | 7 | 8 | {% set files_switch = salt['pillar.get']('php5-fpm:files_switch', ['id']) %} 9 | 10 | 11 | 12 | {% for pool in salt['pillar.get']('php5-fpm:pools', []) %} 13 | 14 | {% set pool_attr = salt['pillar.get']('php5-fpm:pools:' ~ pool) %} 15 | 16 | {% if pool_attr['conf_filename'] is defined %} 17 | {% set conf_filename = pool_attr['conf_filename'] %} 18 | {% else %} 19 | {% set conf_filename = pool ~ '.conf' %} 20 | {% endif %} 21 | 22 | {% if pool_attr['template'] is defined %} 23 | {% set template = pool_attr['template'] %} 24 | {% else %} 25 | {% set template = 'minimal' %} 26 | {% endif %} 27 | 28 | {% if pool_attr['state'] is not defined or 29 | pool_attr['state'] == 'enabled' %} 30 | /etc/php5/fpm/pool.d/{{ pool }}.conf: 31 | file: 32 | - managed 33 | - source: 34 | {% for grain in files_switch if salt['grains.get'](grain) is defined -%} 35 | - salt://php5/files/{{ salt['grains.get'](grain) }}/etc/php5/fpm/pool.d/{{ template }}.jinja 36 | {% endfor -%} 37 | - salt://php5/files/default/etc/php5/fpm/pool.d/{{ template }}.jinja 38 | - template: jinja 39 | - context: 40 | pool: {{ pool }} 41 | - require: 42 | - pkg: php5-fpm 43 | - watch_in: 44 | - service: php5-fpm 45 | 46 | 47 | {% if pool_attr['create_dirs'] is defined and pool_attr['create_dirs'] %} 48 | {% if pool_attr['log_dir'] is defined %} 49 | {{ pool_attr['log_dir'] }}: 50 | file: 51 | - directory 52 | - makedirs: true 53 | - user: {{ pool_attr['user'] | d('www-data') }} 54 | - group: {{ pool_attr['group'] | d('www-data') }} 55 | - mode: 775 56 | - require: 57 | - user: {{ pool_attr['user'] | d('www-data') }} 58 | - group: {{ pool_attr['group'] | d('www-data') }} 59 | - require_in: 60 | - service: php5-fpm 61 | {% endif %} 62 | {% endif %} 63 | 64 | {% elif pool_attr['state'] == 'absent' %} 65 | /etc/php5/fpm/pool.d/{{ pool }}.conf: 66 | file: 67 | - absent 68 | - require: 69 | - pkg: php5-fpm 70 | - watch_in: 71 | - service: php5-fpm 72 | {% endif %} 73 | {% endfor %} 74 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/php5/fpm/init.sls: -------------------------------------------------------------------------------- 1 | {% from "php5/map.jinja" import php5 with context %} 2 | 3 | 4 | php5-fpm: 5 | pkg: 6 | - installed 7 | - name: {{ php5.fpm.pkg }} 8 | {% if php5.fpm.version is defined %} 9 | - version: {{ php5.fpm.version }} 10 | {% endif %} 11 | service: 12 | - running 13 | - name: {{ php5.fpm.service }} 14 | - enable: True 15 | - require: 16 | - pkg: php5-fpm 17 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/php5/fpm/logrotate.sls: -------------------------------------------------------------------------------- 1 | {% from "php5/map.jinja" import php5 with context %} 2 | 3 | 4 | # This configures the logrotate needed configurations for the log files. In 5 | # order to be useful, you need logrotate installed and minimally configured. 6 | 7 | 8 | {% set files_switch = salt['pillar.get']('php5-fpm:files_switch', ['id']) %} 9 | 10 | 11 | php5-fpm_logrotate: 12 | file: 13 | - directory 14 | - name: /etc/logrotate.d 15 | 16 | 17 | {% for pool in salt['pillar.get']('php5-fpm:pools', []) %} 18 | 19 | {% set pool_attr = salt['pillar.get']('php5-fpm:pools:' ~ pool) %} 20 | 21 | {% set logrotate_filename = 'php5-fpm-' ~ pool %} 22 | 23 | {% if pool_attr['logrotate_template'] is defined %} 24 | {% set template = pool_attr['logrotate_template'] %} 25 | {% else %} 26 | {% set template = 'minimal' %} 27 | {% endif %} 28 | 29 | {% if pool_attr['state'] is not defined or 30 | pool_attr['state'] == 'enabled' %} 31 | /etc/logrotate.d/{{ logrotate_filename }}: 32 | file: 33 | - managed 34 | - source: 35 | {% for grain in files_switch if salt['grains.get'](grain) is defined -%} 36 | - salt://php5/files/{{ salt['grains.get'](grain) }}/etc/logrotate.d/{{ template }}.jinja 37 | {% endfor -%} 38 | - salt://php5/files/default/etc/logrotate.d/{{ template }}.jinja 39 | - template: jinja 40 | - context: 41 | pool: {{ pool }} 42 | - require: 43 | - pkg: php5-fpm 44 | 45 | 46 | {% else %} 47 | /etc/logrotate.d/{{ logrotate_filename }}: 48 | file: 49 | - absent 50 | - require: 51 | - pkg: php5-fpm 52 | 53 | 54 | {% endif %} 55 | {% endfor %} 56 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/php5/fpm/repo.sls: -------------------------------------------------------------------------------- 1 | {% from "php5/map.jinja" import php5 with context %} 2 | 3 | 4 | include: 5 | - php5.fpm 6 | - php5.repo 7 | 8 | 9 | # Here we just add a requisite declaration to ensure correct order 10 | extend: 11 | php5_repo: 12 | pkgrepo: 13 | - require_in: 14 | - pkg: php5-fpm 15 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/php5/gd.sls: -------------------------------------------------------------------------------- 1 | {% from "php5/map.jinja" import php5 with context %} 2 | 3 | 4 | include: 5 | - php5 6 | 7 | 8 | php5-gd: 9 | pkg: 10 | - installed 11 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/php5/init.sls: -------------------------------------------------------------------------------- 1 | {% from "php5/map.jinja" import php5 with context %} 2 | 3 | 4 | php5: 5 | pkg: 6 | - installed 7 | - name: {{ php5.pkg }} 8 | {% if php5.version is defined %} 9 | - version: {{ php5.version }} 10 | {% endif %} 11 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/php5/map.jinja: -------------------------------------------------------------------------------- 1 | {% set php5 = salt['grains.filter_by']({ 2 | 'RedHat': { 3 | 'pkg': 'php', 4 | 'service': 'php', 5 | 'config': '/etc/php.conf', 6 | 'mysql' : { 7 | 'pkg': 'php-mysql' 8 | }, 9 | 'fpm': { 10 | 'pkg': 'php-fpm', 11 | 'service': 'php-fpm' 12 | }, 13 | }, 14 | 'default': { 15 | 'pkg': 'php5', 16 | 'service': 'php5', 17 | 'config': '/etc/php5.conf', 18 | 'mysql' : { 19 | 'pkg': 'php5-mysql' 20 | }, 21 | 'fpm': { 22 | 'pkg': 'php5-fpm', 23 | 'service': 'php5-fpm' 24 | }, 25 | }, 26 | }, merge=salt['pillar.get']('php5:lookup')) %} 27 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/php5/mysql.sls: -------------------------------------------------------------------------------- 1 | {% from "php5/map.jinja" import php5 with context %} 2 | 3 | 4 | include: 5 | - php5 6 | 7 | php5-mysql: 8 | pkg: 9 | - installed 10 | - name: {{ php5.mysql.pkg }} 11 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/php5/repo.sls: -------------------------------------------------------------------------------- 1 | {% from "php5/map.jinja" import php5 with context %} 2 | 3 | 4 | include: 5 | - php5 6 | 7 | 8 | # This adds a conveniently updated repo for PHP5 9 | {%if salt['grains.get']('os_family') == 'Debian' %} 10 | php5_repo: 11 | pkgrepo: 12 | - managed 13 | - ppa: ondrej/php5 14 | - require: 15 | - cmd: php5_repo 16 | cmd: 17 | - run 18 | - name: /usr/bin/apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E5267A6C 19 | - unless: /usr/bin/apt-key adv --list-key E5267A6C 20 | - user: root 21 | {% endif %} 22 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/readme.txt: -------------------------------------------------------------------------------- 1 | These pillars have been taken from 2 | 3 | https://github.com/moreda 4 | 5 | The initial scripts have been developed for Debian/Ubuntu style systems. 6 | 7 | There are some local changes to adopt it to CentOS (there will be a merge request soon). 8 | 9 | Br, 10 | Alex. -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/top.sls: -------------------------------------------------------------------------------- 1 | base: 2 | '*': 3 | - zabbix.users 4 | - zabbix.agent.repo 5 | - zabbix.agent.conf 6 | - zabbix.mysql.conf 7 | - zabbix.mysql.schema 8 | - zabbix.server.repo 9 | - zabbix.server.conf 10 | - apache.repo 11 | - apache.conf 12 | - apache.users 13 | - apache.mod_proxy_fcgi 14 | - apache.mod_actions 15 | - php5.fpm.conf 16 | - php5.mysql 17 | - zabbix.frontend.repo 18 | - zabbix.frontend.conf 19 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/zabbix/agent/conf.sls: -------------------------------------------------------------------------------- 1 | {% from "zabbix/map.jinja" import zabbix with context %} 2 | 3 | 4 | include: 5 | - zabbix.agent 6 | 7 | 8 | {% set files_switch = salt['pillar.get']('zabbix-agent:files_switch', ['id']) %} 9 | 10 | 11 | {{ zabbix.agent.config }}: 12 | file: 13 | - managed 14 | - source: 15 | {% for grain in files_switch if salt['grains.get'](grain) is defined -%} 16 | - salt://zabbix/files/{{ salt['grains.get'](grain) }}/etc/zabbix/zabbix_agentd.conf.jinja 17 | {% endfor -%} 18 | - salt://zabbix/files/default/etc/zabbix/zabbix_agentd.conf.jinja 19 | - template: jinja 20 | - require: 21 | - pkg: zabbix-agent 22 | - watch_in: 23 | - service: zabbix-agent 24 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/zabbix/agent/init.sls: -------------------------------------------------------------------------------- 1 | {% from "zabbix/map.jinja" import zabbix with context %} 2 | 3 | 4 | zabbix-agent: 5 | pkg: 6 | - installed 7 | - name: {{ zabbix.agent.pkg }} 8 | {% if zabbix.agent.version is defined %} 9 | - version: {{ zabbix.agent.version }} 10 | {% endif %} 11 | service: 12 | - running 13 | - name: {{ zabbix.agent.service }} 14 | - enable: True 15 | - require: 16 | - pkg: zabbix-agent 17 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/zabbix/agent/repo.sls: -------------------------------------------------------------------------------- 1 | {% from "zabbix/map.jinja" import zabbix with context %} 2 | 3 | 4 | # We have a common state file for the official Zabbix repo 5 | include: 6 | - zabbix.repo 7 | 8 | 9 | # Here we just add a requisite declaration to ensure correct order 10 | extend: 11 | zabbix_repo: 12 | {%- if salt['grains.get']('os_family') == 'Debian' %} 13 | pkgrepo: 14 | - require_in: 15 | - pkg: zabbix-agent 16 | {% else %} {} 17 | {% endif %} 18 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/zabbix/files/default/etc/php.d/zabbix.ini: -------------------------------------------------------------------------------- 1 | # When the timezone has not been set (at least on centos), this will set it. 2 | # Zabbix requires it. 3 | # TODO: make it configurable 4 | date.timezone = Europe/Berlin 5 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/zabbix/files/default/etc/zabbix/web/zabbix.conf.php.jinja: -------------------------------------------------------------------------------- 1 | 20 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/zabbix/frontend/conf.sls: -------------------------------------------------------------------------------- 1 | {% from "zabbix/map.jinja" import zabbix with context %} 2 | 3 | 4 | include: 5 | - zabbix.frontend 6 | - zabbix.frontend.repo 7 | 8 | 9 | {% set files_switch = salt['pillar.get']('zabbix-frontend:files_switch', ['id']) %} 10 | 11 | 12 | {{ zabbix.frontend.config }}: 13 | file: 14 | - managed 15 | - source: 16 | {% for grain in files_switch if salt['grains.get'](grain) is defined -%} 17 | - salt://zabbix/files/{{ salt['grains.get'](grain) }}/etc/zabbix/web/zabbix.conf.php.jinja 18 | {% endfor -%} 19 | - salt://zabbix/files/default/etc/zabbix/web/zabbix.conf.php.jinja 20 | - template: jinja 21 | - watch_in: 22 | - service: apache 23 | - service: php5-fpm 24 | - require: 25 | - pkg: zabbix-web-mysql 26 | 27 | /etc/php.d/zabbix.ini: 28 | file: 29 | - managed 30 | - source: 31 | {% for grain in files_switch if salt['grains.get'](grain) is defined -%} 32 | - salt://zabbix/files/{{ salt['grains.get'](grain) }}/etc/php.d/zabbix.ini 33 | {% endfor -%} 34 | - salt://zabbix/files/default/etc/php.d/zabbix.ini 35 | - watch_in: 36 | - service: apache 37 | - service: php5-fpm 38 | - require: 39 | - pkg: php5-fpm 40 | - pkg: apache 41 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/zabbix/frontend/init.sls: -------------------------------------------------------------------------------- 1 | {% from "zabbix/map.jinja" import zabbix with context %} 2 | 3 | 4 | zabbix-frontend-php: 5 | pkg: 6 | - installed 7 | - name: {{ zabbix.frontend.pkg }} 8 | {% if zabbix.frontend.version is defined %} 9 | - version: {{ zabbix.frontend.version }} 10 | {% endif %} 11 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/zabbix/frontend/repo.sls: -------------------------------------------------------------------------------- 1 | {% from "zabbix/map.jinja" import zabbix with context %} 2 | 3 | 4 | # We have a common state file for the official Zabbix repo 5 | include: 6 | - zabbix.repo 7 | 8 | 9 | # Here we just add a requisite declaration to ensure correct order 10 | extend: 11 | zabbix_repo: 12 | {%- if salt['grains.get']('os_family') == 'Debian' %} 13 | pkgrepo: 14 | - require_in: 15 | - pkg: zabbix-frontend-php 16 | {% else %} {} 17 | {% endif %} 18 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/zabbix/map.jinja: -------------------------------------------------------------------------------- 1 | {% set zabbix = salt['grains.filter_by']({ 2 | 'Debian': { 3 | 'version_repo': '2.2', 4 | 'agent': { 5 | 'pkg': 'zabbix-agent', 6 | 'service': 'zabbix-agent', 7 | 'config': '/etc/zabbix/zabbix_agentd.conf' 8 | }, 9 | 'server': { 10 | 'pkg': 'zabbix-server-mysql', 11 | 'service': 'zabbix-server', 12 | 'config': '/etc/zabbix/zabbix_server.conf', 13 | 'dbsocket': '/var/run/mysqld/mysqld.sock' 14 | }, 15 | 'frontend': { 16 | 'pkg': 'zabbix-frontend-php', 17 | 'config': '/etc/zabbix/web/zabbix.conf.php' 18 | } 19 | }, 20 | 21 | 'FreeBSD': { 22 | 'agent': { 23 | 'pkg': 'zabbix22-agent', 24 | 'service': 'zabbix_agentd', 25 | 'config': '/usr/local/etc/zabbix22/zabbix_agentd.conf' 26 | }, 27 | 'server': { 28 | 'pkg': 'zabbix22-server', 29 | 'service': 'zabbix', 30 | 'config': '/usr/local/etc/zabbix22/zabbix_server.conf', 31 | 'dbsocket': '/var/run/mysqld/mysqld.sock' 32 | } 33 | }, 34 | 'RedHat': { 35 | 'agent': { 36 | 'pkg': 'zabbix-agent', 37 | 'service': 'zabbix-agent', 38 | 'config': '/etc/zabbix/zabbix_agentd.conf' 39 | }, 40 | 'server': { 41 | 'pkg': 'zabbix-server-mysql', 42 | 'service': 'zabbix-server', 43 | 'config': '/etc/zabbix/zabbix_server.conf', 44 | 'dbsocket': '/var/lib/mysql/mysql.sock' 45 | }, 46 | 'frontend': { 47 | 'pkg': 'zabbix-web-mysql', 48 | 'config': '/etc/zabbix/web/zabbix.conf.php' 49 | } 50 | }, 51 | 'default': { 52 | 'agent': { 53 | 'pkg': 'zabbix-agent', 54 | 'service': 'zabbix-agent', 55 | 'config': '/etc/zabbix/zabbix_agentd.conf' 56 | }, 57 | 'server': { 58 | 'pkg': 'zabbix-server-mysql', 59 | 'service': 'zabbix-server', 60 | 'config': '/etc/zabbix/zabbix_server.conf', 61 | 'dbsocket': '/var/run/mysqld/mysqld.sock' 62 | }, 63 | 'frontend': { 64 | 'pkg': 'zabbix-frontend-php', 65 | 'config': '/etc/zabbix/web/zabbix.conf.php' 66 | } 67 | }, 68 | }, merge=salt['pillar.get']('zabbix:lookup')) %} 69 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/zabbix/mysql/conf.sls: -------------------------------------------------------------------------------- 1 | {% from "mysql/map.jinja" import mysql with context %} 2 | 3 | {% set dbhost = salt['pillar.get']('zabbix-mysql:dbhost', 'localhost') %} 4 | {% set dbname = salt['pillar.get']('zabbix-mysql:dbname', 'zabbix') %} 5 | {% set dbuser = salt['pillar.get']('zabbix-mysql:dbuser', 'zabbixuser') %} 6 | {% set dbpass = salt['pillar.get']('zabbix-mysql:dbpass', 'zabbixpass') %} 7 | {% set dbuser_host = salt['pillar.get']('zabbix-mysql:dbuser_host', 'localhost') %} 8 | 9 | 10 | include: 11 | - mysql.server 12 | 13 | 14 | zabbix_db: 15 | mysql_database: 16 | - present 17 | - name: {{ dbname }} 18 | - character_set: utf8 19 | - collate: utf8_bin 20 | mysql_grants: 21 | - present 22 | - grant: all privileges 23 | - database: {{ dbname }}.* 24 | - user: {{ dbuser }} 25 | - host: '{{ dbuser_host }}' 26 | - require: 27 | - mysql_database: zabbix_db 28 | mysql_user: 29 | - present 30 | - name: {{ dbuser }} 31 | - host: '{{ dbuser_host }}' 32 | - password: {{ dbpass }} 33 | - require: 34 | - mysql_grants: zabbix_db 35 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/zabbix/mysql/schema.sls: -------------------------------------------------------------------------------- 1 | {% from "mysql/map.jinja" import mysql with context %} 2 | 3 | {% set dbhost = salt['pillar.get']('zabbix-mysql:dbhost', 'localhost') %} 4 | {% set dbname = salt['pillar.get']('zabbix-mysql:dbname', 'zabbix') %} 5 | {% set dbuser = salt['pillar.get']('zabbix-mysql:dbuser', 'zabbixuser') %} 6 | {% set dbpass = salt['pillar.get']('zabbix-mysql:dbpass', 'zabbixpass') %} 7 | 8 | 9 | include: 10 | - mysql.client 11 | 12 | 13 | {% set files_switch = salt['pillar.get']('zabbix-mysql:files_switch', ['id']) %} 14 | 15 | 16 | {% for file in [ 17 | '/usr/share/zabbix-server-mysql/schema.sql', 18 | '/usr/share/zabbix-server-mysql/images.sql', 19 | '/usr/share/zabbix-server-mysql/data.sql' 20 | ] %} 21 | {{ file }}: 22 | file: 23 | - managed 24 | - source: 25 | {% for grain in files_switch if salt['grains.get'](grain) is defined -%} 26 | - salt://zabbix/files/{{ salt['grains.get'](grain) }}{{ file }} 27 | {% endfor -%} 28 | - salt://zabbix/files/default{{ file }} 29 | - makedirs: true 30 | cmd: 31 | - run 32 | - name: /usr/bin/mysql -h {{ dbhost }} -u {{ dbuser }} --password={{ dbpass }} {{ dbname }} < {{ file }} && touch {{ file }}.applied 33 | - unless: test -f {{ file }}.applied 34 | - require: 35 | - file: {{ file }} 36 | - pkg: mysql-client 37 | {% endfor %} 38 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/zabbix/repo.sls: -------------------------------------------------------------------------------- 1 | {% from "zabbix/map.jinja" import zabbix with context %} 2 | 3 | # Zabbix official repo releases a deb package that sets a zabbix.list apt 4 | # sources. Here we do the same as that package does, including the PGP key for 5 | # the repo. 6 | 7 | 8 | {%- if salt['grains.get']('os_family') == 'Debian' %} 9 | zabbix_repo: 10 | pkgrepo: 11 | - managed 12 | - name: deb http://repo.zabbix.com/zabbix/{{ zabbix.version_repo }}/ubuntu {{grains['oscodename']}} main 13 | - file: /etc/apt/sources.list.d/zabbix.list 14 | - require: 15 | - cmd: zabbix_repo_add_gpg 16 | 17 | 18 | zabbix_repo_add_gpg: 19 | cmd: 20 | - wait 21 | - name: /usr/bin/apt-key add /var/tmp/zabbix-official-repo.gpg 22 | - watch: 23 | - file: /var/tmp/zabbix-official-repo.gpg 24 | 25 | 26 | /var/tmp/zabbix-official-repo.gpg: 27 | file: 28 | - managed 29 | - contents: | 30 | -----BEGIN PGP PUBLIC KEY BLOCK----- 31 | 32 | mQGiBFCNJaYRBAC4nIW8o2NyOIswb82Xn3AYSMUcNZuKB2fMtpu0WxSXIRiX2BwC 33 | YXx8cIEQVYtLRBL5o0JdmoNCjW6jd5fOVem3EmOcPksvzzRWonIgFHf4EI2n1KJc 34 | JXX/nDC+eoh5xW35mRNFN/BEJHxxiRGGbp2MCnApwgrZLhOujaCGAwavGwCgiG4D 35 | wKMZ4xX6Y2Gv3MSuzMIT0bcEAKYn3WohS+udp0yC3FHDj+oxfuHpklu1xuI3y6ha 36 | 402aEFahNi3wr316ukgdPAYLbpz76ivoouTJ/U2MqbNLjAspDvlnHXXyqPM5GC6K 37 | jtXPqNrRMUCrwisoAhorGUg/+S5pyXwsWcJ6EKmA80pR9HO+TbsELE5bGe/oc238 38 | t/2oBAC3zcQ46wPvXpMCNFb+ED71qDOlnDYaaAPbjgkvnp+WN6nZFFyevjx180Kw 39 | qWOLnlNP6JOuFW27MP75MDPDpbAAOVENp6qnuW9dxXTN80YpPLKUxrQS8vWPnzkY 40 | WtUfF75pEOACFVTgXIqEgW0E6oww2HJi9zF5fS8IlFHJztNYtbQgWmFiYml4IFNJ 41 | QSA8cGFja2FnZXJAemFiYml4LmNvbT6IYAQTEQIAIAUCUI0lpgIbAwYLCQgHAwIE 42 | FQIIAwQWAgMBAh4BAheAAAoJENE9WOR56l7UhUwAmgIGZ39U6D2w2oIWDD8m7KV3 43 | oI06AJ9EnOxMMlxEjTkt9lEvGhEX1bEh7bkBDQRQjSWmEAQAqx+ecOzBbhqMq5hU 44 | l39cJ6l4aocz6EZ9mSSoF/g+HFz6WYnPAfRaYyfLmZdtF5rGBDD4ysalYG5yD59R 45 | Mv5tNVf/CEx+JAPMhp6JCBkGRaH+xHws4eBPGkea4rGNVP3L3rA7g+c1YXZICGRI 46 | OOH7CIzIZ/w6aFGsPp7xM35ogncAAwUD/3s8Nc1OLDy81DC6rGpxfEURd5pvd/j0 47 | D5Di0WSBEcHXp5nThDz6ro/Vr0/FVIBtT97tmBHX27yBS3PqxxNRIjZ0GSWQqdws 48 | Q8o3YT+RHjBugXn8CzTOvIn+2QNMA8EtGIZPpCblJv8q6MFPi9m7avQxguMqufgg 49 | fAk7377Rt9RqiEkEGBECAAkFAlCNJaYCGwwACgkQ0T1Y5HnqXtQx4wCfcJZINKVq 50 | kQIoV3KTQAIzr6IvbZoAn12XXt4GP89xHuzPDZ86YJVAgnfK 51 | =+200 52 | -----END PGP PUBLIC KEY BLOCK----- 53 | {%- elif salt['grains.get']('os_family') == 'RedHat' and 54 | salt['grains.get']('osmajorrelease')[0] == '6' %} 55 | zabbix_repo: 56 | pkgrepo: 57 | - managed 58 | - name: zabbix 59 | - humanname: Zabbix Official Repository - $basearch 60 | - baseurl: http://repo.zabbix.com/zabbix/2.2/rhel/6/$basearch/ 61 | - gpgcheck: 1 62 | - gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ZABBIX 63 | - require: 64 | - file: /etc/pki/rpm-gpg/RPM-GPG-KEY-ZABBIX 65 | 66 | zabbix_non_supported_repo: 67 | pkgrepo: 68 | - managed 69 | - name: zabbix_non_supported 70 | - humanname: Zabbix Official Repository non-supported - $basearch 71 | - baseurl: http://repo.zabbix.com/non-supported/rhel/6/$basearch/ 72 | - gpgcheck: 1 73 | - gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-ZABBIX 74 | - require: 75 | - file: /etc/pki/rpm-gpg/RPM-GPG-KEY-ZABBIX 76 | 77 | /etc/pki/rpm-gpg/RPM-GPG-KEY-ZABBIX: 78 | file: 79 | - managed 80 | - contents: | 81 | -----BEGIN PGP PUBLIC KEY BLOCK----- 82 | 83 | mQGiBFCNJaYRBAC4nIW8o2NyOIswb82Xn3AYSMUcNZuKB2fMtpu0WxSXIRiX2BwC 84 | YXx8cIEQVYtLRBL5o0JdmoNCjW6jd5fOVem3EmOcPksvzzRWonIgFHf4EI2n1KJc 85 | JXX/nDC+eoh5xW35mRNFN/BEJHxxiRGGbp2MCnApwgrZLhOujaCGAwavGwCgiG4D 86 | wKMZ4xX6Y2Gv3MSuzMIT0bcEAKYn3WohS+udp0yC3FHDj+oxfuHpklu1xuI3y6ha 87 | 402aEFahNi3wr316ukgdPAYLbpz76ivoouTJ/U2MqbNLjAspDvlnHXXyqPM5GC6K 88 | jtXPqNrRMUCrwisoAhorGUg/+S5pyXwsWcJ6EKmA80pR9HO+TbsELE5bGe/oc238 89 | t/2oBAC3zcQ46wPvXpMCNFb+ED71qDOlnDYaaAPbjgkvnp+WN6nZFFyevjx180Kw 90 | qWOLnlNP6JOuFW27MP75MDPDpbAAOVENp6qnuW9dxXTN80YpPLKUxrQS8vWPnzkY 91 | WtUfF75pEOACFVTgXIqEgW0E6oww2HJi9zF5fS8IlFHJztNYtbQgWmFiYml4IFNJ 92 | QSA8cGFja2FnZXJAemFiYml4LmNvbT6IYAQTEQIAIAUCUI0lpgIbAwYLCQgHAwIE 93 | FQIIAwQWAgMBAh4BAheAAAoJENE9WOR56l7UhUwAmgIGZ39U6D2w2oIWDD8m7KV3 94 | oI06AJ9EnOxMMlxEjTkt9lEvGhEX1bEh7bkBDQRQjSWmEAQAqx+ecOzBbhqMq5hU 95 | l39cJ6l4aocz6EZ9mSSoF/g+HFz6WYnPAfRaYyfLmZdtF5rGBDD4ysalYG5yD59R 96 | Mv5tNVf/CEx+JAPMhp6JCBkGRaH+xHws4eBPGkea4rGNVP3L3rA7g+c1YXZICGRI 97 | OOH7CIzIZ/w6aFGsPp7xM35ogncAAwUD/3s8Nc1OLDy81DC6rGpxfEURd5pvd/j0 98 | D5Di0WSBEcHXp5nThDz6ro/Vr0/FVIBtT97tmBHX27yBS3PqxxNRIjZ0GSWQqdws 99 | Q8o3YT+RHjBugXn8CzTOvIn+2QNMA8EtGIZPpCblJv8q6MFPi9m7avQxguMqufgg 100 | fAk7377Rt9RqiEkEGBECAAkFAlCNJaYCGwwACgkQ0T1Y5HnqXtQx4wCfcJZINKVq 101 | kQIoV3KTQAIzr6IvbZoAn12XXt4GP89xHuzPDZ86YJVAgnfK 102 | =+200 103 | -----END PGP PUBLIC KEY BLOCK----- 104 | {% else %} 105 | zabbix_repo: {} 106 | {% endif %} 107 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/zabbix/server/conf.sls: -------------------------------------------------------------------------------- 1 | {% from "zabbix/map.jinja" import zabbix with context %} 2 | 3 | 4 | include: 5 | - zabbix.server 6 | 7 | 8 | {% set files_switch = salt['pillar.get']('zabbix-server:files_switch', ['id']) %} 9 | 10 | 11 | {% if grains['os_family'] == 'Debian' %} 12 | # We don't want to manage the db through dbconfig when we install the package 13 | # so we set this cmd as prereq. 14 | zabbix-server_debconf: 15 | debconf: 16 | - set 17 | - name: {{ zabbix.server.pkg}} 18 | - data: 19 | 'zabbix-server-mysql/internal/skip-preseed': {'type': 'boolean', 'value': True} 20 | 'zabbix-server-mysql/dbconfig-install': {'type': 'boolean', 'value': False} 21 | 'zabbix-server-mysql/dbconfig-upgrade': {'type': 'boolean', 'value': False} 22 | - prereq: 23 | - pkg: zabbix-server 24 | {% endif %} 25 | 26 | 27 | {{ zabbix.server.config }}: 28 | file: 29 | - managed 30 | - source: 31 | {% for grain in files_switch if salt['grains.get'](grain) is defined -%} 32 | - salt://zabbix/files/{{ salt['grains.get'](grain) }}/etc/zabbix/zabbix_server.conf.jinja 33 | {% endfor -%} 34 | - salt://zabbix/files/default/etc/zabbix/zabbix_server.conf.jinja 35 | - template: jinja 36 | - require: 37 | - pkg: zabbix-server 38 | - watch_in: 39 | - service: zabbix-server 40 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/zabbix/server/init.sls: -------------------------------------------------------------------------------- 1 | {% from "zabbix/map.jinja" import zabbix with context %} 2 | 3 | 4 | zabbix-server: 5 | pkg: 6 | - name: {{ zabbix.server.pkg }} 7 | - installed 8 | {% if zabbix.server.version is defined %} 9 | - version: {{ zabbix.server.version }} 10 | {% endif %} 11 | service: 12 | - name: {{ zabbix.server.service }} 13 | - running 14 | - enable: True 15 | - require: 16 | - pkg: zabbix-server 17 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/zabbix/server/repo.sls: -------------------------------------------------------------------------------- 1 | {% from "zabbix/map.jinja" import zabbix with context %} 2 | 3 | 4 | # We have a common state file for the official Zabbix repo 5 | include: 6 | - zabbix.repo 7 | 8 | 9 | # Here we just add a requisite declaration to ensure correct order 10 | extend: 11 | zabbix_repo: 12 | {%- if salt['grains.get']('os_family') == 'Debian' %} 13 | pkgrepo: 14 | - require_in: 15 | - pkg: zabbix-server 16 | {% else %} {} 17 | {% endif %} 18 | 19 | # IMPORTANT NOTE: This is needed in Debian to ensure that installing the 20 | # server doesn't trigger a install of mysql-server. The official package of 21 | # zabbix-server-mysql "recommends" mysql-server which forces a default install 22 | # with server + db in the same host... which is not always what we want. 23 | # There's no way so far to tell the apt pkg state module something as the 24 | # "--without-recommends" flag just for a package. 25 | {% if grains['os_family'] == 'Debian' %} 26 | /etc/apt/apt.conf.d/00local-disable-recommends: 27 | file: 28 | - managed 29 | - contents: 'APT::Install-Recommends "false";' 30 | - require_in: 31 | - pkgrepo: zabbix_repo 32 | {% endif %} 33 | -------------------------------------------------------------------------------- /tools/zabbix/salt/roots/salt/zabbix/users.sls: -------------------------------------------------------------------------------- 1 | {% from "zabbix/map.jinja" import zabbix with context %} 2 | 3 | 4 | zabbix_user: 5 | user: 6 | - present 7 | - name: {{ salt['pillar.get']('zabbix:user', 'zabbix') }} 8 | 9 | 10 | zabbix_group: 11 | group: 12 | - present 13 | - name: {{ salt['pillar.get']('zabbix:group', 'zabbix') }} 14 | --------------------------------------------------------------------------------