├── .codacy.yml ├── .gitignore ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── config ├── java.d.conf └── java.d │ └── jmx.conf ├── eclipse-formatter.xml ├── installer └── functions.sh ├── mvnw ├── mvnw.cmd ├── netdata-java-orchestrator-installer.sh ├── pom.xml └── src ├── main ├── java │ └── org │ │ └── firehol │ │ └── netdata │ │ ├── CommandLineArgs.java │ │ ├── Main.java │ │ ├── exception │ │ ├── AssertionException.java │ │ ├── IllegalCommandLineArumentException.java │ │ ├── InitializationException.java │ │ ├── NotImplementedException.java │ │ └── UnreachableCodeException.java │ │ ├── model │ │ ├── Chart.java │ │ ├── ChartType.java │ │ ├── Dimension.java │ │ └── DimensionAlgorithm.java │ │ ├── module │ │ ├── Module.java │ │ └── jmx │ │ │ ├── JmxModule.java │ │ │ ├── MBeanServerCollector.java │ │ │ ├── configuration │ │ │ ├── JmxChartConfiguration.java │ │ │ ├── JmxDimensionConfiguration.java │ │ │ ├── JmxModuleConfiguration.java │ │ │ └── JmxServerConfiguration.java │ │ │ ├── exception │ │ │ ├── JmxMBeanServerConnectionException.java │ │ │ ├── JmxMBeanServerQueryException.java │ │ │ ├── JmxModuleException.java │ │ │ └── VirtualMachineConnectionException.java │ │ │ ├── query │ │ │ ├── MBeanCompositeDataQuery.java │ │ │ ├── MBeanDoubleStore.java │ │ │ ├── MBeanIntegerStore.java │ │ │ ├── MBeanLongStore.java │ │ │ ├── MBeanQuery.java │ │ │ ├── MBeanSimpleQuery.java │ │ │ └── MBeanValueStore.java │ │ │ └── utils │ │ │ ├── MBeanServerUtils.java │ │ │ └── VirtualMachineUtils.java │ │ ├── orchestrator │ │ ├── Collector.java │ │ ├── Orchestrator.java │ │ ├── Printer.java │ │ └── configuration │ │ │ ├── ConfigurationService.java │ │ │ ├── EnvironmentConfigurationService.java │ │ │ ├── exception │ │ │ ├── ConfigurationSchemeInstantiationException.java │ │ │ ├── EnvironmentConfigurationException.java │ │ │ └── ParseException.java │ │ │ └── schema │ │ │ └── OrchestratorConfiguration.java │ │ └── utils │ │ ├── AlignToTimeIntervalService.java │ │ ├── ClockService.java │ │ ├── LoggingUtils.java │ │ ├── ResourceUtils.java │ │ ├── StringUtils.java │ │ └── UnitConversion.java └── sh │ └── java.d.plugin └── test └── java └── org └── firehol └── netdata ├── MainTest.java ├── module └── jmx │ ├── MBeanServerCollectorTest.java │ ├── query │ ├── MBeanCompositeDataQueryTest.java │ ├── MBeanQueryTest.java │ └── MBeanValueStoreTest.java │ └── utils │ └── MBeanServerUtilsTest.java ├── orchestrator ├── PrinterTest.java └── configuration │ ├── ConfigurationServiceTest.java │ ├── EnvironmentConfigurationServiceTest.java │ ├── NoTestConfiguration.java │ └── TestConfiguration.java ├── test └── architecture │ └── UtilsTest.java ├── testutils ├── ExitException.java ├── NoExitSecurityManager.java ├── ReflectionUtils.java └── TestObjectBuilder.java └── utils ├── AlignToTimeIntervalServiceTest.java ├── LoggingUtilsTest.java ├── ResourceUtilsTest.java └── StringUtilsTest.java /.codacy.yml: -------------------------------------------------------------------------------- 1 | exclude_paths: 2 | - installer/functions.sh 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Mobile Tools for Java (J2ME) 4 | .mtj.tmp/ 5 | 6 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 7 | hs_err_pid* 8 | 9 | # Eclipse 10 | .classpath 11 | .project 12 | .settings/ 13 | 14 | # IntelliJ IDEA 15 | .idea/ 16 | *.iml 17 | 18 | # Maven 19 | target/ 20 | 21 | # netdata-java-orchestrator-installer.sh 22 | netdata-java-orchestrator-installer.log 23 | netdata-java-orchestrator-uninstaller.sh 24 | 25 | # macOS 26 | .DS_Store 27 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simartn/netdata-java-orchestrator/e03ba0d9b72f31d3cdf23cd474866a6563519b4c/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.6.1/apache-maven-3.6.1-bin.zip -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | 3 | dist: trusty 4 | 5 | jdk: 6 | - oraclejdk8 7 | - oraclejdk9 8 | - oraclejdk11 9 | - openjdk8 10 | 11 | before_install: 12 | - sudo apt-get install jq 13 | - curl -LSs $(curl -LSs https://api.github.com/repos/codacy/codacy-coverage-reporter/releases/latest | jq -r '.assets | map({content_type, browser_download_url} | select(.content_type | contains("application/java-archive"))) | .[0].browser_download_url') -o codacy-coverage-reporter-assembly.jar 14 | 15 | after_success: 16 | - mvn jacoco:report 17 | - java -jar codacy-coverage-reporter-assembly.jar report -l Java -r target/site/jacoco/jacoco.xml 18 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Java Orchestrator 2 | 3 | ## Code Style 4 | 5 | - Stick to the configured code style 6 | - Eclipse formatter definition: `eclipse-formatter.xml` 7 | - To validate the code base run `./mvnw formatter:validate` 8 | - To reformat the code base run `./mvnw formatter:format` 9 | - Stick to the configured import order 10 | - Import order configuration of plugin `net.revelc.code:impsort-maven-plugin` in `pom.xml` 11 | - To validate import order run `./mvnw impsort:check` 12 | - To organize imports run `./mvnw impsort:sort` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Netdata Java Orchestrator 2 | 3 | [![Build Status](https://travis-ci.org/simonnagl/netdata-java-orchestrator.svg?branch=master)](https://travis-ci.org/simonnagl/netdata-java-orchestrator.svg?branch=master) 4 | [![Codacy Badge](https://api.codacy.com/project/badge/Coverage/c5196ea860ba4cb8a47f40c5264cc17f)](https://www.codacy.com/app/simonnagl/netdata-plugin-java-daemon?utm_source=github.com&utm_medium=referral&utm_content=simonnagl/netdata-plugin-java-daemon&utm_campaign=Badge_Coverage) 5 | [![Codacy Badge](https://api.codacy.com/project/badge/Grade/c5196ea860ba4cb8a47f40c5264cc17f)](https://www.codacy.com/app/simonnagl/netdata-plugin-java-daemon?utm_source=github.com&utm_medium=referral&utm_content=simonnagl/netdata-plugin-java-daemon&utm_campaign=badger) 6 | [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fsimonnagl%2Fnetdata-java-orchestrator.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fsimonnagl%2Fnetdata-java-orchestrator?ref=badge_shield) 7 | 8 | netdata-java-orchestrator is a [netdata](https://github.com/firehol/netdata) plugin which can collect any data in java and send it to netdata. 9 | 10 | ## Java Modules 11 | 12 | - JMX Collector 13 | 14 | ## Installation 15 | 16 | ### 1. Prepare your system 17 | 18 | #### Required for compilation 19 | 20 | - netdata 21 | - JDK 8.x 22 | 23 | #### Required to run netdata 24 | 25 | - netdata 26 | - JRE 8.x 27 | 28 | ### 2. Install netdata-java-orchestrator 29 | 30 | Do this to install and run netdata-java-orchestrator: 31 | 32 | ```(sh) 33 | # download it - the directory 'netdata-java-orchestrator' will be created 34 | git clone https://github.com/simonnagl/netdata-java-orchestrator.git --depth=1 35 | cd netdata-java-orchestrator 36 | 37 | # run script with root privileges to build and install the plugin and restart netdata. 38 | netdata-java-orchestrator-installer.sh 39 | ```` 40 | 41 | ## Configuration 42 | 43 | Configuration files contain JSON Objects. 44 | Additional to the JSON specification Java/C++ style comments (both '/'+'*' and '//' varieties) are allowed. 45 | 46 | Each module get's it's own configuration file. The standard configuration should have enogh examples and comments to extend or adapt it. The table below references the classes which describe the JSON schemes of the configuration files. 47 | 48 | File | Schema | Purpose 49 | ---------------------------- | ------ | ------- 50 | /etc/netdata/java.d/jmx.conf | [JmxModuleConfiguration](https://github.com/simonnagl/netdata-java-orchestrator/blob/master/src/main/java/org/firehol/netdata/module/jmx/configuration/JmxModuleConfiguration.java)| JMX module configuration 51 | 52 | 53 | ## License 54 | 55 | netdata-java-orchestrator is [GPLv3+](LICENSE). 56 | 57 | [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fsimonnagl%2Fnetdata-java-orchestrator.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fsimonnagl%2Fnetdata-java-orchestrator?ref=badge_large) 58 | -------------------------------------------------------------------------------- /config/java.d.conf: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | {} -------------------------------------------------------------------------------- /config/java.d/jmx.conf: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | // netdata-java-orchestrator JMX module configuration 4 | // 5 | // The comments in this file should help you to extend this configuration. 6 | // Comments starting with '//' are descriptive comments. Uncommenting them leads to syntax errors. 7 | // Block comments ('/* {...} */') are used to exclude configuration examples. 8 | // These can be uncommented. 9 | // 10 | // For a more formal reference user the configuration scheme: org.firehol.netdata.module.jmx.configuration.JmxModuleConfiguration 11 | 12 | { 13 | // If true auto detect and monitor running local virtual machines. 14 | "autoDetectLocalVirtualMachines": "true", 15 | // Configure a list of JMX servers to monitor. 16 | "jmxServers": [ 17 | // Example configuration for a java program started on the same host with these flags: 18 | // -Dcom.sun.management.jmxremote.port=9999 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false 19 | /* 20 | { 21 | // Name displayed at the dashboard menu. 22 | "name": "ExampleJMX", 23 | // JMX Service URL used to connect to the JVM. 24 | // service:jmx:rmi://[host[:port]][urlPath] 25 | // @see: https://docs.oracle.com/cd/E19159-01/819-7758/gcnqf/index.html 26 | "serviceUrl": "service:jmx:rmi:///jndi/rmi://:9999/jmxrmi" 27 | } 28 | */ 29 | ], 30 | // Global chart configurations. 31 | // Every monitored JMX Servers tries to monitor each chart configuration. 32 | // If a JMX Server does not have the required M(X)Beans we won't try adding it over and over again. 33 | // 34 | // Set of common charts: 35 | // Feel free to open pull requests to share new chart configurations of M(X)Beans distributed with java 36 | // or any open source project. 37 | "commonCharts": [ 38 | // #################################################################### 39 | // Chart configuration documentation 40 | // #################################################################### 41 | /* 42 | { 43 | // Unique ID of this chart in this list. 44 | "id": "example", 45 | // Title describing this chart 46 | "title": "Example chart configuration", 47 | // Unit of the collected value 48 | "units": "some_unit", 49 | // orders charts. Lower numbers make the charts appear before the ones with higher numbers 50 | "priority": "8000", 51 | // Possible chart types: AREA, LINE, STACKED 52 | "chartType": "AREA", 53 | // Possible dimension algorithms: 54 | // ABSOLUTE, INCREMENTAL, PERCENTAGE_OF_ABSOLUTE_ROW, PERCENTAGE_OF_INCREMENTAL_ROW 55 | "dimensionAlgorithm": "ABSOLUTE", 56 | // List of dimensions to add to the chart. 57 | "dimensions": [ 58 | { 59 | // Object Name of the M(X)Bean to collect a value from. 60 | // @see: http://www.oracle.com/technetwork/java/javase/tech/best-practices-jsp-136021.html#mozTocId509360 61 | "from": "java.lang:type=OperatingSystem", 62 | // M(X)Bean attribute to collect. 63 | // The getter of the attribute must return one of these types. 64 | // - Integer (int) 65 | // - Double (double) 66 | // - Long (long) 67 | "value": "ProcessCpuTime", 68 | // Name at the dashboard 69 | "name": "cpu", 70 | // Tells netdata to multiply the value before displaying it. 71 | "multiplier": "1", 72 | // Tells netdata to divide the value before displaying it. 73 | "divisor": "1", 74 | // Collect the value and handle it in dimensionAlgorithm but do not display it. 75 | "hidden": "false" 76 | } 77 | ] 78 | }, 79 | */ 80 | 81 | // #################################################################### 82 | // JVM M(X)Beans 83 | // #################################################################### 84 | { 85 | "id": "cpu", 86 | "title": "JVM CPU utilization", 87 | "units": "percentage", 88 | "priority": "8000", 89 | "chartType": "AREA", 90 | "dimensionAlgorithm": "INCREMENTAL", 91 | "dimensions": [ 92 | { 93 | "from": "java.lang:type=OperatingSystem", 94 | "value": "ProcessCpuTime", 95 | "name": "cpu", 96 | "divisor": "10000000" 97 | } 98 | ] 99 | }, 100 | { 101 | "id": "load", 102 | "title": "JVM Load Average", 103 | "units": "load", 104 | "priority": "8010", 105 | "chartType": "LINE", 106 | "dimensionAlgorithm": "ABSOLUTE", 107 | "dimensions": [ 108 | { 109 | "from": "java.lang:type=OperatingSystem", 110 | "value": "ProcessCpuLoad", 111 | "name": "load1" 112 | } 113 | ] 114 | }, 115 | { 116 | "id": "memory_heap", 117 | "title": "Memory Usage", 118 | "family": "memory", 119 | "units": "KB", 120 | "priority": "8015", 121 | "chartType": "STACKED", 122 | "dimensionAlgorithm": "ABSOLUTE", 123 | "dimensions": [ 124 | { 125 | "from": "java.lang:type=Memory", 126 | "value": "HeapMemoryUsage.used", 127 | "name": "heap", 128 | "divisor": "1000" 129 | }, 130 | { 131 | "from": "java.lang:type=Memory", 132 | "value": "NonHeapMemoryUsage.used", 133 | "name": "no_heap", 134 | "divisor": "1000" 135 | } 136 | ] 137 | }, 138 | { 139 | "id": "memory_by_pool", 140 | "title": "Heap Memory Usage", 141 | "family": "memory", 142 | "units": "KB", 143 | "priority": "8016", 144 | "chartType": "STACKED", 145 | "dimensionAlgorithm": "ABSOLUTE", 146 | "dimensions": [ 147 | { 148 | "from": "java.lang:type=MemoryPool,name=PS Eden Space", 149 | "value": "Usage.used", 150 | "name": "ps_eden_space", 151 | "divisor": "1000" 152 | }, 153 | { 154 | "from": "java.lang:type=MemoryPool,name=PS Old Gen", 155 | "value": "Usage.used", 156 | "name": "ps_old_gen", 157 | "divisor": "1000" 158 | }, 159 | { 160 | "from": "java.lang:type=MemoryPool,name=PS Survivor Space", 161 | "value": "Usage.used", 162 | "name": "ps_survivor_space", 163 | "divisor": "1000" 164 | }, 165 | { 166 | "from": "java.lang:type=MemoryPool,name=Code Cache", 167 | "value": "Usage.used", 168 | "name": "code_cache", 169 | "divisor": "1000" 170 | }, 171 | { 172 | "from": "java.lang:type=MemoryPool,name=Compressed Class Space", 173 | "value": "Usage.used", 174 | "name": "compressed_class_space", 175 | "divisor": "1000" 176 | }, 177 | { 178 | "from": "java.lang:type=MemoryPool,name=Metaspace", 179 | "value": "Usage.used", 180 | "name": "metaspace", 181 | "divisor": "1000" 182 | } 183 | ] 184 | }, 185 | { 186 | "id": "uptime", 187 | "title": "JVM Uptime", 188 | "units": "seconds", 189 | "priority": "8020", 190 | "chartType": "LINE", 191 | "dimensionAlgorithm": "ABSOLUTE", 192 | "dimensions": [ 193 | { 194 | "from": "java.lang:type=Runtime", 195 | "value": "Uptime", 196 | "name": "uptime", 197 | "divisor": "1000" 198 | } 199 | ] 200 | }, 201 | { 202 | "id": "threads_started", 203 | "title": "Threads started", 204 | "family": "threads", 205 | "units": "threads", 206 | "priority": "8030", 207 | "chartType": "LINE", 208 | "dimensionAlgorithm": "ABSOLUTE", 209 | "dimensions": [ 210 | // Returns the total number of threads created and also started since the Java virtual machine started. 211 | { 212 | "from": "java.lang:type=Threading", 213 | "value": "TotalStartedThreadCount", 214 | "name": "threads" 215 | } 216 | ] 217 | }, 218 | { 219 | "id": "threads_active", 220 | "title": "Threads active", 221 | "family": "threads", 222 | "units": "threads", 223 | "priority": "8035", 224 | "chartType": "LINE", 225 | "dimensionAlgorithm": "ABSOLUTE", 226 | "dimensions": [ 227 | // Returns the peak live thread count since the Java virtual machine started or peak was reset. 228 | { 229 | "from": "java.lang:type=Threading", 230 | "value": "PeakThreadCount", 231 | "name": "peak" 232 | }, 233 | // Returns the current number of live daemon threads. 234 | { 235 | "from": "java.lang:type=Threading", 236 | "value": "DaemonThreadCount", 237 | "name": "daemon" 238 | }, 239 | // Returns the current number of live threads including both daemon and non-daemon threads. 240 | { 241 | "from": "java.lang:type=Threading", 242 | "value": "ThreadCount", 243 | "name": "current" 244 | } 245 | ] 246 | }, 247 | { 248 | "id": "classloading", 249 | "title": "Classes loaded", 250 | "family": "class_loading", 251 | "units": "classes", 252 | "priority": "8040", 253 | "chartType": "LINE", 254 | "dimensionAlgorithm": "ABSOLUTE", 255 | "dimensions": [ 256 | { 257 | "from": "java.lang:type=ClassLoading", 258 | "value": "TotalLoadedClassCount", 259 | "name": "loaded_since_start" 260 | }, 261 | { 262 | "from": "java.lang:type=ClassLoading", 263 | "value": "LoadedClassCount", 264 | "name": "current" 265 | }, 266 | { 267 | "from": "java.lang:type=ClassLoading", 268 | "value": "UnloadedClassCount", 269 | "name": "unloaded_since_start" 270 | } 271 | ] 272 | }, 273 | { 274 | "id": "compilation", 275 | "title": "Compilation Time", 276 | "units": "percentage", 277 | "priority": "8050", 278 | "chartType": "LINE", 279 | "dimensionAlgorithm": "INCREMENTAL", 280 | "dimensions": [ 281 | { 282 | "from": "java.lang:type=Compilation", 283 | // Returns the approximate accumlated elapsed time (in milliseconds) spent in compilation. 284 | "value": "TotalCompilationTime", 285 | "name": "total", 286 | // Convert ms/s to percent 287 | "divisor": "10" 288 | } 289 | ] 290 | }, 291 | { 292 | "id": "garbagecount", 293 | "title": "Garbage Collection Number", 294 | "family": "garbage_collection", 295 | "units": "collection/s", 296 | "priority": "8060", 297 | "chartType": "LINE", 298 | "dimensionAlgorithm": "ABSOLUTE", 299 | "dimensions": [ 300 | { 301 | "from": "java.lang:type=GarbageCollector,name=PS Scavenge", 302 | "value": "CollectionCount", 303 | "name": "PS_Scavenge" 304 | }, 305 | { 306 | "from": "java.lang:type=GarbageCollector,name=PS MarkSweep", 307 | "value": "CollectionCount", 308 | "name": "PS_MarkSweep" 309 | } 310 | ] 311 | }, 312 | { 313 | "id": "garbagetime", 314 | "title": "Time spent collecting garbage", 315 | "family": "garbage_collection", 316 | "units": "percentage", 317 | "priority": "8070", 318 | "chartType": "LINE", 319 | "dimensionAlgorithm": "INCREMENTAL", 320 | "dimensions": [ 321 | { 322 | "from": "java.lang:type=GarbageCollector,name=PS Scavenge", 323 | "value": "CollectionTime", 324 | "name": "PS_Scavenge", 325 | "divisor": "10" 326 | }, 327 | { 328 | "from": "java.lang:type=GarbageCollector,name=PS MarkSweep", 329 | "value": "CollectionTime", 330 | "name": "PS_MarkSweep", 331 | "divisor": "10" 332 | } 333 | ] 334 | }, 335 | { 336 | "id": "bufferpool_direct", 337 | "title": "Direct Buffer Pool", 338 | "family": "buffer_pool", 339 | "units": "byte", 340 | "priority": "8080", 341 | "chartType": "LINE", 342 | "dimensionAlgorithm": "ABSOLUTE", 343 | "dimensions": [ 344 | { 345 | "from": "java.nio:type=BufferPool,name=direct", 346 | "value": "TotalCapacity", 347 | "name": "capacity" 348 | }, 349 | { 350 | "from": "java.nio:type=BufferPool,name=direct", 351 | "value": "MemoryUsed", 352 | "name": "used" 353 | } 354 | ] 355 | }, 356 | { 357 | "id": "bufferpool_mapped", 358 | "title": "Mapped Buffer Pool", 359 | "family": "buffer_pool", 360 | "units": "byte", 361 | "priority": "8090", 362 | "chartType": "LINE", 363 | "dimensionAlgorithm": "ABSOLUTE", 364 | "dimensions": [ 365 | { 366 | "from": "java.nio:type=BufferPool,name=mapped", 367 | "value": "TotalCapacity", 368 | "name": "capacity" 369 | }, 370 | { 371 | "from": "java.nio:type=BufferPool,name=mapped", 372 | "value": "MemoryUsed", 373 | "name": "used" 374 | } 375 | ] 376 | } 377 | ] 378 | } 379 | -------------------------------------------------------------------------------- /installer/functions.sh: -------------------------------------------------------------------------------- 1 | # no shebang necessary - this is a library to be sourced 2 | # SPDX-License-Identifier: GPL-3.0-or-later 3 | 4 | # make sure we have a UID 5 | [ -z "${UID}" ] && UID="$(id -u)" 6 | 7 | 8 | # ----------------------------------------------------------------------------- 9 | # checking the availability of commands 10 | 11 | which_cmd() { 12 | which "${1}" 2>/dev/null || \ 13 | command -v "${1}" 2>/dev/null 14 | } 15 | 16 | check_cmd() { 17 | which_cmd "${1}" >/dev/null 2>&1 && return 0 18 | return 1 19 | } 20 | 21 | 22 | # ----------------------------------------------------------------------------- 23 | 24 | setup_terminal() { 25 | TPUT_RESET="" 26 | TPUT_BLACK="" 27 | TPUT_RED="" 28 | TPUT_GREEN="" 29 | TPUT_YELLOW="" 30 | TPUT_BLUE="" 31 | TPUT_PURPLE="" 32 | TPUT_CYAN="" 33 | TPUT_WHITE="" 34 | TPUT_BGBLACK="" 35 | TPUT_BGRED="" 36 | TPUT_BGGREEN="" 37 | TPUT_BGYELLOW="" 38 | TPUT_BGBLUE="" 39 | TPUT_BGPURPLE="" 40 | TPUT_BGCYAN="" 41 | TPUT_BGWHITE="" 42 | TPUT_BOLD="" 43 | TPUT_DIM="" 44 | TPUT_UNDERLINED="" 45 | TPUT_BLINK="" 46 | TPUT_INVERTED="" 47 | TPUT_STANDOUT="" 48 | TPUT_BELL="" 49 | TPUT_CLEAR="" 50 | 51 | # Is stderr on the terminal? If not, then fail 52 | test -t 2 || return 1 53 | 54 | if check_cmd tput 55 | then 56 | if [ $(( $(tput colors 2>/dev/null) )) -ge 8 ] 57 | then 58 | # Enable colors 59 | TPUT_RESET="$(tput sgr 0)" 60 | TPUT_BLACK="$(tput setaf 0)" 61 | TPUT_RED="$(tput setaf 1)" 62 | TPUT_GREEN="$(tput setaf 2)" 63 | TPUT_YELLOW="$(tput setaf 3)" 64 | TPUT_BLUE="$(tput setaf 4)" 65 | TPUT_PURPLE="$(tput setaf 5)" 66 | TPUT_CYAN="$(tput setaf 6)" 67 | TPUT_WHITE="$(tput setaf 7)" 68 | TPUT_BGBLACK="$(tput setab 0)" 69 | TPUT_BGRED="$(tput setab 1)" 70 | TPUT_BGGREEN="$(tput setab 2)" 71 | TPUT_BGYELLOW="$(tput setab 3)" 72 | TPUT_BGBLUE="$(tput setab 4)" 73 | TPUT_BGPURPLE="$(tput setab 5)" 74 | TPUT_BGCYAN="$(tput setab 6)" 75 | TPUT_BGWHITE="$(tput setab 7)" 76 | TPUT_BOLD="$(tput bold)" 77 | TPUT_DIM="$(tput dim)" 78 | TPUT_UNDERLINED="$(tput smul)" 79 | TPUT_BLINK="$(tput blink)" 80 | TPUT_INVERTED="$(tput rev)" 81 | TPUT_STANDOUT="$(tput smso)" 82 | TPUT_BELL="$(tput bel)" 83 | TPUT_CLEAR="$(tput clear)" 84 | fi 85 | fi 86 | 87 | return 0 88 | } 89 | setup_terminal || echo >/dev/null 90 | 91 | progress() { 92 | echo >&2 " --- ${TPUT_DIM}${TPUT_BOLD}${*}${TPUT_RESET} --- " 93 | } 94 | 95 | # ----------------------------------------------------------------------------- 96 | 97 | netdata_banner() { 98 | local l1=" ^" \ 99 | l2=" |.-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-. .-" \ 100 | l3=" | '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' '-' " \ 101 | l4=" +----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+--->" \ 102 | sp=" " \ 103 | netdata="netdata-java-orchestrator" start end msg="${*}" chartcolor="${TPUT_DIM}" 104 | 105 | [ ${#msg} -lt ${#netdata} ] && msg="${msg}${sp:0:$(( ${#netdata} - ${#msg}))}" 106 | [ ${#msg} -gt $(( ${#l2} - 20 )) ] && msg="${msg:0:$(( ${#l2} - 23 ))}..." 107 | 108 | start="$(( ${#l2} / 2 - 4 ))" 109 | [ $(( start + ${#msg} + 4 )) -gt ${#l2} ] && start=$((${#l2} - ${#msg} - 4)) 110 | end=$(( ${start} + ${#msg} + 4 )) 111 | 112 | echo >&2 113 | echo >&2 "${chartcolor}${l1}${TPUT_RESET}" 114 | echo >&2 "${chartcolor}${l2:0:start}${sp:0:2}${TPUT_RESET}${TPUT_BOLD}${TPUT_GREEN}${netdata}${TPUT_RESET}${chartcolor}${sp:0:$((end - start - 2 - ${#netdata}))}${l2:end:$((${#l2} - end))}${TPUT_RESET}" 115 | echo >&2 "${chartcolor}${l3:0:start}${sp:0:2}${TPUT_RESET}${TPUT_BOLD}${TPUT_CYAN}${msg}${TPUT_RESET}${chartcolor}${sp:0:2}${l3:end:$((${#l2} - end))}${TPUT_RESET}" 116 | echo >&2 "${chartcolor}${l4}${TPUT_RESET}" 117 | echo >&2 118 | } 119 | 120 | # ----------------------------------------------------------------------------- 121 | # portable service command 122 | 123 | service_cmd="$(which_cmd service)" 124 | systemctl_cmd="$(which_cmd systemctl)" 125 | service() { 126 | local cmd="${1}" action="${2}" 127 | 128 | if [ ! -z "${systemctl_cmd}" ] 129 | then 130 | run "${systemctl_cmd}" "${action}" "${cmd}" 131 | return $? 132 | elif [ ! -z "${service_cmd}" ] 133 | then 134 | run "${service_cmd}" "${cmd}" "${action}" 135 | return $? 136 | fi 137 | return 1 138 | } 139 | 140 | # ----------------------------------------------------------------------------- 141 | 142 | run_ok() { 143 | printf >&2 "${TPUT_BGGREEN}${TPUT_WHITE}${TPUT_BOLD} OK ${TPUT_RESET} ${*} \n\n" 144 | } 145 | 146 | run_failed() { 147 | printf >&2 "${TPUT_BGRED}${TPUT_WHITE}${TPUT_BOLD} FAILED ${TPUT_RESET} ${*} \n\n" 148 | } 149 | 150 | ESCAPED_PRINT_METHOD= 151 | printf "%q " test >/dev/null 2>&1 152 | [ $? -eq 0 ] && ESCAPED_PRINT_METHOD="printfq" 153 | escaped_print() { 154 | if [ "${ESCAPED_PRINT_METHOD}" = "printfq" ] 155 | then 156 | printf "%q " "${@}" 157 | else 158 | printf "%s" "${*}" 159 | fi 160 | return 0 161 | } 162 | 163 | run_logfile="/dev/null" 164 | run() { 165 | local user="${USER--}" dir="${PWD}" info info_console 166 | 167 | if [ "${UID}" = "0" ] 168 | then 169 | info="[root ${dir}]# " 170 | info_console="[${TPUT_DIM}${dir}${TPUT_RESET}]# " 171 | else 172 | info="[${user} ${dir}]$ " 173 | info_console="[${TPUT_DIM}${dir}${TPUT_RESET}]$ " 174 | fi 175 | 176 | printf >> "${run_logfile}" "${info}" 177 | escaped_print >> "${run_logfile}" "${@}" 178 | printf >> "${run_logfile}" " ... " 179 | 180 | printf >&2 "${info_console}${TPUT_BOLD}${TPUT_YELLOW}" 181 | escaped_print >&2 "${@}" 182 | printf >&2 "${TPUT_RESET}\n" 183 | 184 | "${@}" 185 | 186 | local ret=$? 187 | if [ ${ret} -ne 0 ] 188 | then 189 | run_failed 190 | printf >> "${run_logfile}" "FAILED with exit code ${ret}\n" 191 | else 192 | run_ok 193 | printf >> "${run_logfile}" "OK\n" 194 | fi 195 | 196 | return ${ret} 197 | } 198 | 199 | getent_cmd="$(which_cmd getent)" 200 | portable_check_user_exists() { 201 | local username="${1}" found= 202 | 203 | if [ ! -z "${getent_cmd}" ] 204 | then 205 | "${getent_cmd}" passwd "${username}" >/dev/null 2>&1 206 | return $? 207 | fi 208 | 209 | found="$(cut -d ':' -f 1 /dev/null 2>&1 220 | return $? 221 | fi 222 | 223 | found="$(cut -d ':' -f 1 &2 "User '${username}' already exists." && return 0 247 | 248 | echo >&2 "Adding ${username} user account ..." 249 | 250 | local nologin="$(which nologin 2>/dev/null || command -v nologin 2>/dev/null || echo '/bin/false')" 251 | 252 | # Linux 253 | if check_cmd useradd 254 | then 255 | run useradd -r -g "${username}" -c "${username}" -s "${nologin}" -d / "${username}" && return 0 256 | fi 257 | 258 | # FreeBSD 259 | if check_cmd pw 260 | then 261 | run pw useradd "${username}" -d / -g "${username}" -s "${nologin}" && return 0 262 | fi 263 | 264 | # BusyBox 265 | if check_cmd adduser 266 | then 267 | run adduser -D -G "${username}" "${username}" && return 0 268 | fi 269 | 270 | echo >&2 "Failed to add ${username} user account !" 271 | 272 | return 1 273 | } 274 | 275 | portable_add_group() { 276 | local groupname="${1}" 277 | 278 | portable_check_group_exists "${groupname}" 279 | [ $? -eq 0 ] && echo >&2 "Group '${groupname}' already exists." && return 0 280 | 281 | echo >&2 "Adding ${groupname} user group ..." 282 | 283 | # Linux 284 | if check_cmd groupadd 285 | then 286 | run groupadd -r "${groupname}" && return 0 287 | fi 288 | 289 | # FreeBSD 290 | if check_cmd pw 291 | then 292 | run pw groupadd "${groupname}" && return 0 293 | fi 294 | 295 | # BusyBox 296 | if check_cmd addgroup 297 | then 298 | run addgroup "${groupname}" && return 0 299 | fi 300 | 301 | echo >&2 "Failed to add ${groupname} user group !" 302 | return 1 303 | } 304 | 305 | portable_add_user_to_group() { 306 | local groupname="${1}" username="${2}" 307 | 308 | portable_check_group_exists "${groupname}" 309 | [ $? -ne 0 ] && echo >&2 "Group '${groupname}' does not exist." && return 1 310 | 311 | # find the user is already in the group 312 | if portable_check_user_in_group "${username}" "${groupname}" 313 | then 314 | # username is already there 315 | echo >&2 "User '${username}' is already in group '${groupname}'." 316 | return 0 317 | else 318 | # username is not in group 319 | echo >&2 "Adding ${username} user to the ${groupname} group ..." 320 | 321 | # Linux 322 | if check_cmd usermod 323 | then 324 | run usermod -a -G "${groupname}" "${username}" && return 0 325 | fi 326 | 327 | # FreeBSD 328 | if check_cmd pw 329 | then 330 | run pw groupmod "${groupname}" -m "${username}" && return 0 331 | fi 332 | 333 | # BusyBox 334 | if check_cmd addgroup 335 | then 336 | run addgroup "${username}" "${groupname}" && return 0 337 | fi 338 | 339 | echo >&2 "Failed to add user ${username} to group ${groupname} !" 340 | return 1 341 | fi 342 | } 343 | 344 | iscontainer() { 345 | # man systemd-detect-virt 346 | local cmd=$(which_cmd systemd-detect-virt) 347 | if [ ! -z "${cmd}" -a -x "${cmd}" ] 348 | then 349 | "${cmd}" --container >/dev/null 2>&1 && return 0 350 | fi 351 | 352 | # /proc/1/sched exposes the host's pid of our init ! 353 | # http://stackoverflow.com/a/37016302 354 | local pid=$( cat /proc/1/sched 2>/dev/null | head -n 1 | { IFS='(),#:' read name pid th threads; echo $pid; } ) 355 | pid=$(( pid + 0 )) 356 | [ ${pid} -ne 1 ] && return 0 357 | 358 | # lxc sets environment variable 'container' 359 | [ ! -z "${container}" ] && return 0 360 | 361 | # docker creates /.dockerenv 362 | # http://stackoverflow.com/a/25518345 363 | [ -f "/.dockerenv" ] && return 0 364 | 365 | # ubuntu and debian supply /bin/running-in-container 366 | # https://www.apt-browse.org/browse/ubuntu/trusty/main/i386/upstart/1.12.1-0ubuntu4/file/bin/running-in-container 367 | if [ -x "/bin/running-in-container" ] 368 | then 369 | "/bin/running-in-container" >/dev/null 2>&1 && return 0 370 | fi 371 | 372 | return 1 373 | } 374 | 375 | issystemd() { 376 | local pids p myns ns systemctl 377 | 378 | # if the directory /etc/systemd/system does not exit, it is not systemd 379 | [ ! -d /etc/systemd/system ] && return 1 380 | 381 | # if there is no systemctl command, it is not systemd 382 | systemctl=$(which systemctl 2>/dev/null || command -v systemctl 2>/dev/null) 383 | [ -z "${systemctl}" -o ! -x "${systemctl}" ] && return 1 384 | 385 | # if pid 1 is systemd, it is systemd 386 | [ "$(basename $(readlink /proc/1/exe) 2>/dev/null)" = "systemd" ] && return 0 387 | 388 | # if systemd is not running, it is not systemd 389 | pids=$(pidof systemd 2>/dev/null) 390 | [ -z "${pids}" ] && return 1 391 | 392 | # check if the running systemd processes are not in our namespace 393 | myns="$(readlink /proc/self/ns/pid 2>/dev/null)" 394 | for p in ${pids} 395 | do 396 | ns="$(readlink /proc/${p}/ns/pid 2>/dev/null)" 397 | 398 | # if pid of systemd is in our namespace, it is systemd 399 | [ ! -z "${myns}" && "${myns}" = "${ns}" ] && return 0 400 | done 401 | 402 | # else, it is not systemd 403 | return 1 404 | } 405 | 406 | install_non_systemd_init() { 407 | [ "${UID}" != 0 ] && return 1 408 | 409 | local key="unknown" 410 | if [ -f /etc/os-release ] 411 | then 412 | source /etc/os-release || return 1 413 | key="${ID}-${VERSION_ID}" 414 | 415 | elif [ -f /etc/redhat-release ] 416 | then 417 | key=$(&2 "Installing OpenRC init file..." 425 | run cp system/netdata-openrc /etc/init.d/netdata && \ 426 | run chmod 755 /etc/init.d/netdata && \ 427 | run rc-update add netdata default && \ 428 | return 0 429 | 430 | elif [ "${key}" = "debian-7" \ 431 | -o "${key}" = "ubuntu-12.04" \ 432 | -o "${key}" = "ubuntu-14.04" \ 433 | ] 434 | then 435 | echo >&2 "Installing LSB init file..." 436 | run cp system/netdata-lsb /etc/init.d/netdata && \ 437 | run chmod 755 /etc/init.d/netdata && \ 438 | run update-rc.d netdata defaults && \ 439 | run update-rc.d netdata enable && \ 440 | return 0 441 | elif [[ "${key}" =~ ^(amzn-201[567]|ol|CentOS release 6|Red Hat Enterprise Linux Server release 6).* ]] 442 | then 443 | echo >&2 "Installing init.d file..." 444 | run cp system/netdata-init-d /etc/init.d/netdata && \ 445 | run chmod 755 /etc/init.d/netdata && \ 446 | run chkconfig netdata on && \ 447 | return 0 448 | else 449 | echo >&2 "I don't know what init file to install on system '${key}'. Open a github issue to help us fix it." 450 | return 1 451 | fi 452 | elif [ -f /etc/init.d/netdata ] 453 | then 454 | echo >&2 "file '/etc/init.d/netdata' already exists." 455 | return 0 456 | else 457 | echo >&2 "I don't know what init file to install on system '${key}'. Open a github issue to help us fix it." 458 | fi 459 | 460 | return 1 461 | } 462 | 463 | NETDATA_START_CMD="netdata" 464 | NETDATA_STOP_CMD="killall netdata" 465 | 466 | install_netdata_service() { 467 | if [ "${UID}" -eq 0 ] 468 | then 469 | if issystemd 470 | then 471 | # systemd is running on this system 472 | NETDATA_START_CMD="systemctl start netdata" 473 | NETDATA_STOP_CMD="systemctl stop netdata" 474 | 475 | if [ ! -f /etc/systemd/system/netdata.service ] 476 | then 477 | echo >&2 "Installing systemd service..." 478 | run cp system/netdata.service /etc/systemd/system/netdata.service && \ 479 | run systemctl daemon-reload && \ 480 | run systemctl enable netdata && \ 481 | return 0 482 | else 483 | echo >&2 "file '/etc/systemd/system/netdata.service' already exists." 484 | return 0 485 | fi 486 | else 487 | install_non_systemd_init 488 | local ret=$? 489 | 490 | if [ ${ret} -eq 0 ] 491 | then 492 | NETDATA_START_CMD="service netdata start" 493 | NETDATA_STOP_CMD="service netdata stop" 494 | fi 495 | 496 | return ${ret} 497 | fi 498 | fi 499 | 500 | return 1 501 | } 502 | 503 | 504 | # ----------------------------------------------------------------------------- 505 | # stop netdata 506 | 507 | pidisnetdata() { 508 | if [ -d /proc/self ] 509 | then 510 | [ -z "$1" -o ! -f "/proc/$1/stat" ] && return 1 511 | [ "$(cat "/proc/$1/stat" | cut -d '(' -f 2 | cut -d ')' -f 1)" = "netdata" ] && return 0 512 | return 1 513 | fi 514 | return 0 515 | } 516 | 517 | stop_netdata_on_pid() { 518 | local pid="${1}" ret=0 count=0 519 | 520 | pidisnetdata ${pid} || return 0 521 | 522 | printf >&2 "Stopping netdata on pid ${pid} ..." 523 | while [ ! -z "$pid" -a ${ret} -eq 0 ] 524 | do 525 | if [ ${count} -gt 45 ] 526 | then 527 | echo >&2 "Cannot stop the running netdata on pid ${pid}." 528 | return 1 529 | fi 530 | 531 | count=$(( count + 1 )) 532 | 533 | run kill ${pid} 2>/dev/null 534 | ret=$? 535 | 536 | test ${ret} -eq 0 && printf >&2 "." && sleep 2 537 | done 538 | 539 | echo >&2 540 | if [ ${ret} -eq 0 ] 541 | then 542 | echo >&2 "SORRY! CANNOT STOP netdata ON PID ${pid} !" 543 | return 1 544 | fi 545 | 546 | echo >&2 "netdata on pid ${pid} stopped." 547 | return 0 548 | } 549 | 550 | stop_all_netdata() { 551 | local p myns ns 552 | 553 | myns="$(readlink /proc/self/ns/pid 2>/dev/null)" 554 | 555 | # echo >&2 "Stopping a (possibly) running netdata (namespace '${myns}')..." 556 | 557 | for p in \ 558 | $(cat /var/run/netdata.pid 2>/dev/null) \ 559 | $(cat /var/run/netdata/netdata.pid 2>/dev/null) \ 560 | $(pidof netdata 2>/dev/null) 561 | do 562 | ns="$(readlink /proc/${p}/ns/pid 2>/dev/null)" 563 | 564 | if [ -z "${myns}" -o -z "${ns}" -o "${myns}" = "${ns}" ] 565 | then 566 | stop_netdata_on_pid ${p} 567 | fi 568 | done 569 | } 570 | 571 | # ----------------------------------------------------------------------------- 572 | # restart netdata 573 | 574 | restart_netdata() { 575 | local netdata="${1}" 576 | shift 577 | 578 | local started=0 579 | 580 | progress "Start netdata" 581 | 582 | if [ "${UID}" -eq 0 ] 583 | then 584 | service netdata stop 585 | stop_all_netdata 586 | service netdata restart && started=1 587 | 588 | if [ ${started} -eq 0 ] 589 | then 590 | service netdata start && started=1 591 | fi 592 | fi 593 | 594 | if [ ${started} -eq 0 ] 595 | then 596 | # still not started... 597 | 598 | run stop_all_netdata 599 | run "${netdata}" "${@}" 600 | return $? 601 | fi 602 | 603 | return 0 604 | } 605 | 606 | # ----------------------------------------------------------------------------- 607 | # install netdata logrotate 608 | 609 | install_netdata_logrotate() { 610 | if [ ${UID} -eq 0 ] 611 | then 612 | if [ -d /etc/logrotate.d ] 613 | then 614 | if [ ! -f /etc/logrotate.d/netdata ] 615 | then 616 | run cp system/netdata.logrotate /etc/logrotate.d/netdata 617 | fi 618 | 619 | if [ -f /etc/logrotate.d/netdata ] 620 | then 621 | run chmod 644 /etc/logrotate.d/netdata 622 | fi 623 | 624 | return 0 625 | fi 626 | fi 627 | 628 | return 1 629 | } 630 | 631 | # ----------------------------------------------------------------------------- 632 | # add netdata user and group 633 | 634 | NETDATA_ADDED_TO_DOCKER=0 635 | NETDATA_ADDED_TO_NGINX=0 636 | NETDATA_ADDED_TO_VARNISH=0 637 | NETDATA_ADDED_TO_HAPROXY=0 638 | NETDATA_ADDED_TO_ADM=0 639 | NETDATA_ADDED_TO_NSD=0 640 | NETDATA_ADDED_TO_PROXY=0 641 | NETDATA_ADDED_TO_SQUID=0 642 | add_netdata_user_and_group() { 643 | if [ ${UID} -eq 0 ] 644 | then 645 | portable_add_group netdata || return 1 646 | portable_add_user netdata || return 1 647 | portable_add_user_to_group docker netdata && NETDATA_ADDED_TO_DOCKER=1 648 | portable_add_user_to_group nginx netdata && NETDATA_ADDED_TO_NGINX=1 649 | portable_add_user_to_group varnish netdata && NETDATA_ADDED_TO_VARNISH=1 650 | portable_add_user_to_group haproxy netdata && NETDATA_ADDED_TO_HAPROXY=1 651 | portable_add_user_to_group adm netdata && NETDATA_ADDED_TO_ADM=1 652 | portable_add_user_to_group nsd netdata && NETDATA_ADDED_TO_NSD=1 653 | portable_add_user_to_group proxy netdata && NETDATA_ADDED_TO_PROXY=1 654 | portable_add_user_to_group squid netdata && NETDATA_ADDED_TO_SQUID=1 655 | return 0 656 | fi 657 | 658 | return 1 659 | } -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Migwn, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | # TODO classpath? 118 | fi 119 | 120 | if [ -z "$JAVA_HOME" ]; then 121 | javaExecutable="`which javac`" 122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 123 | # readlink(1) is not available as standard on Solaris 10. 124 | readLink=`which readlink` 125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 126 | if $darwin ; then 127 | javaHome="`dirname \"$javaExecutable\"`" 128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 129 | else 130 | javaExecutable="`readlink -f \"$javaExecutable\"`" 131 | fi 132 | javaHome="`dirname \"$javaExecutable\"`" 133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 134 | JAVA_HOME="$javaHome" 135 | export JAVA_HOME 136 | fi 137 | fi 138 | fi 139 | 140 | if [ -z "$JAVACMD" ] ; then 141 | if [ -n "$JAVA_HOME" ] ; then 142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 143 | # IBM's JDK on AIX uses strange locations for the executables 144 | JAVACMD="$JAVA_HOME/jre/sh/java" 145 | else 146 | JAVACMD="$JAVA_HOME/bin/java" 147 | fi 148 | else 149 | JAVACMD="`which java`" 150 | fi 151 | fi 152 | 153 | if [ ! -x "$JAVACMD" ] ; then 154 | echo "Error: JAVA_HOME is not defined correctly." >&2 155 | echo " We cannot execute $JAVACMD" >&2 156 | exit 1 157 | fi 158 | 159 | if [ -z "$JAVA_HOME" ] ; then 160 | echo "Warning: JAVA_HOME environment variable is not set." 161 | fi 162 | 163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 164 | 165 | # traverses directory structure from process work directory to filesystem root 166 | # first directory with .mvn subdirectory is considered project base directory 167 | find_maven_basedir() { 168 | 169 | if [ -z "$1" ] 170 | then 171 | echo "Path not specified to find_maven_basedir" 172 | return 1 173 | fi 174 | 175 | basedir="$1" 176 | wdir="$1" 177 | while [ "$wdir" != '/' ] ; do 178 | if [ -d "$wdir"/.mvn ] ; then 179 | basedir=$wdir 180 | break 181 | fi 182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 183 | if [ -d "${wdir}" ]; then 184 | wdir=`cd "$wdir/.."; pwd` 185 | fi 186 | # end of workaround 187 | done 188 | echo "${basedir}" 189 | } 190 | 191 | # concatenates all lines of a file 192 | concat_lines() { 193 | if [ -f "$1" ]; then 194 | echo "$(tr -s '\n' ' ' < "$1")" 195 | fi 196 | } 197 | 198 | BASE_DIR=`find_maven_basedir "$(pwd)"` 199 | if [ -z "$BASE_DIR" ]; then 200 | exit 1; 201 | fi 202 | 203 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 204 | echo $MAVEN_PROJECTBASEDIR 205 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 206 | 207 | # For Cygwin, switch paths to Windows format before running java 208 | if $cygwin; then 209 | [ -n "$M2_HOME" ] && 210 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 211 | [ -n "$JAVA_HOME" ] && 212 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 213 | [ -n "$CLASSPATH" ] && 214 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 215 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 216 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 217 | fi 218 | 219 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 220 | 221 | exec "$JAVACMD" \ 222 | $MAVEN_OPTS \ 223 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 224 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 225 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 226 | -------------------------------------------------------------------------------- /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 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 84 | @REM Fallback to current working directory if not found. 85 | 86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 88 | 89 | set EXEC_DIR=%CD% 90 | set WDIR=%EXEC_DIR% 91 | :findBaseDir 92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 93 | cd .. 94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 95 | set WDIR=%CD% 96 | goto findBaseDir 97 | 98 | :baseDirFound 99 | set MAVEN_PROJECTBASEDIR=%WDIR% 100 | cd "%EXEC_DIR%" 101 | goto endDetectBaseDir 102 | 103 | :baseDirNotFound 104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 105 | cd "%EXEC_DIR%" 106 | 107 | :endDetectBaseDir 108 | 109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 110 | 111 | @setlocal EnableExtensions EnableDelayedExpansion 112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 114 | 115 | :endReadAdditionalConfig 116 | 117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 118 | 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 123 | if ERRORLEVEL 1 goto error 124 | goto end 125 | 126 | :error 127 | set ERROR_CODE=1 128 | 129 | :end 130 | @endlocal & set ERROR_CODE=%ERROR_CODE% 131 | 132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 136 | :skipRcPost 137 | 138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 140 | 141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 142 | 143 | exit /B %ERROR_CODE% 144 | -------------------------------------------------------------------------------- /netdata-java-orchestrator-installer.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # SPDX-License-Identifier: GPL-3.0-or-later 3 | 4 | source_dir="$(pwd)" 5 | installer_dir="$(dirname "${0}")" 6 | 7 | if [ "${source_dir}" != "${installer_dir}" -a "${installer_dir}" != "." ] 8 | then 9 | echo >&2 "Warning: you are currently in '${source_dir}' but the installer is in '${installer_dir}'." 10 | fi 11 | 12 | 13 | # ----------------------------------------------------------------------------- 14 | # reload the user profile 15 | 16 | [ -f /etc/profile ] && . /etc/profile 17 | 18 | # make sure /etc/profile does not change our current directory 19 | cd "${source_dir}" || exit 1 20 | 21 | 22 | # ----------------------------------------------------------------------------- 23 | # load the required functions 24 | 25 | if [ -f "${installer_dir}/installer/functions.sh" ] 26 | then 27 | source "${installer_dir}/installer/functions.sh" || exit 1 28 | else 29 | source "${source_dir}/installer/functions.sh" || exit 1 30 | fi 31 | 32 | run_logfile="netdata-java-orchestrator-installer.log" 33 | 34 | umask 002 35 | 36 | # Be nice on production environments 37 | renice 19 $$ >/dev/null 2>/dev/null 38 | 39 | ME="$0" 40 | DONOTSTART=0 41 | DONOTWAIT=0 42 | NETDATA_PREFIX= 43 | NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS-}" 44 | 45 | usage() { 46 | netdata_banner "installer command line options" 47 | cat < 50 | 51 | Valid are: 52 | 53 | --install /PATH/TO/INSTALL 54 | 55 | If you give: --install /opt 56 | netdata-java-orchestrator will be installed in /opt/netdata 57 | Use the same value you used for netdata-installer.sh. 58 | 59 | --dont-start-it 60 | 61 | Do not (re)start netdata. 62 | Just install it. 63 | 64 | --dont-wait 65 | 66 | Do not wait for the user to press ENTER. 67 | Start immediately building it. 68 | 69 | For the installer to complete successfully, you will need 70 | these packages installed: 71 | 72 | netdata 73 | jdk8 74 | jre8 75 | 76 | USAGE 77 | } 78 | 79 | # Parse command line 80 | while [ ! -z "${1}" ] 81 | do 82 | if [ "$1" = "--install" ] 83 | then 84 | NETDATA_PREFIX="${2}/netdata" 85 | shift 2 86 | elif [ "$1" = "--dont-start-it" ] 87 | then 88 | DONOTSTART=1 89 | shift 1 90 | elif [ "$1" = "--dont-wait" ] 91 | then 92 | DONOTWAIT=1 93 | shift 1 94 | elif [ "$1" = "--help" -o "$1" = "-h" ] 95 | then 96 | usage 97 | exit 1 98 | elif [ "$1" = "get_git_config_signatures" ] 99 | then 100 | get_git_config_signatures && exit 0 101 | exit 1 102 | else 103 | echo >&2 104 | echo >&2 "ERROR:" 105 | echo >&2 "I cannot understand option '$1'." 106 | usage 107 | exit 1 108 | fi 109 | done 110 | 111 | netdata_banner "java orchestrator with jmx monitoring" 112 | cat <&2 -ep \$'\001${TPUT_BOLD}${TPUT_GREEN}\002Press ENTER to build and install netdata-java-orchestrator to \'\001${TPUT_CYAN}\002${NETDATA_PREFIX}\001${TPUT_YELLOW}\002\'\001${TPUT_RESET}\002 > ' -e -r REPLY" 194 | else 195 | eval "read >&2 -ep \$'\001${TPUT_BOLD}${TPUT_GREEN}\002Press ENTER to build and install netdata-java-orchestrator to your system\001${TPUT_RESET}\002 > ' -e -r REPLY" 196 | fi 197 | fi 198 | 199 | build_error() { 200 | netdata_banner "sorry, it failed to build..." 201 | cat < ${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/java.d.plugin 238 | run chmod 0755 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/java.d.plugin" 239 | 240 | # Copy configuration 241 | NETDATA_CONFIG_DIR="${NETDATA_PREFIX}/etc/netdata/" 242 | [ -d "${NETDATA_CONFIG_DIR}" ] || run mkdir -p "${NETDATA_CONFIG_DIR}" 243 | [ -f "${NETDATA_CONFIG_DIR}/java.d.conf" ] || run cp "config/java.d.conf" "${NETDATA_CONFIG_DIR}" 244 | 245 | # Copy plugin configuration files if not present. 246 | [ -d "${NETDATA_CONFIG_DIR}/java.d" ] || run mkdir -p "${NETDATA_CONFIG_DIR}/java.d" 247 | for filename in $(ls config/java.d) 248 | do 249 | [ -f "${NETDATA_CONFIG_DIR}/java.d/${filename}" ] || run cp "config/java.d/${filename}" "${NETDATA_CONFIG_DIR}/java.d/" 250 | done 251 | 252 | # ----------------------------------------------------------------------------- 253 | # check if we can re-start netdata 254 | 255 | started=0 256 | if [ ${DONOTSTART} -ne 1 ] 257 | then 258 | restart_netdata ${NETDATA_PREFIX}/usr/sbin/netdata "${@}" 259 | if [ $? -ne 0 ] 260 | then 261 | echo >&2 262 | echo >&2 "SORRY! FAILED TO START NETDATA!" 263 | echo >&2 264 | exit 1 265 | fi 266 | 267 | started=1 268 | echo >&2 "OK. NetData Started!" 269 | echo >&2 270 | fi 271 | 272 | # ----------------------------------------------------------------------------- 273 | progress "Generate netdata-java-orchestrator-uninstaller.sh" 274 | 275 | cat >netdata-java-orchestrator-uninstaller.sh <&2 "This script will REMOVE netdata-java-orchestrator from your system." 284 | echo >&2 "Run it again with --force to do it." 285 | exit 1 286 | fi 287 | 288 | deletedir() { 289 | if [ ! -z "\$1" -a -d "\$1" ] 290 | then 291 | echo 292 | echo "Deleting directory '\$1' ..." 293 | rm -r "\$1" 294 | fi 295 | } 296 | 297 | deletedir "${NETDATA_PREFIX}/usr/libexec/netdata-java-orchestrator" 298 | rm -f ${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/java.d.plugin 299 | rm -f ${NETDATA_PREFIX}/etc/netdata/java.d.conf 300 | deletedir "${NETDATA_PREFIX}/etc/netdata/java.d" 301 | 302 | UNINSTALL 303 | chmod 750 netdata-java-orchestrator-uninstaller.sh 304 | 305 | # ----------------------------------------------------------------------------- 306 | progress "Basic netdata-java-orchestrator instructions" 307 | 308 | cat <&2 "Uninstall script generated: ${TPUT_RED}${TPUT_BOLD}./netdata-java-orchestrator-uninstaller.sh${TPUT_RESET}" 315 | 316 | # ----------------------------------------------------------------------------- 317 | echo >&2 318 | progress "We are done!" 319 | 320 | if [ ${started} -eq 1 ] 321 | then 322 | netdata_banner "is installed and running now!" 323 | else 324 | netdata_banner "is installed now!" 325 | fi 326 | 327 | echo >&2 " enjoy real-time performance and health monitoring..." 328 | echo >&2 329 | exit 0 330 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | org.firehol.netdata 5 | java-orchestrator 6 | jar 7 | 0.1.0-SNAPSHOT 8 | netdata-java-orchestrator 9 | http://netdata.firehol.org 10 | 11 | 12 | 2.0.2 13 | 14 | 15 | UTF-8 16 | 1.8 17 | 1.8 18 | 19 | 20 | 21 | com.github.olivergondza 22 | maven-jdk-tools-wrapper 23 | 0.1 24 | 25 | 26 | com.fasterxml.jackson.core 27 | jackson-databind 28 | 2.13.4.1 29 | 30 | 31 | org.projectlombok 32 | lombok 33 | 1.18.8 34 | provided 35 | 36 | 37 | junit 38 | junit 39 | 4.13.1 40 | test 41 | 42 | 43 | org.mockito 44 | mockito-core 45 | 3.0.0 46 | test 47 | 48 | 49 | org.powermock 50 | powermock-module-junit4 51 | ${powermock.version} 52 | test 53 | 54 | 55 | org.powermock 56 | powermock-api-mockito2 57 | ${powermock.version} 58 | test 59 | 60 | 61 | 62 | com.github.stefanbirkner 63 | system-rules 64 | 1.19.0 65 | test 66 | 67 | 68 | com.tngtech.archunit 69 | archunit 70 | 0.11.0 71 | test 72 | 73 | 74 | 75 | 76 | 77 | net.revelc.code.formatter 78 | formatter-maven-plugin 79 | 2.7.2 80 | 81 | ${project.basedir}/eclipse-formatter.xml 82 | 83 | 84 | 85 | 86 | validate 87 | 88 | 89 | 90 | 91 | 92 | net.revelc.code 93 | impsort-maven-plugin 94 | 1.0.1 95 | 96 | java.,javax.,org.,com. 97 | java,* 98 | 99 | 100 | 101 | 102 | check 103 | 104 | 105 | 106 | 107 | 108 | org.apache.maven.plugins 109 | maven-jar-plugin 110 | 3.0.2 111 | 112 | 113 | 114 | org.firehol.netdata.Main 115 | 116 | 117 | ${java.home}/../lib/tools.jar 118 | 119 | 120 | 121 | 122 | 123 | org.apache.maven.plugins 124 | maven-shade-plugin 125 | 3.1.0 126 | 127 | false 128 | 129 | 130 | 131 | package 132 | 133 | shade 134 | 135 | 136 | 137 | 138 | 139 | org.jacoco 140 | jacoco-maven-plugin 141 | 0.8.3 142 | 143 | 144 | jacoco-initialize 145 | 146 | prepare-agent 147 | 148 | 149 | 150 | jacoco-site 151 | post-integration-test 152 | 153 | report 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | org.apache.maven.plugins 164 | maven-javadoc-plugin 165 | 3.0.0-M1 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | Firehol 174 | http://firehol.org 175 | 176 | 177 | https://github.com/simonnagl/netdata-java-orchestrator 178 | scm:git:https://github.com/simonnagl/netdata-java-orchestrator.git 179 | scm:git:https://github.com/simonnagl/netdata-java-orchestrator.git 180 | HEAD 181 | 182 | 183 | GitHub 184 | https://github.com/simonnagl/netdata-java-orchestrator/issues 185 | 186 | 187 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/CommandLineArgs.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata; 4 | 5 | import org.firehol.netdata.exception.AssertionException; 6 | import org.firehol.netdata.exception.IllegalCommandLineArumentException; 7 | 8 | public final class CommandLineArgs { 9 | 10 | private final String[] args; 11 | 12 | public CommandLineArgs(final String[] args) { 13 | this.args = args; 14 | } 15 | 16 | public int getUpdateEveryInSeconds() throws IllegalCommandLineArumentException { 17 | try { 18 | assertJustOne(); 19 | } catch (Exception e) { 20 | throw new IllegalCommandLineArumentException("Wrong number of command lines found.", e); 21 | } 22 | 23 | try { 24 | return Integer.valueOf(args[0]); 25 | } catch (Exception e) { 26 | throw new IllegalCommandLineArumentException("First command line argument is no integer.", e); 27 | } 28 | 29 | } 30 | 31 | private void assertJustOne() throws AssertionException { 32 | if (args.length < 1) { 33 | throw new AssertionException("Expected just one command line argument. " + args.length + " are present."); 34 | } 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/Main.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata; 4 | 5 | import java.util.Collections; 6 | import java.util.LinkedList; 7 | import java.util.List; 8 | import java.util.logging.Logger; 9 | 10 | import org.firehol.netdata.exception.UnreachableCodeException; 11 | import org.firehol.netdata.module.Module; 12 | import org.firehol.netdata.module.jmx.JmxModule; 13 | import org.firehol.netdata.orchestrator.Orchestrator; 14 | import org.firehol.netdata.orchestrator.Printer; 15 | import org.firehol.netdata.orchestrator.configuration.ConfigurationService; 16 | import org.firehol.netdata.utils.LoggingUtils; 17 | 18 | public final class Main { 19 | private static final Logger log = Logger.getLogger("org.firehol.netdata.orchestrator"); 20 | 21 | private static List modules = Collections.emptyList(); 22 | 23 | private Main() { 24 | } 25 | 26 | public static void main(final String[] args) { 27 | int updateEverySecond = getUpdateEveryInSecondsFomCommandLineFailFast(args); 28 | configureModules(); 29 | new Orchestrator(updateEverySecond, modules).start(); 30 | } 31 | 32 | static int getUpdateEveryInSecondsFomCommandLineFailFast(final String[] args) { 33 | try { 34 | return new CommandLineArgs(args).getUpdateEveryInSeconds(); 35 | } catch (Exception failureReason) { 36 | exit(LoggingUtils.buildMessage("Invalid command line options supplied.", failureReason)); 37 | throw new UnreachableCodeException(); 38 | } 39 | } 40 | 41 | private static void configureModules() { 42 | ConfigurationService configService = ConfigurationService.getInstance(); 43 | modules = new LinkedList<>(); 44 | modules.add(new JmxModule(configService)); 45 | } 46 | 47 | public static void exit(String info) { 48 | log.severe(info); 49 | Printer.disable(); 50 | System.exit(1); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/exception/AssertionException.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.exception; 4 | 5 | public class AssertionException extends Exception { 6 | private static final long serialVersionUID = -8681237240624248839L; 7 | 8 | public AssertionException(String message) { 9 | super(message); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/exception/IllegalCommandLineArumentException.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.exception; 4 | 5 | public class IllegalCommandLineArumentException extends Exception { 6 | private static final long serialVersionUID = 3530966792041074621L; 7 | 8 | public IllegalCommandLineArumentException(String message, Throwable reason) { 9 | super(message, reason); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/exception/InitializationException.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.exception; 4 | 5 | /** 6 | * Wraps an Exception during initialization. Marks the throwing object as 7 | * invalid. 8 | */ 9 | public class InitializationException extends Exception { 10 | private static final long serialVersionUID = 6446433868518776741L; 11 | 12 | public InitializationException(String message) { 13 | super(message); 14 | } 15 | 16 | public InitializationException(Throwable cause) { 17 | super(cause); 18 | } 19 | 20 | public InitializationException(String message, Throwable cause) { 21 | super(message, cause); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/exception/NotImplementedException.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.exception; 4 | 5 | public class NotImplementedException extends UnsupportedOperationException { 6 | private static final long serialVersionUID = 129273964181145272L; 7 | 8 | public NotImplementedException() { 9 | } 10 | 11 | public NotImplementedException(String message) { 12 | super(message); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/exception/UnreachableCodeException.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.exception; 4 | 5 | public class UnreachableCodeException extends RuntimeException { 6 | private static final long serialVersionUID = 9126523210158499016L; 7 | 8 | public UnreachableCodeException() { 9 | super(); 10 | } 11 | 12 | public UnreachableCodeException(String message, Throwable cause) { 13 | super(message, cause); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/model/Chart.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.model; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import lombok.AccessLevel; 9 | import lombok.Getter; 10 | import lombok.NoArgsConstructor; 11 | import lombok.Setter; 12 | 13 | @Getter 14 | @Setter 15 | @NoArgsConstructor 16 | public class Chart { 17 | /** 18 | * Controls the menu the charts will appear in. 19 | */ 20 | private String type; 21 | /** 22 | * type.id uniquely identifies the chart, this is what will be needed to add 23 | * values to the chart 24 | */ 25 | private String id; 26 | /** 27 | * is the name that will be presented to the user instead of id in type.id. 28 | * This means that only the id part of type.id is changed. When a name has 29 | * been given, the chart is index (and can be referred) as both type.id and 30 | * type.name. You can set name to '', or null, or (null) to disable it. 31 | */ 32 | private String name; 33 | /** 34 | * the text above the chart 35 | */ 36 | private String title; 37 | /** 38 | * the label of the vertical axis of the chart, all dimensions added to a 39 | * chart should have the same units of measurement 40 | */ 41 | private String units; 42 | /** 43 | * is used to group charts together (for example all eth0 charts should say: 44 | * eth0), if empty or missing, the id part of type.id will be used 45 | * 46 | * this controls the sub-menu on the dashboard 47 | */ 48 | private String family; 49 | /** 50 | * The context is giving the template of the chart. For example, if multiple 51 | * charts present the same information for a different family, they should 52 | * have the same context. 53 | * 54 | * This is used for looking up rendering information for the chart (colors, 55 | * sizes, informational texts) and also apply alarms to it. 56 | */ 57 | private String context; 58 | private ChartType chartType = ChartType.LINE; 59 | /** 60 | * the relative priority of the charts as rendered on the web page. Lower 61 | * numbers make the charts appear before the ones with higher numbers. 62 | */ 63 | private int priority = 1000; 64 | /** 65 | * overwrite the update frequency set by the server, if empty or missing, 66 | * the user configured value will be used 67 | */ 68 | private Integer updateEvery; 69 | 70 | @Setter(AccessLevel.NONE) 71 | private final List allDimension = new ArrayList<>(); 72 | 73 | public boolean hasName() { 74 | return getName() != null; 75 | } 76 | 77 | public boolean hasFamily() { 78 | return getFamily() != null; 79 | } 80 | 81 | public boolean hasContext() { 82 | return getContext() != null; 83 | } 84 | 85 | public boolean hasUpdateEvery() { 86 | return getUpdateEvery() != null; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/model/ChartType.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.model; 4 | 5 | public enum ChartType { 6 | LINE, AREA, STACKED; 7 | 8 | @Override 9 | public String toString() { 10 | return name().toLowerCase(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/model/Dimension.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.model; 4 | 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | import lombok.Setter; 8 | 9 | @Getter 10 | @Setter 11 | @NoArgsConstructor 12 | public class Dimension { 13 | /** 14 | * Identifier of this dimension (it is a text value, not numeric), this will 15 | * be needed later to add values to the dimension. 16 | */ 17 | private String id; 18 | /** 19 | * Name of the dimension as it will appear at the legend of the chart, if 20 | * empty or missing the id will be used. 21 | */ 22 | private String name; 23 | private DimensionAlgorithm algorithm = DimensionAlgorithm.ABSOLUTE; 24 | /** 25 | * Multiply the collected value. 26 | */ 27 | private int multiplier = 1; 28 | /** 29 | * Divide the collected value. 30 | */ 31 | private int divisor = 1; 32 | /** 33 | * Make this dimension hidden, it will take part in the calculations but 34 | * will not be presented in the chart. 35 | */ 36 | private boolean hidden; 37 | 38 | /** 39 | * Current collected value. Null if the last value was sent to netdata. 40 | */ 41 | private Long currentValue; 42 | 43 | public boolean hasName() { 44 | return getName() != null; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/model/DimensionAlgorithm.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.model; 4 | 5 | public enum DimensionAlgorithm { 6 | /** 7 | * the value is to drawn as-is (interpolated to second boundary), if 8 | * algorithm is empty, invalid or missing, absolute is used 9 | */ 10 | ABSOLUTE, 11 | /** 12 | * the value increases over time, the difference from the last value is 13 | * presented in the chart, the server interpolates the value and calculates 14 | * a per second figure 15 | */ 16 | INCREMENTAL, 17 | /** 18 | * the % of this value compared to the total of all dimensions 19 | */ 20 | PERCENTAGE_OF_ABSOLUTE_ROW, 21 | /** 22 | * 23 | */ 24 | PERCENTAGE_OF_INCREMENTAL_ROW; 25 | 26 | @Override 27 | public String toString() { 28 | return name().replace('_', '-').toLowerCase(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/module/Module.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.module; 4 | 5 | import org.firehol.netdata.orchestrator.Collector; 6 | 7 | public interface Module extends Collector { 8 | 9 | String getName(); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/module/jmx/JmxModule.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.module.jmx; 4 | 5 | import java.io.IOException; 6 | import java.lang.management.ManagementFactory; 7 | import java.util.*; 8 | import java.util.concurrent.CompletableFuture; 9 | import java.util.concurrent.ExecutionException; 10 | import java.util.function.Function; 11 | import java.util.logging.Logger; 12 | import java.util.stream.Collectors; 13 | 14 | import javax.management.MBeanServerConnection; 15 | import javax.management.remote.JMXConnector; 16 | import javax.management.remote.JMXConnectorFactory; 17 | import javax.management.remote.JMXServiceURL; 18 | 19 | import org.firehol.netdata.exception.InitializationException; 20 | import org.firehol.netdata.model.Chart; 21 | import org.firehol.netdata.module.Module; 22 | import org.firehol.netdata.module.jmx.configuration.JmxChartConfiguration; 23 | import org.firehol.netdata.module.jmx.configuration.JmxModuleConfiguration; 24 | import org.firehol.netdata.module.jmx.configuration.JmxServerConfiguration; 25 | import org.firehol.netdata.module.jmx.exception.JmxMBeanServerConnectionException; 26 | import org.firehol.netdata.module.jmx.exception.JmxMBeanServerQueryException; 27 | import org.firehol.netdata.module.jmx.exception.VirtualMachineConnectionException; 28 | import org.firehol.netdata.module.jmx.utils.VirtualMachineUtils; 29 | import org.firehol.netdata.orchestrator.configuration.ConfigurationService; 30 | import org.firehol.netdata.orchestrator.configuration.exception.ConfigurationSchemeInstantiationException; 31 | import org.firehol.netdata.utils.LoggingUtils; 32 | import org.firehol.netdata.utils.ResourceUtils; 33 | 34 | import com.sun.tools.attach.AttachNotSupportedException; 35 | import com.sun.tools.attach.VirtualMachine; 36 | import com.sun.tools.attach.VirtualMachineDescriptor; 37 | 38 | /** 39 | * JmxModule collects metrics from JMX Servers. 40 | * 41 | *

42 | * The module also attatches to the local JMX server to monitor the orchestrator 43 | * process. 44 | *

45 | * 46 | * @see Java 48 | * Management Extensions (JMX) Technology 49 | * 50 | */ 51 | public class JmxModule implements Module { 52 | 53 | private final Logger log = Logger.getLogger("org.firehol.netdata.module.jmx"); 54 | 55 | private final ConfigurationService configurationService; 56 | 57 | private JmxModuleConfiguration configuration; 58 | 59 | private final List allMBeanCollector = new ArrayList<>(); 60 | 61 | public JmxModule(ConfigurationService configurationService) { 62 | this.configurationService = configurationService; 63 | } 64 | 65 | @Override 66 | public Collection initialize() throws InitializationException { 67 | initConfiguration(); 68 | connectToAllServer(); 69 | return initCharts(); 70 | } 71 | 72 | private void initConfiguration() throws InitializationException { 73 | readConfiguration(); 74 | propagateCommonChartsToServerConfiguration(); 75 | } 76 | 77 | private void readConfiguration() throws InitializationException { 78 | try { 79 | configuration = configurationService.readModuleConfiguration("jmx", JmxModuleConfiguration.class); 80 | } catch (ConfigurationSchemeInstantiationException e) { 81 | throw new InitializationException("Could not read jmx module configuration", e); 82 | } 83 | } 84 | 85 | private void propagateCommonChartsToServerConfiguration() { 86 | for (JmxServerConfiguration serverConfiguartion : configuration.getJmxServers()) { 87 | if (serverConfiguartion.getCharts() == null) { 88 | serverConfiguartion.setCharts(configuration.getCommonCharts()); 89 | continue; 90 | } 91 | 92 | Map chartConfigById = chartConfigurationsById( 93 | serverConfiguartion.getCharts()); 94 | 95 | for (JmxChartConfiguration chartConfig : configuration.getCommonCharts()) { 96 | chartConfigById.putIfAbsent(chartConfig.getId(), chartConfig); 97 | } 98 | 99 | List chartConfigs = new ArrayList<>(chartConfigById.values()); 100 | serverConfiguartion.setCharts(chartConfigs); 101 | } 102 | } 103 | 104 | private Map chartConfigurationsById(List charts) { 105 | return charts.stream().collect(Collectors.toMap(JmxChartConfiguration::getId, Function.identity())); 106 | } 107 | 108 | private void connectToAllServer() { 109 | connectToConfiguredServers(); 110 | connectToLocalProcess(); 111 | 112 | if (configuration.isAutoDetectLocalVirtualMachines()) { 113 | connectToLocalServers(); 114 | } 115 | } 116 | 117 | private void connectToConfiguredServers() { 118 | for (JmxServerConfiguration serverConfiguartion : configuration.getJmxServers()) { 119 | MBeanServerCollector collector; 120 | try { 121 | collector = buildMBeanServerCollector(serverConfiguartion); 122 | } catch (JmxMBeanServerConnectionException e) { 123 | log.warning(LoggingUtils.buildMessage(e)); 124 | continue; 125 | } 126 | 127 | allMBeanCollector.add(collector); 128 | } 129 | } 130 | 131 | private MBeanServerCollector buildMBeanServerCollector(JmxServerConfiguration config) 132 | throws JmxMBeanServerConnectionException { 133 | 134 | JMXConnector connection = null; 135 | 136 | try { 137 | JMXServiceURL url = new JMXServiceURL(config.getServiceUrl()); 138 | connection = JMXConnectorFactory.connect(url); 139 | MBeanServerConnection server = connection.getMBeanServerConnection(); 140 | return new MBeanServerCollector(config, server, connection); 141 | } catch (IOException e) { 142 | if (connection != null) { 143 | ResourceUtils.close(connection); 144 | } 145 | throw new JmxMBeanServerConnectionException( 146 | "Faild to connect to JMX Server " + config.getServiceUrl() + ".", e); 147 | } 148 | } 149 | 150 | private void connectToLocalProcess() { 151 | JmxServerConfiguration localConfiguration = new JmxServerConfiguration(); 152 | localConfiguration.setCharts(configuration.getCommonCharts()); 153 | localConfiguration.setName("JavaPlugin"); 154 | 155 | MBeanServerCollector collector = new MBeanServerCollector(localConfiguration, 156 | ManagementFactory.getPlatformMBeanServer()); 157 | allMBeanCollector.add(collector); 158 | } 159 | 160 | private void connectToLocalServers() { 161 | Set allRuntimeName = getAllMBeanCollectorRuntimeName(); 162 | 163 | // List running VirtualMachines 164 | List virtualMachineDescriptors = VirtualMachine.list(); 165 | for (VirtualMachineDescriptor virtualMachineDescriptor : virtualMachineDescriptors) { 166 | // Build the MBeanServerCollector 167 | MBeanServerCollector collector; 168 | try { 169 | collector = buildMBeanServerCollector(virtualMachineDescriptor); 170 | } catch (Exception e) { 171 | log.warning(LoggingUtils.getMessageSupplier( 172 | "Could not connect to JMX agent of process with PID " + virtualMachineDescriptor.id(), e)); 173 | continue; 174 | } 175 | 176 | // Check if we already have a connection to this server... 177 | try { 178 | String runtimeName = collector.getRuntimeName(); 179 | if (allRuntimeName.contains(runtimeName)) { 180 | // ... and close the connection if true. 181 | try { 182 | collector.close(); 183 | } catch (IOException e) { 184 | log.warning(LoggingUtils.getMessageSupplier( 185 | "Could not close second connection to first configured and second auto detected JVM.", 186 | e)); 187 | } 188 | continue; 189 | } 190 | } catch (JmxMBeanServerQueryException e) { 191 | log.warning(LoggingUtils.getMessageSupplier("Could not find runtimeName", e)); 192 | } 193 | 194 | allMBeanCollector.add(collector); 195 | } 196 | } 197 | 198 | private Set getAllMBeanCollectorRuntimeName() { 199 | Set allRuntimeName = new HashSet<>(); 200 | for (MBeanServerCollector mBeanCollector : allMBeanCollector) { 201 | try { 202 | String runtimeName = mBeanCollector.getRuntimeName(); 203 | allRuntimeName.add(runtimeName); 204 | } catch (JmxMBeanServerQueryException e) { 205 | log.warning(LoggingUtils.getMessageSupplier("Could not find runtimeName", e)); 206 | } 207 | } 208 | return allRuntimeName; 209 | } 210 | 211 | private MBeanServerCollector buildMBeanServerCollector(VirtualMachineDescriptor virtualMachineDescriptor) 212 | throws VirtualMachineConnectionException, JmxMBeanServerConnectionException { 213 | VirtualMachine virtualMachine = null; 214 | 215 | try { 216 | virtualMachine = VirtualMachine.attach(virtualMachineDescriptor); 217 | 218 | JMXServiceURL serviceUrl; 219 | try { 220 | serviceUrl = VirtualMachineUtils.getJMXServiceURL(virtualMachine, true); 221 | } catch (IOException e) { 222 | throw new VirtualMachineConnectionException( 223 | "Could not get JMX ServiceUrl from Virtual Machine with PID " + virtualMachine.id(), e); 224 | 225 | } 226 | 227 | // Build configuration 228 | JmxServerConfiguration config = new JmxServerConfiguration(); 229 | config.setServiceUrl(serviceUrl.toString()); 230 | 231 | config.setName(virtualMachine.id()); 232 | if (configuration != null) { 233 | config.setCharts(configuration.getCommonCharts()); 234 | } 235 | 236 | // Build the MBeanServerCollector 237 | return buildMBeanServerCollector(config); 238 | 239 | } catch (AttachNotSupportedException | IOException e) { 240 | throw new VirtualMachineConnectionException( 241 | "Could not attatch to virtualMachine with PID " + virtualMachineDescriptor.id(), e); 242 | 243 | } finally { 244 | // Detatch from virtual machine. 245 | try { 246 | if (virtualMachine != null) { 247 | virtualMachine.detach(); 248 | } 249 | } catch (IOException e) { 250 | log.warning(LoggingUtils.getMessageSupplier( 251 | "Could not detatch from virtual machine with PID " + virtualMachine.id(), e)); 252 | } 253 | } 254 | } 255 | 256 | private Collection initCharts() { 257 | List allChart = new LinkedList<>(); 258 | Iterator mBeanCollectorIterator = allMBeanCollector.iterator(); 259 | 260 | while (mBeanCollectorIterator.hasNext()) { 261 | MBeanServerCollector mBeanCollector = mBeanCollectorIterator.next(); 262 | try { 263 | allChart.addAll(mBeanCollector.initialize()); 264 | } catch (InitializationException e) { 265 | log.warning("Could not initialize JMX orchestrator " + mBeanCollector.getMBeanServer().toString()); 266 | ResourceUtils.close(mBeanCollector); 267 | mBeanCollectorIterator.remove(); 268 | } 269 | } 270 | 271 | return allChart; 272 | } 273 | 274 | public void cleanup() { 275 | try { 276 | CompletableFuture 277 | .allOf(allMBeanCollector.stream().map(ResourceUtils::close).toArray(CompletableFuture[]::new)) 278 | .get(); 279 | } catch (InterruptedException | ExecutionException e) { 280 | log.fine("Could not close connection to at least one JMX Server"); 281 | } 282 | 283 | } 284 | 285 | @Override 286 | public Collection collectValues() { 287 | return allMBeanCollector.stream().map(MBeanServerCollector::collectValues).flatMap(Collection::stream).collect( 288 | Collectors.toList()); 289 | } 290 | 291 | @Override 292 | public String getName() { 293 | return "jmx"; 294 | } 295 | 296 | } 297 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/module/jmx/MBeanServerCollector.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.module.jmx; 4 | 5 | import java.io.Closeable; 6 | import java.io.IOException; 7 | import java.util.*; 8 | import java.util.logging.Logger; 9 | 10 | import javax.management.MBeanServerConnection; 11 | import javax.management.MalformedObjectNameException; 12 | import javax.management.ObjectName; 13 | import javax.management.remote.JMXConnector; 14 | 15 | import org.firehol.netdata.exception.InitializationException; 16 | import org.firehol.netdata.exception.UnreachableCodeException; 17 | import org.firehol.netdata.model.Chart; 18 | import org.firehol.netdata.model.Dimension; 19 | import org.firehol.netdata.module.jmx.configuration.JmxChartConfiguration; 20 | import org.firehol.netdata.module.jmx.configuration.JmxDimensionConfiguration; 21 | import org.firehol.netdata.module.jmx.configuration.JmxServerConfiguration; 22 | import org.firehol.netdata.module.jmx.exception.JmxMBeanServerQueryException; 23 | import org.firehol.netdata.module.jmx.query.MBeanQuery; 24 | import org.firehol.netdata.module.jmx.utils.MBeanServerUtils; 25 | import org.firehol.netdata.orchestrator.Collector; 26 | import org.firehol.netdata.utils.LoggingUtils; 27 | 28 | import lombok.Getter; 29 | 30 | /** 31 | * Collects metrics of one MBeanServerConnection. 32 | * 33 | * @since 1.0.0 34 | * @author Simon Nagl 35 | * 36 | */ 37 | public class MBeanServerCollector implements Collector, Closeable { 38 | 39 | private final Logger log = Logger.getLogger("org.firehol.netdata.module.jmx"); 40 | 41 | private JmxServerConfiguration serverConfiguration; 42 | 43 | @Getter 44 | private final MBeanServerConnection mBeanServer; 45 | 46 | private JMXConnector jmxConnector; 47 | 48 | private List allMBeanQuery = new LinkedList<>(); 49 | 50 | private List allChart = new LinkedList<>(); 51 | 52 | /** 53 | * Creates an MBeanServerCollector. 54 | * 55 | *

56 | * Warning: Only use this when you do not want to close the 57 | * underlying JMXConnetor when closing the generated MBeanServerCollector. 58 | *

59 | * 60 | * @param configuration 61 | * Configuration to apply to this collector. 62 | * @param mBeanServer 63 | * to query 64 | */ 65 | public MBeanServerCollector(JmxServerConfiguration configuration, MBeanServerConnection mBeanServer) { 66 | this.serverConfiguration = configuration; 67 | this.mBeanServer = mBeanServer; 68 | } 69 | 70 | /** 71 | * Creates an MBeanServerCollector. 72 | * 73 | *

74 | * Calling {@link #close()}} on the resulting {@code MBeanServerCollector} 75 | * closes {@code jmxConnector} too. 76 | *

77 | * 78 | * @param configuration 79 | * @param mBeanServer 80 | * @param jmxConnector 81 | */ 82 | public MBeanServerCollector(JmxServerConfiguration configuration, MBeanServerConnection mBeanServer, 83 | JMXConnector jmxConnector) { 84 | this(configuration, mBeanServer); 85 | this.jmxConnector = jmxConnector; 86 | } 87 | 88 | /** 89 | *

90 | * Queries MBean {@code java.lang:type=Runtime} for attribute {@code Name}. 91 | *

92 | * 93 | *

94 | * This attribute can be used as a unique identifier of the underlying JMX 95 | * agent 96 | *

97 | * 98 | * @return the name representing the Java virtual machine of the queried 99 | * server.. 100 | * @throws JmxMBeanServerQueryException 101 | * on errors. 102 | */ 103 | public String getRuntimeName() throws JmxMBeanServerQueryException { 104 | 105 | // Final names. 106 | final String runtimeMBeanName = "java.lang:type=Runtime"; 107 | final String runtimeNameAttributeName = "Name"; 108 | 109 | // Build object name. 110 | ObjectName runtimeObjectName; 111 | try { 112 | runtimeObjectName = ObjectName.getInstance("java.lang:type=Runtime"); 113 | } catch (MalformedObjectNameException e) { 114 | throw new UnreachableCodeException("Can not be reached because argument of getInstance() is static.", e); 115 | } 116 | 117 | // Query mBeanServer. 118 | Object attribute = getAttribute(runtimeObjectName, "Name"); 119 | if (attribute instanceof String) { 120 | return (String) attribute; 121 | } 122 | 123 | // Error handling 124 | throw new JmxMBeanServerQueryException(LoggingUtils.buildMessage("Expected attribute '", 125 | runtimeNameAttributeName, " 'of MBean '", runtimeMBeanName, 126 | "' to return a string. Instead it returned a '", attribute.getClass().getSimpleName(), "'.")); 127 | 128 | } 129 | 130 | public Collection initialize() throws InitializationException { 131 | 132 | // Step 1 133 | // Check commonChart configuration 134 | for (JmxChartConfiguration chartConfig : serverConfiguration.getCharts()) { 135 | Chart chart = initializeChart(chartConfig); 136 | 137 | // Check if the mBeanServer has the desired sources. 138 | for (JmxDimensionConfiguration dimensionConfig : chartConfig.getDimensions()) { 139 | 140 | final ObjectName objectName; 141 | final MBeanQuery mBeanQuery; 142 | 143 | try { 144 | try { 145 | objectName = ObjectName.getInstance(dimensionConfig.getFrom()); 146 | } catch (MalformedObjectNameException e) { 147 | throw new JmxMBeanServerQueryException( 148 | "'" + dimensionConfig.getFrom() + "' is no valid JMX ObjectName", e); 149 | } catch (NullPointerException e) { 150 | throw new JmxMBeanServerQueryException("'' is no valid JMX OBjectName", e); 151 | } 152 | 153 | // Initialize Query Info if needed 154 | mBeanQuery = getMBeanQueryForName(objectName, dimensionConfig.getValue()) 155 | .orElse(addNewMBeanQuery(objectName, dimensionConfig.getValue())); 156 | } catch (JmxMBeanServerQueryException e) { 157 | log.warning(LoggingUtils.buildMessage("Could not query one dimension. Skipping...", e)); 158 | continue; 159 | } 160 | 161 | // Initialize Dimension 162 | final Dimension dimension = initializeDimension(chartConfig, dimensionConfig); 163 | 164 | try { 165 | mBeanQuery.addDimension(dimension, dimensionConfig.getValue()); 166 | } catch (JmxMBeanServerQueryException e) { 167 | log.warning(LoggingUtils 168 | .buildMessage("Could not query dimension " + dimension.getName() + ". Skippint...", e)); 169 | continue; 170 | } 171 | 172 | chart.getAllDimension().add(dimension); 173 | } 174 | 175 | allChart.add(chart); 176 | } 177 | 178 | return allChart; 179 | } 180 | 181 | private Optional getMBeanQueryForName(final ObjectName objectName, final String attribute) { 182 | return allMBeanQuery.stream() 183 | .filter(mBeanQuery -> mBeanQuery.getName().equals(objectName) 184 | && mBeanQuery.getAttribute().equals(attribute)) 185 | .findAny(); 186 | } 187 | 188 | Chart initializeChart(JmxChartConfiguration config) { 189 | Chart chart = new Chart(); 190 | 191 | chart.setType("jmx_" + serverConfiguration.getName()); 192 | chart.setFamily(config.getFamily()); 193 | chart.setId(config.getId()); 194 | chart.setTitle(config.getTitle()); 195 | chart.setUnits(config.getUnits()); 196 | chart.setContext(serverConfiguration.getName()); 197 | chart.setChartType(config.getChartType()); 198 | if (config.getPriority() != null) { 199 | chart.setPriority(config.getPriority()); 200 | } 201 | 202 | return chart; 203 | } 204 | 205 | Dimension initializeDimension(JmxChartConfiguration chartConfig, JmxDimensionConfiguration dimensionConfig) { 206 | Dimension dimension = new Dimension(); 207 | dimension.setId(dimensionConfig.getName()); 208 | dimension.setName(dimensionConfig.getName()); 209 | dimension.setAlgorithm(chartConfig.getDimensionAlgorithm()); 210 | dimension.setMultiplier(dimensionConfig.getMultiplier()); 211 | dimension.setDivisor(dimensionConfig.getDivisor()); 212 | 213 | return dimension; 214 | } 215 | 216 | private MBeanQuery addNewMBeanQuery(final ObjectName objectName, final String valueName) 217 | throws JmxMBeanServerQueryException { 218 | final MBeanQuery query = MBeanQuery.newInstance(mBeanServer, objectName, valueName); 219 | allMBeanQuery.add(query); 220 | return query; 221 | } 222 | 223 | Object getAttribute(ObjectName name, String attribute) throws JmxMBeanServerQueryException { 224 | return MBeanServerUtils.getAttribute(mBeanServer, name, attribute); 225 | } 226 | 227 | public Collection collectValues() { 228 | // Query all attributes and fill charts. 229 | Iterator queryIterator = allMBeanQuery.iterator(); 230 | 231 | while (queryIterator.hasNext()) { 232 | final MBeanQuery query = queryIterator.next(); 233 | 234 | try { 235 | query.query(); 236 | } catch (JmxMBeanServerQueryException e) { 237 | // Stop collecting this value. 238 | log.warning(LoggingUtils.buildMessage( 239 | "Stop collection value '" + query.getAttribute() + "' of '" + query.getName() + "'.", e)); 240 | queryIterator.remove(); 241 | } 242 | } 243 | 244 | // Return Updated Charts. 245 | return allChart; 246 | } 247 | 248 | /* 249 | * (non-Javadoc) 250 | * 251 | * @see java.io.Closeable#close() 252 | */ 253 | @Override 254 | public void close() throws IOException { 255 | if (this.jmxConnector != null) { 256 | this.jmxConnector.close(); 257 | } 258 | } 259 | 260 | @Override 261 | public void cleanup() { 262 | try { 263 | close(); 264 | } catch (IOException e) { 265 | log.warning(LoggingUtils.buildMessage("Could not cleanup MBeanServerCollector.", e)); 266 | } 267 | } 268 | } 269 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/module/jmx/configuration/JmxChartConfiguration.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.module.jmx.configuration; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import org.firehol.netdata.model.ChartType; 9 | import org.firehol.netdata.model.DimensionAlgorithm; 10 | import org.firehol.netdata.module.jmx.JmxModule; 11 | 12 | import lombok.Getter; 13 | import lombok.Setter; 14 | 15 | /** 16 | * Configuration scheme of a chart created by the {@link JmxModule}. 17 | */ 18 | @Getter 19 | @Setter 20 | public class JmxChartConfiguration { 21 | 22 | /** 23 | * uniquely identifies the chart 24 | */ 25 | private String id; 26 | /** 27 | * the text above the chart 28 | */ 29 | private String title; 30 | /** 31 | * the label of the vertical axis of the chart, all dimensions added to a 32 | * chart should have the same units of measurement 33 | */ 34 | private String units; 35 | /** 36 | * the sub-menu on the dashboard 37 | */ 38 | private String family; 39 | 40 | /** 41 | * the relative priority of the charts as rendered on the web page. Lower 42 | * numbers make the charts appear before the ones with higher numbers. 43 | */ 44 | private Integer priority; 45 | 46 | /** 47 | * the chart type used on the web page. 48 | */ 49 | private ChartType chartType = ChartType.LINE; 50 | /** 51 | * how to interpret collected values. 52 | */ 53 | private DimensionAlgorithm dimensionAlgorithm = DimensionAlgorithm.ABSOLUTE; 54 | 55 | /** 56 | * dimensions this chart displays. 57 | */ 58 | private List dimensions = new ArrayList<>(); 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/module/jmx/configuration/JmxDimensionConfiguration.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.module.jmx.configuration; 4 | 5 | import org.firehol.netdata.module.jmx.JmxModule; 6 | 7 | import lombok.Getter; 8 | import lombok.Setter; 9 | 10 | /** 11 | * Configuration scheme of a dimension of a chart created by the 12 | * {@link JmxModule}. 13 | */ 14 | @Getter 15 | @Setter 16 | public class JmxDimensionConfiguration { 17 | 18 | /** 19 | * Jmx Object Name. 20 | */ 21 | private String from; 22 | 23 | /** 24 | * JmxBean property. 25 | * 26 | * To access a property of a CompositeData use 27 | * property.compositeDataKey 28 | */ 29 | private String value; 30 | 31 | /** 32 | * Multiply the collected value before displaying it. 33 | */ 34 | private int multiplier = 1; 35 | /** 36 | * Divide the collected value before displaying it. 37 | */ 38 | private int divisor = 1; 39 | 40 | /** 41 | * Name displayed to user. 42 | */ 43 | private String name; 44 | 45 | /** 46 | * If true the value get's collected but not displayed. 47 | */ 48 | private boolean hidden = false; 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/module/jmx/configuration/JmxModuleConfiguration.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.module.jmx.configuration; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | import org.firehol.netdata.module.jmx.JmxModule; 9 | 10 | import lombok.Getter; 11 | import lombok.Setter; 12 | 13 | /** 14 | * Configuration scheme to configure {@link JmxModule} 15 | * 16 | * @since 1.0.0 17 | * @author Simon Nagl 18 | */ 19 | @Getter 20 | @Setter 21 | public class JmxModuleConfiguration { 22 | 23 | /** 24 | * If true auto detect and monitor running local virtual machines. 25 | */ 26 | private boolean autoDetectLocalVirtualMachines = true; 27 | 28 | /** 29 | * A list of JMX servers to monitor. 30 | */ 31 | private List jmxServers = new ArrayList<>(); 32 | 33 | /** 34 | * A list of chart configurations. 35 | * 36 | *

37 | * Every monitored JMX Servers tries to monitor each chart in this list. If 38 | * a JMX Server does not have the required M(X)Beans we won't try adding it 39 | * over and over again. 40 | *

41 | */ 42 | private List commonCharts = new ArrayList<>(); 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/module/jmx/configuration/JmxServerConfiguration.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.module.jmx.configuration; 4 | 5 | import java.util.List; 6 | 7 | import com.fasterxml.jackson.annotation.JsonIgnore; 8 | 9 | import lombok.Getter; 10 | import lombok.Setter; 11 | 12 | /** 13 | * Configuration scheme to configure JMX agents to monitor. 14 | */ 15 | @Getter 16 | @Setter 17 | public class JmxServerConfiguration { 18 | /** 19 | * JMX Service URL used to connect to the JVM. 20 | * 21 | *
{@code service:jmx:rmi://[host[:port]][urlPath]} 22 | *
23 | * 24 | * @see Oracle 26 | * Developer's Guide for JMX Clients 27 | * 28 | */ 29 | private String serviceUrl; 30 | 31 | /** 32 | * Name displayed at the dashboard. 33 | */ 34 | private String name; 35 | 36 | @JsonIgnore 37 | // This property is not part of the configuration scheme. 38 | // This is a technical property used by the module. 39 | private List charts; 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/module/jmx/exception/JmxMBeanServerConnectionException.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.module.jmx.exception; 4 | 5 | public class JmxMBeanServerConnectionException extends JmxModuleException { 6 | private static final long serialVersionUID = -6153969842214336278L; 7 | 8 | public JmxMBeanServerConnectionException(String message, Throwable cause) { 9 | super(message, cause); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/module/jmx/exception/JmxMBeanServerQueryException.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.module.jmx.exception; 4 | 5 | public class JmxMBeanServerQueryException extends JmxModuleException { 6 | private static final long serialVersionUID = 5480135001434254831L; 7 | 8 | public JmxMBeanServerQueryException(String message, Throwable cause) { 9 | super(message, cause); 10 | } 11 | 12 | public JmxMBeanServerQueryException(String message) { 13 | super(message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/module/jmx/exception/JmxModuleException.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.module.jmx.exception; 4 | 5 | public class JmxModuleException extends Exception { 6 | private static final long serialVersionUID = -9084555240752421197L; 7 | 8 | public JmxModuleException(String message, Throwable cause) { 9 | super(message, cause); 10 | } 11 | 12 | public JmxModuleException(String message) { 13 | super(message); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/module/jmx/exception/VirtualMachineConnectionException.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.module.jmx.exception; 4 | 5 | public class VirtualMachineConnectionException extends JmxModuleException { 6 | private static final long serialVersionUID = -4214747861980964583L; 7 | 8 | public VirtualMachineConnectionException(String message) { 9 | super(message); 10 | } 11 | 12 | public VirtualMachineConnectionException(String message, Throwable reason) { 13 | super(message, reason); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/module/jmx/query/MBeanCompositeDataQuery.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.module.jmx.query; 4 | 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.TreeMap; 8 | import java.util.stream.Collectors; 9 | 10 | import javax.management.MBeanServerConnection; 11 | import javax.management.ObjectName; 12 | import javax.management.openmbean.CompositeData; 13 | 14 | import org.firehol.netdata.model.Dimension; 15 | import org.firehol.netdata.module.jmx.exception.JmxMBeanServerQueryException; 16 | import org.firehol.netdata.module.jmx.utils.MBeanServerUtils; 17 | 18 | class MBeanCompositeDataQuery extends MBeanQuery { 19 | 20 | private final Map allDimensionByKey = new TreeMap<>(); 21 | 22 | MBeanCompositeDataQuery(final MBeanServerConnection mBeanServer, final ObjectName name, final String attribute) { 23 | super(mBeanServer, name, attribute); 24 | } 25 | 26 | @Override 27 | public void addDimension(Dimension dimension, final String attribute) throws JmxMBeanServerQueryException { 28 | final String[] splitString = attribute.split("\\."); 29 | if (splitString.length != 2) { 30 | throw new IllegalArgumentException( 31 | String.format("Expected attribute to be in format '.', but was '%s'", attribute)); 32 | } 33 | if (!this.getAttribute().equals(splitString[0])) { 34 | throw new IllegalArgumentException(String.format("Expected attribute to start with '%s', but was '%s'", 35 | this.getAttribute(), attribute)); 36 | } 37 | 38 | final CompositeData queryResult = queryServer(); 39 | final Object result = queryResult.get(splitString[1]); 40 | 41 | allDimensionByKey.computeIfAbsent(splitString[1], k -> MBeanValueStore.newInstance(result)) 42 | .addDimension(dimension); 43 | } 44 | 45 | @Override 46 | public List getDimensions() { 47 | return allDimensionByKey.values().stream().flatMap(MBeanValueStore::streamAllDimension).collect( 48 | Collectors.toList()); 49 | } 50 | 51 | @Override 52 | public void query() throws JmxMBeanServerQueryException { 53 | final CompositeData compositeData = queryServer(); 54 | 55 | allDimensionByKey.forEach((key, allDimension) -> { 56 | final Object result = compositeData.get(key); 57 | allDimension.updateValue(result); 58 | }); 59 | } 60 | 61 | private CompositeData queryServer() throws JmxMBeanServerQueryException { 62 | return (CompositeData) MBeanServerUtils.getAttribute(getMBeanServer(), this.getName(), this.getAttribute()); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/module/jmx/query/MBeanDoubleStore.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.module.jmx.query; 4 | 5 | import org.firehol.netdata.model.Dimension; 6 | 7 | public class MBeanDoubleStore extends MBeanValueStore { 8 | private static final int LONG_RESOLUTION = 100; 9 | 10 | @Override 11 | public void addDimension(final Dimension dimension) { 12 | dimension.setDivisor(dimension.getDivisor() * LONG_RESOLUTION); 13 | super.addDimension(dimension); 14 | } 15 | 16 | @Override 17 | long toLong(final Object value) { 18 | return (long) ((double) value * LONG_RESOLUTION); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/module/jmx/query/MBeanIntegerStore.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.module.jmx.query; 4 | 5 | public class MBeanIntegerStore extends MBeanValueStore { 6 | @Override 7 | long toLong(final Object value) { 8 | return ((Integer) value).longValue(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/module/jmx/query/MBeanLongStore.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.module.jmx.query; 4 | 5 | public class MBeanLongStore extends MBeanValueStore { 6 | 7 | @Override 8 | long toLong(final Object value) { 9 | return (long) value; 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/module/jmx/query/MBeanQuery.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.module.jmx.query; 4 | 5 | import java.util.List; 6 | 7 | import javax.management.MBeanServerConnection; 8 | import javax.management.ObjectName; 9 | import javax.management.openmbean.CompositeData; 10 | 11 | import org.firehol.netdata.model.Dimension; 12 | import org.firehol.netdata.module.jmx.exception.JmxMBeanServerQueryException; 13 | import org.firehol.netdata.module.jmx.utils.MBeanServerUtils; 14 | 15 | import lombok.Getter; 16 | 17 | /** 18 | * MBeanQuery is able to query one attribute of a MBeanServer and update the 19 | * currentValue of added Dimensions. 20 | * 21 | *

22 | * Supported attributes are 23 | * 24 | *

    25 | *
  • Simple attributes which return long, int or double
  • 26 | *
  • Composite attributes which may return more than one value at once. For 27 | * this cases you have to add the attribute in format 28 | * {@code .}
  • 29 | *
30 | *

31 | */ 32 | @Getter 33 | public abstract class MBeanQuery { 34 | private final ObjectName name; 35 | 36 | private final String attribute; 37 | 38 | private final MBeanServerConnection mBeanServer; 39 | 40 | MBeanQuery(final MBeanServerConnection mBeanServer, final ObjectName name, final String attribute) { 41 | this.mBeanServer = mBeanServer; 42 | this.name = name; 43 | this.attribute = attribute; 44 | } 45 | 46 | public static MBeanQuery newInstance(final MBeanServerConnection mBeanServer, final ObjectName mBeanName, 47 | final String attribute) throws JmxMBeanServerQueryException { 48 | final String mBeanAttribute = attribute.split("\\.", 2)[0]; 49 | final Object queryResult = MBeanServerUtils.getAttribute(mBeanServer, mBeanName, mBeanAttribute); 50 | 51 | if (CompositeData.class.isAssignableFrom(queryResult.getClass())) { 52 | return new MBeanCompositeDataQuery(mBeanServer, mBeanName, mBeanAttribute); 53 | } 54 | 55 | return new MBeanSimpleQuery(mBeanServer, mBeanName, mBeanAttribute, MBeanValueStore.newInstance(queryResult)); 56 | } 57 | 58 | public abstract void addDimension(Dimension dimension, String attribute) throws JmxMBeanServerQueryException; 59 | 60 | public abstract void query() throws JmxMBeanServerQueryException; 61 | 62 | public abstract List getDimensions(); 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/module/jmx/query/MBeanSimpleQuery.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.module.jmx.query; 4 | 5 | import java.util.List; 6 | 7 | import javax.management.MBeanServerConnection; 8 | import javax.management.ObjectName; 9 | 10 | import org.firehol.netdata.model.Dimension; 11 | import org.firehol.netdata.module.jmx.exception.JmxMBeanServerQueryException; 12 | import org.firehol.netdata.module.jmx.utils.MBeanServerUtils; 13 | 14 | import lombok.Getter; 15 | 16 | /** 17 | * A MBeanQuery is responsible to query a attribute of a MBean and place it's 18 | * value into {@link Dimension} 19 | */ 20 | @Getter 21 | public class MBeanSimpleQuery extends MBeanQuery { 22 | 23 | private final MBeanValueStore valueStore; 24 | 25 | MBeanSimpleQuery(final MBeanServerConnection mBeanServer, final ObjectName name, final String attribute, 26 | final MBeanValueStore valueStore) { 27 | super(mBeanServer, name, attribute); 28 | this.valueStore = valueStore; 29 | } 30 | 31 | public List getDimensions() { 32 | return valueStore.getAllDimension(); 33 | } 34 | 35 | /** 36 | * Add a dimension which value should be updated by this query. 37 | *

38 | * Attribute must match {@link #getAttribute()} or be more precise. 39 | * 40 | * @param dimension 41 | * to add to the list of dimensions 42 | * @param attribute 43 | * of the MBean which should be queried 44 | */ 45 | @Override 46 | public void addDimension(Dimension dimension, final String attribute) { 47 | if (!this.getAttribute().equals(attribute)) { 48 | throw new IllegalArgumentException( 49 | String.format("attribute '%s' must match this.attribute '%s'", attribute, this.getAttribute())); 50 | } 51 | 52 | this.valueStore.addDimension(dimension); 53 | } 54 | 55 | @Override 56 | public void query() throws JmxMBeanServerQueryException { 57 | Object result = MBeanServerUtils.getAttribute(getMBeanServer(), this.getName(), this.getAttribute()); 58 | valueStore.updateValue(result); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/module/jmx/query/MBeanValueStore.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.module.jmx.query; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.stream.Stream; 8 | 9 | import org.firehol.netdata.model.Dimension; 10 | 11 | public abstract class MBeanValueStore { 12 | 13 | final List allDimension = new ArrayList<>(1); 14 | 15 | MBeanValueStore() { 16 | } 17 | 18 | public static MBeanValueStore newInstance(Object valueToHandle) { 19 | if (valueToHandle instanceof Double) { 20 | return new MBeanDoubleStore(); 21 | } else if (valueToHandle instanceof Integer) { 22 | return new MBeanIntegerStore(); 23 | } 24 | return new MBeanLongStore(); 25 | } 26 | 27 | public void updateValue(final Object value) { 28 | final long castResult = toLong(value); 29 | allDimension.forEach(dimension -> dimension.setCurrentValue(castResult)); 30 | } 31 | 32 | abstract long toLong(final Object value); 33 | 34 | public void addDimension(final Dimension dimension) { 35 | allDimension.add(dimension); 36 | } 37 | 38 | public Stream streamAllDimension() { 39 | return allDimension.stream(); 40 | } 41 | 42 | public List getAllDimension() { 43 | return allDimension; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/module/jmx/utils/MBeanServerUtils.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.module.jmx.utils; 4 | 5 | import java.io.IOException; 6 | 7 | import javax.management.*; 8 | 9 | import org.firehol.netdata.module.jmx.exception.JmxMBeanServerQueryException; 10 | 11 | public final class MBeanServerUtils { 12 | 13 | private MBeanServerUtils() { 14 | } 15 | 16 | public static Object getAttribute(MBeanServerConnection mBeanServer, ObjectName name, String attribute) 17 | throws JmxMBeanServerQueryException { 18 | try { 19 | return mBeanServer.getAttribute(name, attribute); 20 | } catch (AttributeNotFoundException | InstanceNotFoundException | MBeanException | ReflectionException 21 | | IOException e) { 22 | throw new JmxMBeanServerQueryException( 23 | "Could not query attribute '" + attribute + "' of MBean '" + name + "'", e); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/module/jmx/utils/VirtualMachineUtils.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.module.jmx.utils; 4 | 5 | import java.io.IOException; 6 | import java.util.logging.Logger; 7 | 8 | import javax.management.remote.JMXServiceURL; 9 | 10 | import org.firehol.netdata.utils.LoggingUtils; 11 | 12 | import com.sun.tools.attach.VirtualMachine; 13 | 14 | /** 15 | * Common methods for operation on a {@link VirtualMachine}. 16 | * 17 | * There are no instances of this class. 18 | * 19 | * @since 1.0.0 20 | * @author Simon Nagl 21 | */ 22 | public final class VirtualMachineUtils { 23 | 24 | private static final String SERVICE_URL_AGENT_PROPERTY_KEY = "com.sun.management.jmxremote.localConnectorAddress"; 25 | 26 | private static final Logger log = Logger.getLogger("org.firehol.netdata.module.jmx"); 27 | 28 | private VirtualMachineUtils() { 29 | } 30 | 31 | /** 32 | * Get the JMX ServiceUrl of a virtualMachine. 33 | * 34 | * If {@code startJMXAgent} is true, try to start the jmxAgent if it is not 35 | * started. 36 | * 37 | * @param virtualMachine 38 | * Attached virtual machine to query. 39 | * @param startJMXAgent 40 | * If true, try to start the jmxAgent if it is not started. 41 | * @return a JMX ServiceUrl which can be used to connect to the 42 | * VirtualMachine or null if it could not be found. 43 | * @throws IOException 44 | * Thrown when an IOException occurs while communicating with 45 | * the virtualMachine. 46 | */ 47 | public static JMXServiceURL getJMXServiceURL(VirtualMachine virtualMachine, boolean startJMXAgent) 48 | throws IOException { 49 | JMXServiceURL serviceUrl = getJMXServiceURL(virtualMachine); 50 | 51 | if (!startJMXAgent) { 52 | return serviceUrl; 53 | } 54 | 55 | if (serviceUrl != null) { 56 | return serviceUrl; 57 | } 58 | 59 | virtualMachine.startLocalManagementAgent(); 60 | return getJMXServiceURL(virtualMachine); 61 | } 62 | 63 | /** 64 | * Get the JMX ServiceUrl of a virtualMachine. 65 | * 66 | * @param virtualMachine 67 | * Attached virtual machine to query. 68 | * @return a JMX ServiceUrl which can be used to connect to the 69 | * VirtualMachine or null if it could not be found. 70 | * @throws IOException 71 | * Thrown when an IOException occurs while communicating with 72 | * the virtualMachine. 73 | */ 74 | public static JMXServiceURL getJMXServiceURL(VirtualMachine virtualMachine) throws IOException { 75 | String serviceUrl = virtualMachine.getAgentProperties().getProperty(SERVICE_URL_AGENT_PROPERTY_KEY); 76 | 77 | if (serviceUrl == null) { 78 | return null; 79 | } 80 | 81 | try { 82 | return new JMXServiceURL(serviceUrl); 83 | } catch (Exception e) { 84 | log.fine(LoggingUtils.getMessageSupplier("Could not instantiate JMXServiceURL", e)); 85 | return null; 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/orchestrator/Collector.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.orchestrator; 4 | 5 | import java.util.Collection; 6 | 7 | import org.firehol.netdata.exception.InitializationException; 8 | import org.firehol.netdata.model.Chart; 9 | 10 | public interface Collector { 11 | 12 | Collection initialize() throws InitializationException; 13 | 14 | Collection collectValues(); 15 | 16 | void cleanup(); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/orchestrator/Orchestrator.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.orchestrator; 4 | 5 | import java.util.Collection; 6 | import java.util.Iterator; 7 | import java.util.LinkedList; 8 | import java.util.List; 9 | import java.util.concurrent.TimeUnit; 10 | import java.util.logging.Logger; 11 | import java.util.stream.Collectors; 12 | 13 | import org.firehol.netdata.Main; 14 | import org.firehol.netdata.exception.InitializationException; 15 | import org.firehol.netdata.model.Chart; 16 | import org.firehol.netdata.module.Module; 17 | import org.firehol.netdata.utils.AlignToTimeIntervalService; 18 | import org.firehol.netdata.utils.LoggingUtils; 19 | 20 | public class Orchestrator implements Collector { 21 | private static final Logger log = Logger.getLogger("org.firehol.netdata.orchestrator"); 22 | 23 | private final int updateEverySecond; 24 | 25 | private final List modules; 26 | 27 | public Orchestrator(int updateEveryInSeconds, List modules) { 28 | this.updateEverySecond = updateEveryInSeconds; 29 | this.modules = modules; 30 | } 31 | 32 | public void start() { 33 | initializeModules(); 34 | runMainLoop(); 35 | } 36 | 37 | private void initializeModules() { 38 | try { 39 | Collection chartsToInitialize = initialize(); 40 | for (Chart chart : chartsToInitialize) { 41 | Printer.initializeChart(chart); 42 | } 43 | } catch (Exception e) { 44 | Main.exit(LoggingUtils.buildMessage("Could not initialize. Disabling Java Orchestrator.", e)); 45 | } 46 | 47 | } 48 | 49 | @Override 50 | public Collection initialize() throws InitializationException { 51 | Collection chartsToInitialize = new LinkedList<>(); 52 | 53 | Iterator moduleIterator = modules.iterator(); 54 | while (moduleIterator.hasNext()) { 55 | Module module = moduleIterator.next(); 56 | try { 57 | chartsToInitialize.addAll(module.initialize()); 58 | } catch (InitializationException e) { 59 | moduleIterator.remove(); 60 | log.warning(LoggingUtils.getMessageSupplier("Could not initialize module " + module.getName(), e)); 61 | } 62 | } 63 | 64 | if (chartsToInitialize.size() < 1) { 65 | throw new InitializationException("No Charts to initialize."); 66 | } 67 | 68 | return chartsToInitialize; 69 | } 70 | 71 | private void runMainLoop() { 72 | AlignToTimeIntervalService timeService = new AlignToTimeIntervalService(updateEverySecond, TimeUnit.SECONDS); 73 | while (true) { 74 | timeService.alignToNextInterval(); 75 | 76 | collectValues().stream().forEach(Printer::collect); 77 | } 78 | } 79 | 80 | @Override 81 | public Collection collectValues() { 82 | return modules.stream().map(Module::collectValues).flatMap(Collection::stream).collect(Collectors.toList()); 83 | } 84 | 85 | @Override 86 | public void cleanup() { 87 | for (Module module : modules) { 88 | module.cleanup(); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/orchestrator/Printer.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.orchestrator; 4 | 5 | import org.firehol.netdata.model.Chart; 6 | import org.firehol.netdata.model.Dimension; 7 | 8 | /** 9 | * The class {@code Printer} contains methods to communicate with the caller. 10 | * 11 | * The format of the communication is defined here 13 | * 14 | * @author Simon Nagl 15 | * @since 1.0.0 16 | */ 17 | public final class Printer { 18 | 19 | private Printer() { 20 | } 21 | 22 | private static void print(final String command) { 23 | System.out.println(command); 24 | } 25 | 26 | public static void initializeChart(final Chart chart) { 27 | StringBuilder sb = new StringBuilder(); 28 | appendInitializeChart(sb, chart); 29 | 30 | for (Dimension dimension : chart.getAllDimension()) { 31 | sb.append(System.lineSeparator()); 32 | appendInitializeDimension(sb, dimension); 33 | } 34 | 35 | print(sb.toString()); 36 | } 37 | 38 | protected static void appendInitializeChart(StringBuilder sb, final Chart chart) { 39 | // Start new chart 40 | sb.append("CHART "); 41 | // Append identifier 42 | sb.append(chart.getType()); 43 | sb.append('.'); 44 | sb.append(chart.getId()); 45 | sb.append(' '); 46 | // Append name 47 | if (chart.hasName()) { 48 | sb.append(chart.getName()); 49 | } else { 50 | sb.append("null"); 51 | } 52 | sb.append(" '"); 53 | // Append title 54 | sb.append(chart.getTitle()); 55 | sb.append("' "); 56 | // Append untis 57 | sb.append(chart.getUnits()); 58 | sb.append(' '); 59 | // Append familiy 60 | if (chart.hasFamily()) { 61 | sb.append(chart.getFamily()); 62 | } else { 63 | sb.append(chart.getId()); 64 | } 65 | sb.append(' '); 66 | // Append context 67 | if (chart.hasContext()) { 68 | sb.append(chart.getContext()); 69 | } else { 70 | sb.append(chart.getId()); 71 | } 72 | sb.append(' '); 73 | // Append chart type 74 | sb.append(chart.getChartType()); 75 | sb.append(' '); 76 | // Append priority 77 | sb.append(chart.getPriority()); 78 | // Append update_every 79 | if (chart.hasUpdateEvery()) { 80 | sb.append(' '); 81 | sb.append(chart.getUpdateEvery()); 82 | } 83 | } 84 | 85 | protected static void appendInitializeDimension(StringBuilder sb, final Dimension dimension) { 86 | // Start new dimension 87 | sb.append("DIMENSION "); 88 | // Append ID 89 | sb.append(dimension.getId()); 90 | sb.append(' '); 91 | // Append name 92 | if (dimension.hasName()) { 93 | sb.append(dimension.getName()); 94 | } else { 95 | sb.append(dimension.getId()); 96 | } 97 | sb.append(' '); 98 | // Append algorithm 99 | sb.append(dimension.getAlgorithm()); 100 | sb.append(' '); 101 | // Append multiplier 102 | sb.append(dimension.getMultiplier()); 103 | sb.append(' '); 104 | // Append divisor 105 | sb.append(dimension.getDivisor()); 106 | // Append hidden 107 | if (dimension.isHidden()) { 108 | sb.append(" hidden"); 109 | } 110 | } 111 | 112 | public static void collect(final Chart chart) { 113 | StringBuilder sb = new StringBuilder(); 114 | appendCollectBegin(sb, chart); 115 | 116 | for (Dimension dim : chart.getAllDimension()) { 117 | if (dim.getCurrentValue() != null) { 118 | sb.append(System.lineSeparator()); 119 | appendCollectDimension(sb, dim); 120 | dim.setCurrentValue(null); 121 | } 122 | } 123 | 124 | sb.append(System.lineSeparator()); 125 | appendCollectEnd(sb); 126 | 127 | print(sb.toString()); 128 | } 129 | 130 | protected static void appendCollectBegin(StringBuilder sb, Chart chart) { 131 | // TODO Add microseconds to the output. 132 | sb.append("BEGIN "); 133 | sb.append(chart.getType()); 134 | sb.append('.'); 135 | sb.append(chart.getId()); 136 | } 137 | 138 | protected static void appendCollectDimension(StringBuilder sb, Dimension dim) { 139 | sb.append("SET "); 140 | sb.append(dim.getId()); 141 | sb.append(" = "); 142 | sb.append(dim.getCurrentValue()); 143 | } 144 | 145 | protected static void appendCollectEnd(StringBuilder sb) { 146 | sb.append("END"); 147 | } 148 | 149 | /** 150 | * Tell the caller to disable the orchestrator. This will prevent it from 151 | * restarting the orchestrator. 152 | */ 153 | public static void disable() { 154 | print("DISABLE"); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/orchestrator/configuration/ConfigurationService.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.orchestrator.configuration; 4 | 5 | import java.io.File; 6 | import java.nio.file.Path; 7 | import java.util.logging.Logger; 8 | 9 | import org.firehol.netdata.Main; 10 | import org.firehol.netdata.orchestrator.configuration.exception.ConfigurationSchemeInstantiationException; 11 | import org.firehol.netdata.orchestrator.configuration.schema.OrchestratorConfiguration; 12 | import org.firehol.netdata.utils.LoggingUtils; 13 | 14 | import com.fasterxml.jackson.core.JsonParseException; 15 | import com.fasterxml.jackson.core.JsonParser.Feature; 16 | import com.fasterxml.jackson.databind.JsonMappingException; 17 | import com.fasterxml.jackson.databind.ObjectMapper; 18 | 19 | import lombok.Getter; 20 | 21 | public final class ConfigurationService { 22 | private final Logger log = Logger.getLogger("org.firehol.netdata.orchestrator.configuration"); 23 | 24 | private final ObjectMapper mapper; 25 | 26 | private EnvironmentConfigurationService environmentConfigurationService = EnvironmentConfigurationService 27 | .getInstance(); 28 | 29 | @Getter 30 | private OrchestratorConfiguration globalConfiguration; 31 | 32 | private static final ConfigurationService INSTANCE = new ConfigurationService(); 33 | 34 | private ConfigurationService() { 35 | log.fine("Initialize object mapper for reading configuration files."); 36 | mapper = buildObjectMapper(); 37 | 38 | log.info("Read configuration"); 39 | try { 40 | this.globalConfiguration = readGlobalConfiguration(); 41 | } catch (ConfigurationSchemeInstantiationException e) { 42 | Main.exit(LoggingUtils.buildMessage("Could not initialize ConfigurationService", e)); 43 | } 44 | 45 | } 46 | 47 | private ObjectMapper buildObjectMapper() { 48 | ObjectMapper mapper = new ObjectMapper(); 49 | mapper.enable(Feature.ALLOW_COMMENTS); 50 | return mapper; 51 | } 52 | 53 | public static ConfigurationService getInstance() { 54 | return INSTANCE; 55 | } 56 | 57 | /** 58 | * Read a configuration file. 59 | * 60 | *

61 | * If the file cannot be parsed for some reason this methods tries to use a 62 | * default configuration. This is the default instance of the configuration 63 | * scheme. 64 | *

65 | * 66 | * @param 67 | * Configuration Schema. 68 | * 69 | * @param file 70 | * to read 71 | * @param clazz 72 | * The schema of the configuration. 73 | * @return The configuration read from file, or if it was invalid the 74 | * default configuration. 75 | * @throws ConfigurationSchemeInstantiationException 76 | * if it was not possible to instantiate clazz 77 | */ 78 | protected T readConfiguration(File file, Class clazz) throws ConfigurationSchemeInstantiationException { 79 | T configuration = null; 80 | 81 | // First try to read the value. 82 | try { 83 | configuration = mapper.readValue(file, clazz); 84 | } catch (JsonParseException | JsonMappingException e) { 85 | log.warning(LoggingUtils.getMessageSupplier( 86 | "Could not read malformed configuration file '" + file.getAbsolutePath() + ".", e)); 87 | } catch (Exception e) { 88 | log.warning(LoggingUtils.getMessageSupplier("Could not read configuration file '" + file.getAbsolutePath() 89 | + "', " + clazz + ", " + mapper + ".", e)); 90 | } 91 | 92 | // If we still have no configuration try to read the default one. 93 | if (configuration == null) { 94 | try { 95 | configuration = clazz.newInstance(); 96 | } catch (InstantiationException | IllegalAccessException e) { 97 | throw new ConfigurationSchemeInstantiationException( 98 | "Could not instanciate default configuration for class " + clazz.getName() + "."); 99 | } 100 | } 101 | 102 | return configuration; 103 | } 104 | 105 | public OrchestratorConfiguration readGlobalConfiguration() throws ConfigurationSchemeInstantiationException { 106 | final Path configDir = environmentConfigurationService.getConfigDir(); 107 | Path globalConfigPath = configDir.resolve("java.d.conf"); 108 | OrchestratorConfiguration globalConfig; 109 | 110 | globalConfig = readConfiguration(globalConfigPath.toFile(), OrchestratorConfiguration.class); 111 | return globalConfig; 112 | } 113 | 114 | public T readModuleConfiguration(String moduleName, Class clazz) 115 | throws ConfigurationSchemeInstantiationException { 116 | Path configDir = environmentConfigurationService.getConfigDir().resolve("java.d"); 117 | Path configFile = configDir.resolve(moduleName + ".conf"); 118 | 119 | log.info(": Reading '" + moduleName + "' module configuration file '" + configFile.toFile().getAbsolutePath() 120 | + "'"); 121 | return this.readConfiguration(configFile.toFile(), clazz); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/orchestrator/configuration/EnvironmentConfigurationService.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.orchestrator.configuration; 4 | 5 | import java.nio.file.InvalidPathException; 6 | import java.nio.file.Path; 7 | import java.nio.file.Paths; 8 | import java.util.logging.Logger; 9 | 10 | import org.firehol.netdata.Main; 11 | import org.firehol.netdata.orchestrator.configuration.exception.EnvironmentConfigurationException; 12 | import org.firehol.netdata.utils.LoggingUtils; 13 | 14 | import lombok.AccessLevel; 15 | import lombok.Getter; 16 | 17 | @Getter 18 | public class EnvironmentConfigurationService { 19 | @Getter(AccessLevel.NONE) 20 | private final Logger log = Logger.getLogger("org.firehol.netdata.daemon.configuration.environment"); 21 | 22 | private Path configDir; 23 | 24 | private static final EnvironmentConfigurationService INSTANCE = new EnvironmentConfigurationService(); 25 | 26 | public static EnvironmentConfigurationService getInstance() { 27 | return INSTANCE; 28 | } 29 | 30 | private EnvironmentConfigurationService() { 31 | try { 32 | readEnvironmentVariables(); 33 | } catch (EnvironmentConfigurationException e) { 34 | // Fail fast if this important singleton could not initialize. 35 | Main.exit(e.getMessage()); 36 | } 37 | } 38 | 39 | private void readEnvironmentVariables() throws EnvironmentConfigurationException { 40 | configDir = readNetdataConfigDir(); 41 | } 42 | 43 | protected Path readNetdataConfigDir() throws EnvironmentConfigurationException { 44 | log.fine("Parse environment variable NETDATA_CONFIG_DIR"); 45 | String configDirString = System.getenv("NETDATA_CONFIG_DIR"); 46 | 47 | if (configDirString == null) { 48 | throw new EnvironmentConfigurationException( 49 | "Expected environment variable 'NETDATA_CONFIG_DIR' is missing"); 50 | } 51 | 52 | Path configDir; 53 | 54 | try { 55 | configDir = Paths.get(configDirString); 56 | } catch (InvalidPathException e) { 57 | throw new EnvironmentConfigurationException( 58 | LoggingUtils.buildMessage("NETDATA_CONFIG_DIR contains no valid path name.", e)); 59 | } 60 | 61 | return configDir; 62 | 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/orchestrator/configuration/exception/ConfigurationSchemeInstantiationException.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.orchestrator.configuration.exception; 4 | 5 | import javax.naming.ConfigurationException; 6 | 7 | public class ConfigurationSchemeInstantiationException extends ConfigurationException { 8 | private static final long serialVersionUID = -5538037492659066003L; 9 | 10 | public ConfigurationSchemeInstantiationException() { 11 | } 12 | 13 | public ConfigurationSchemeInstantiationException(String explanation) { 14 | super(explanation); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/orchestrator/configuration/exception/EnvironmentConfigurationException.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.orchestrator.configuration.exception; 4 | 5 | import javax.naming.ConfigurationException; 6 | 7 | public class EnvironmentConfigurationException extends ConfigurationException { 8 | private static final long serialVersionUID = 3081984800137015485L; 9 | 10 | public EnvironmentConfigurationException(String message) { 11 | super(message); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/orchestrator/configuration/exception/ParseException.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.orchestrator.configuration.exception; 4 | 5 | import javax.naming.ConfigurationException; 6 | 7 | public class ParseException extends ConfigurationException { 8 | private static final long serialVersionUID = 1383816306854639084L; 9 | 10 | public ParseException() { 11 | super(); 12 | } 13 | 14 | public ParseException(String explanation) { 15 | super(explanation); 16 | } 17 | 18 | public ParseException(Throwable cause) { 19 | this.setRootCause(cause); 20 | } 21 | 22 | public ParseException(String explanation, Throwable cause) { 23 | super(explanation); 24 | this.setRootCause(cause); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/orchestrator/configuration/schema/OrchestratorConfiguration.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.orchestrator.configuration.schema; 4 | 5 | import lombok.Getter; 6 | import lombok.Setter; 7 | 8 | @Getter 9 | @Setter 10 | public final class OrchestratorConfiguration { 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/utils/AlignToTimeIntervalService.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.utils; 4 | 5 | import java.util.concurrent.TimeUnit; 6 | import java.util.logging.Logger; 7 | 8 | public class AlignToTimeIntervalService { 9 | private Logger log = Logger.getLogger("org.firehol.netdata.utils.aligntotimeintervalservice"); 10 | 11 | private final long intervalInNSec; 12 | private long lastTimestamp; 13 | 14 | public AlignToTimeIntervalService(long intervalInNSec, final TimeUnit timeUnit) { 15 | this.intervalInNSec = timeUnit.toNanos(intervalInNSec); 16 | this.lastTimestamp = ClockService.nowMonotonicNSec(); 17 | } 18 | 19 | public long alignToNextInterval() { 20 | long now = ClockService.nowMonotonicNSec(); 21 | long next = now - (now % intervalInNSec) + intervalInNSec; 22 | 23 | while (now < next) { 24 | try { 25 | long delta = next - now; 26 | 27 | Thread.sleep(delta / UnitConversion.MILI_PER_NANO, 28 | Math.toIntExact(delta % UnitConversion.MILI_PER_NANO)); 29 | } catch (InterruptedException e) { 30 | log.warning("Interrupted while waiting for next tick."); 31 | // We try again here. The worst might happen is a busy wait 32 | // instead of sleeping. 33 | } 34 | now = ClockService.nowMonotonicNSec(); 35 | } 36 | 37 | long delta = now - lastTimestamp; 38 | lastTimestamp = now; 39 | if (delta / intervalInNSec > 1) { 40 | log.warning("At least one tick missed since last call of alignToNextInterval()"); 41 | } 42 | return delta; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/utils/ClockService.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.utils; 4 | 5 | public abstract class ClockService { 6 | 7 | /** 8 | * Get the current Monotonic time. 9 | * 10 | * This clock is not affected by discontinuous jumps in the system time. 11 | * 12 | * @return Monotonic Clock in Microseconds 13 | */ 14 | public static long nowMonotonicNSec() { 15 | return System.nanoTime(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/utils/LoggingUtils.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.utils; 4 | 5 | import java.util.function.Supplier; 6 | 7 | public final class LoggingUtils { 8 | 9 | private LoggingUtils() { 10 | } 11 | 12 | private static void appendMessage(Throwable reason, StringBuilder sb) { 13 | 14 | sb.append('['); 15 | sb.append(reason.getClass().getName()); 16 | sb.append("] "); 17 | sb.append(reason.getMessage()); 18 | 19 | Throwable detail = reason.getCause(); 20 | while (detail != null) { 21 | sb.append(" Detail: "); 22 | sb.append(detail.getMessage()); 23 | detail = detail.getCause(); 24 | } 25 | } 26 | 27 | public static String buildMessage(Throwable reason) { 28 | StringBuilder sb = new StringBuilder(); 29 | appendMessage(reason, sb); 30 | return sb.toString(); 31 | } 32 | 33 | public static String buildMessage(String message, Throwable reason) { 34 | StringBuilder sb = new StringBuilder(message); 35 | 36 | sb.append(" Reason: "); 37 | appendMessage(reason, sb); 38 | return sb.toString(); 39 | } 40 | 41 | public static String buildMessage(String... messages) { 42 | if (messages.length == 0) { 43 | return ""; 44 | } 45 | 46 | if (messages.length == 1) { 47 | return messages[0]; 48 | } 49 | 50 | // Find String length. 51 | int totalLength = 0; 52 | for (String message : messages) { 53 | totalLength = +message.length(); 54 | } 55 | 56 | StringBuilder sb = new StringBuilder(totalLength); 57 | 58 | // Build the message 59 | for (String message : messages) { 60 | sb.append(message); 61 | } 62 | 63 | return sb.toString(); 64 | } 65 | 66 | public static Supplier getMessageSupplier(Throwable reason) { 67 | return () -> buildMessage(reason); 68 | } 69 | 70 | public static Supplier getMessageSupplier(String message, Throwable reason) { 71 | return () -> buildMessage(message, reason); 72 | } 73 | 74 | public static Supplier getMessageSupplier(String... messages) { 75 | return () -> buildMessage(messages); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/utils/ResourceUtils.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.utils; 4 | 5 | import java.io.Closeable; 6 | import java.io.IOException; 7 | import java.util.concurrent.CompletableFuture; 8 | import java.util.function.Supplier; 9 | 10 | public final class ResourceUtils { 11 | 12 | private ResourceUtils() { 13 | } 14 | 15 | public static CompletableFuture close(Closeable resource) { 16 | 17 | return CompletableFuture.supplyAsync(new Supplier() { 18 | 19 | @Override 20 | public Boolean get() { 21 | try { 22 | resource.close(); 23 | return true; 24 | } catch (IOException e) { 25 | return false; 26 | } 27 | } 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/utils/StringUtils.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.utils; 4 | 5 | public final class StringUtils { 6 | 7 | private StringUtils() { 8 | } 9 | 10 | /** 11 | * Checks if a String is only whitespace, empty ("") or null. 12 | */ 13 | public static boolean isBlank(String string) { 14 | int length; 15 | if (string == null || (length = string.length()) == 0) { 16 | return true; 17 | } 18 | for (int i = 0; i < length; i++) { 19 | if (!Character.isWhitespace(string.charAt(i))) { 20 | return false; 21 | } 22 | } 23 | return true; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/firehol/netdata/utils/UnitConversion.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.utils; 4 | 5 | import java.util.concurrent.TimeUnit; 6 | 7 | public abstract class UnitConversion { 8 | public static long NANO_PER_PLAIN = TimeUnit.SECONDS.toNanos(1); 9 | 10 | public static long MILI_PER_PLAIN = TimeUnit.SECONDS.toMillis(1); 11 | 12 | public static long MILI_PER_NANO = TimeUnit.MILLISECONDS.toNanos(1); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/sh/java.d.plugin: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | exec java -Djava.util.logging.SimpleFormatter.format='%1$tF %1$TT: java.d: %4$s: %3$s: %5$s%6$s%n' -jar /tmp/java-orchestrator-0.1.0-SNAPSHOT.jar $@ -------------------------------------------------------------------------------- /src/test/java/org/firehol/netdata/MainTest.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | 7 | import org.junit.Rule; 8 | import org.junit.Test; 9 | import org.junit.contrib.java.lang.system.ExpectedSystemExit; 10 | import org.junit.contrib.java.lang.system.SystemErrRule; 11 | import org.junit.contrib.java.lang.system.SystemOutRule; 12 | 13 | public class MainTest { 14 | 15 | @Rule 16 | public final ExpectedSystemExit exit = ExpectedSystemExit.none(); 17 | 18 | @Rule 19 | public final SystemOutRule systemOutRule = new SystemOutRule().muteForSuccessfulTests().enableLog(); 20 | 21 | @Rule 22 | public final SystemErrRule systemerrRule = new SystemErrRule().muteForSuccessfulTests(); 23 | 24 | @Test 25 | public void testGetUpdateEveryInSecondsFomCommandLineFailFast() { 26 | final String[] args = { "3" }; 27 | 28 | int updateEvery = Main.getUpdateEveryInSecondsFomCommandLineFailFast(args); 29 | 30 | assertEquals(3, updateEvery); 31 | } 32 | 33 | @Test 34 | public void testGetUpdateEveryInSecondsFomCommandLineFailFastFailToMany() { 35 | exit.expectSystemExitWithStatus(1); 36 | final String[] args = { "to", "many" }; 37 | 38 | exit.expectSystemExitWithStatus(1); 39 | 40 | Main.getUpdateEveryInSecondsFomCommandLineFailFast(args); 41 | } 42 | 43 | @Test 44 | public void testGetUpdateEveryInSecondsFomCommandLineFailFastFailNoNumber() { 45 | exit.expectSystemExitWithStatus(1); 46 | final String[] args = { "String" }; 47 | 48 | exit.expectSystemExitWithStatus(1); 49 | 50 | Main.getUpdateEveryInSecondsFomCommandLineFailFast(args); 51 | } 52 | 53 | @Test 54 | public void testExit() throws Exception { 55 | exit.expectSystemExitWithStatus(1); 56 | 57 | Main.exit("Test"); 58 | 59 | assertEquals("DISABLE", systemOutRule.getLog()); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/org/firehol/netdata/module/jmx/MBeanServerCollectorTest.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.module.jmx; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | import static org.junit.Assert.assertFalse; 7 | import static org.junit.Assert.assertNull; 8 | import static org.mockito.Mockito.doThrow; 9 | import static org.mockito.Mockito.times; 10 | import static org.mockito.Mockito.verify; 11 | import static org.mockito.Mockito.when; 12 | 13 | import java.io.IOException; 14 | 15 | import javax.management.AttributeNotFoundException; 16 | import javax.management.InstanceNotFoundException; 17 | import javax.management.MBeanException; 18 | import javax.management.MBeanServerConnection; 19 | import javax.management.MalformedObjectNameException; 20 | import javax.management.ObjectName; 21 | import javax.management.ReflectionException; 22 | import javax.management.remote.JMXConnector; 23 | 24 | import org.firehol.netdata.model.Chart; 25 | import org.firehol.netdata.model.ChartType; 26 | import org.firehol.netdata.model.Dimension; 27 | import org.firehol.netdata.model.DimensionAlgorithm; 28 | import org.firehol.netdata.module.jmx.MBeanServerCollector; 29 | import org.firehol.netdata.module.jmx.configuration.JmxChartConfiguration; 30 | import org.firehol.netdata.module.jmx.configuration.JmxDimensionConfiguration; 31 | import org.firehol.netdata.module.jmx.configuration.JmxServerConfiguration; 32 | import org.firehol.netdata.module.jmx.exception.JmxMBeanServerQueryException; 33 | import org.firehol.netdata.testutils.ReflectionUtils; 34 | import org.firehol.netdata.testutils.TestObjectBuilder; 35 | import org.junit.Test; 36 | import org.junit.runner.RunWith; 37 | import org.mockito.InjectMocks; 38 | import org.mockito.Mock; 39 | import org.mockito.junit.MockitoJUnitRunner; 40 | 41 | @RunWith(MockitoJUnitRunner.class) 42 | public class MBeanServerCollectorTest { 43 | 44 | @InjectMocks 45 | private MBeanServerCollector mBeanServerCollector; 46 | 47 | @Mock 48 | private JMXConnector jmxConnector; 49 | 50 | @Mock 51 | private MBeanServerConnection mBeanServer; 52 | 53 | @Test 54 | public void testInitializeChart() throws NoSuchFieldException, IllegalAccessException, SecurityException { 55 | // Static Objects 56 | JmxChartConfiguration config = TestObjectBuilder.buildJmxChartConfiguration(); 57 | JmxServerConfiguration serverConfig = new JmxServerConfiguration(); 58 | String serverName = "TestServer"; 59 | serverConfig.setName(serverName); 60 | ReflectionUtils.setPrivateFiled(mBeanServerCollector, "serverConfiguration", serverConfig); 61 | 62 | // Test 63 | Chart chart = mBeanServerCollector.initializeChart(config); 64 | 65 | // Verify 66 | assertEquals("jmx_TestServer", chart.getType()); 67 | assertEquals("id", chart.getId()); 68 | assertNull(chart.getName()); 69 | assertEquals("title", chart.getTitle()); 70 | assertEquals("units", config.getUnits()); 71 | assertEquals("family", chart.getFamily()); 72 | assertEquals(serverName, chart.getContext()); 73 | assertEquals(ChartType.LINE, chart.getChartType()); 74 | assertEquals(1000, chart.getPriority()); 75 | assertNull(chart.getUpdateEvery()); 76 | } 77 | 78 | @Test 79 | public void testInitializeChartDynamicPriority() 80 | throws NoSuchFieldException, IllegalAccessException, SecurityException { 81 | // Static Objects 82 | JmxChartConfiguration config = TestObjectBuilder.buildJmxChartConfiguration(); 83 | config.setPriority(1); 84 | JmxServerConfiguration serverConfig = new JmxServerConfiguration(); 85 | String serverName = "TestServer"; 86 | serverConfig.setName(serverName); 87 | ReflectionUtils.setPrivateFiled(mBeanServerCollector, "serverConfiguration", serverConfig); 88 | 89 | // Test 90 | Chart chart = mBeanServerCollector.initializeChart(config); 91 | 92 | // Verify 93 | assertEquals(1, chart.getPriority()); 94 | } 95 | 96 | @Test 97 | public void testInitializeDimension() { 98 | // Static Objects 99 | JmxChartConfiguration chartConfig = TestObjectBuilder.buildJmxChartConfiguration(); 100 | JmxDimensionConfiguration dimensionConfig = TestObjectBuilder.buildJmxDimensionConfiguration(); 101 | chartConfig.getDimensions().add(dimensionConfig); 102 | 103 | // Test 104 | Dimension dimension = mBeanServerCollector.initializeDimension(chartConfig, dimensionConfig); 105 | 106 | // Verify 107 | assertEquals("name", dimension.getId()); 108 | assertEquals("name", dimension.getName()); 109 | assertEquals(DimensionAlgorithm.ABSOLUTE, dimension.getAlgorithm()); 110 | assertEquals(1, dimension.getMultiplier()); 111 | assertEquals(1, dimension.getDivisor()); 112 | assertFalse(dimension.isHidden()); 113 | assertNull(dimension.getCurrentValue()); 114 | } 115 | 116 | @Test 117 | public void testGetAttribute() throws MalformedObjectNameException, AttributeNotFoundException, 118 | InstanceNotFoundException, MBeanException, ReflectionException, IOException, JmxMBeanServerQueryException { 119 | // Static Objects 120 | ObjectName name = new ObjectName("org.firehol.netdata.module.jmx", "key", "value"); 121 | String attribute = "attribute"; 122 | 123 | // Mock 124 | when(mBeanServer.getAttribute(name, attribute)).thenReturn(1234L); 125 | 126 | // Test 127 | Object value = mBeanServerCollector.getAttribute(name, attribute); 128 | 129 | // Verify 130 | assertEquals(1234L, value); 131 | } 132 | 133 | @Test(expected = JmxMBeanServerQueryException.class) 134 | public void testGetAttributeFailure() throws MalformedObjectNameException, AttributeNotFoundException, 135 | InstanceNotFoundException, MBeanException, ReflectionException, IOException, JmxMBeanServerQueryException { 136 | // Static Objects 137 | ObjectName name = new ObjectName("org.firehol.netdata.module.jmx", "key", "value"); 138 | String attribute = "attribute"; 139 | 140 | // Mock 141 | when(mBeanServer.getAttribute(name, attribute)).thenThrow(new AttributeNotFoundException()); 142 | 143 | // Test 144 | mBeanServerCollector.getAttribute(name, attribute); 145 | } 146 | 147 | @Test 148 | public void testClose() throws IOException { 149 | // Test 150 | mBeanServerCollector.close(); 151 | // Verify 152 | verify(jmxConnector, times(1)).close(); 153 | } 154 | 155 | @Test(expected = IOException.class) 156 | public void testCloseFailure() throws IOException { 157 | // Mock 158 | doThrow(new IOException()).when(jmxConnector).close(); 159 | // Test 160 | mBeanServerCollector.close(); 161 | } 162 | 163 | } 164 | -------------------------------------------------------------------------------- /src/test/java/org/firehol/netdata/module/jmx/query/MBeanCompositeDataQueryTest.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.module.jmx.query; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | import static org.mockito.Mockito.mock; 7 | import static org.mockito.Mockito.when; 8 | 9 | import java.io.IOException; 10 | 11 | import javax.management.*; 12 | import javax.management.openmbean.CompositeData; 13 | 14 | import org.firehol.netdata.model.Dimension; 15 | import org.firehol.netdata.module.jmx.exception.JmxMBeanServerQueryException; 16 | import org.junit.Test; 17 | 18 | public class MBeanCompositeDataQueryTest { 19 | 20 | private MBeanServerConnection mBeanServer = mock(MBeanServerConnection.class); 21 | 22 | private final MBeanQuery query = new MBeanCompositeDataQuery(mBeanServer, ObjectName.WILDCARD, "Attribute"); 23 | 24 | @Test 25 | public void testConstructorAttributeWithoutKey() { 26 | assertEquals("Attribute", query.getAttribute()); 27 | } 28 | 29 | @Test 30 | public void testQueryInteger() throws AttributeNotFoundException, MBeanException, ReflectionException, 31 | InstanceNotFoundException, IOException, JmxMBeanServerQueryException { 32 | final CompositeData compositeData = mock(CompositeData.class); 33 | when(compositeData.get("key")).thenReturn(1234); 34 | 35 | when(mBeanServer.getAttribute(ObjectName.WILDCARD, "Attribute")).thenReturn(compositeData); 36 | 37 | final Dimension dim = new Dimension(); 38 | query.addDimension(dim, "Attribute.key"); 39 | 40 | query.query(); 41 | 42 | assertEquals((Long) 1234L, dim.getCurrentValue()); 43 | } 44 | 45 | @Test 46 | public void testQueryDouble() throws JmxMBeanServerQueryException, AttributeNotFoundException, MBeanException, 47 | ReflectionException, InstanceNotFoundException, IOException { 48 | final CompositeData compositeData = mock(CompositeData.class); 49 | when(compositeData.get("key")).thenReturn(12.34); 50 | 51 | when(mBeanServer.getAttribute(ObjectName.WILDCARD, "Attribute")).thenReturn(compositeData); 52 | 53 | final Dimension dim = new Dimension(); 54 | query.addDimension(dim, "Attribute.key"); 55 | 56 | query.query(); 57 | 58 | assertEquals((Long) 1234L, dim.getCurrentValue()); 59 | } 60 | 61 | @Test 62 | public void testQueryTwoKey() throws JmxMBeanServerQueryException, AttributeNotFoundException, MBeanException, 63 | ReflectionException, InstanceNotFoundException, IOException { 64 | final CompositeData compositeData = mock(CompositeData.class); 65 | when(compositeData.get("first")).thenReturn(1234L); 66 | when(compositeData.get("second")).thenReturn(4321L); 67 | 68 | when(mBeanServer.getAttribute(ObjectName.WILDCARD, "Attribute")).thenReturn(compositeData); 69 | 70 | final Dimension dimension1 = new Dimension(); 71 | query.addDimension(dimension1, "Attribute.first"); 72 | 73 | final Dimension dimension2 = new Dimension(); 74 | query.addDimension(dimension2, "Attribute.second"); 75 | 76 | query.query(); 77 | 78 | assertEquals((Long) 1234L, dimension1.getCurrentValue()); 79 | assertEquals((Long) 4321L, dimension2.getCurrentValue()); 80 | } 81 | 82 | @Test 83 | public void testQueryTwoDimensionSameKey() throws JmxMBeanServerQueryException, AttributeNotFoundException, 84 | MBeanException, ReflectionException, InstanceNotFoundException, IOException { 85 | final CompositeData compositeData = mock(CompositeData.class); 86 | when(compositeData.get("first")).thenReturn(1234L); 87 | 88 | when(mBeanServer.getAttribute(ObjectName.WILDCARD, "Attribute")).thenReturn(compositeData); 89 | 90 | final Dimension dimension1 = new Dimension(); 91 | query.addDimension(dimension1, "Attribute.first"); 92 | 93 | final Dimension dimension2 = new Dimension(); 94 | query.addDimension(dimension2, "Attribute.first"); 95 | 96 | query.query(); 97 | 98 | assertEquals((Long) 1234L, dimension1.getCurrentValue()); 99 | assertEquals((Long) 1234L, dimension2.getCurrentValue()); 100 | } 101 | 102 | @Test(expected = IllegalArgumentException.class) 103 | public void testAddDimensionAttributeNoMatch() throws JmxMBeanServerQueryException { 104 | final Dimension dim = new Dimension(); 105 | 106 | query.addDimension(dim, "NoMatch.key"); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/test/java/org/firehol/netdata/module/jmx/query/MBeanQueryTest.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.module.jmx.query; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | import static org.junit.Assert.fail; 7 | import static org.mockito.Mockito.verify; 8 | import static org.powermock.api.mockito.PowerMockito.mock; 9 | import static org.powermock.api.mockito.PowerMockito.when; 10 | 11 | import java.io.IOException; 12 | import java.util.Collection; 13 | 14 | import javax.management.*; 15 | import javax.management.openmbean.CompositeData; 16 | import javax.management.openmbean.CompositeType; 17 | 18 | import org.firehol.netdata.model.Dimension; 19 | import org.firehol.netdata.module.jmx.exception.JmxMBeanServerQueryException; 20 | import org.firehol.netdata.module.jmx.utils.MBeanServerUtils; 21 | import org.junit.Assert; 22 | import org.junit.Test; 23 | import org.junit.runner.RunWith; 24 | import org.mockito.ArgumentMatchers; 25 | import org.powermock.api.mockito.PowerMockito; 26 | import org.powermock.core.classloader.annotations.PrepareForTest; 27 | import org.powermock.modules.junit4.PowerMockRunner; 28 | 29 | @RunWith(PowerMockRunner.class) 30 | @PrepareForTest(MBeanServerUtils.class) 31 | public class MBeanQueryTest { 32 | 33 | private final MBeanServerConnection mBeanServer = mock(MBeanServerConnection.class); 34 | 35 | @Test 36 | public void testNewInsctanceInteger() throws AttributeNotFoundException, MBeanException, ReflectionException, 37 | InstanceNotFoundException, IOException, JmxMBeanServerQueryException { 38 | final String testAttribute = "Attribute"; 39 | when(mBeanServer.getAttribute(ObjectName.WILDCARD, testAttribute)).thenReturn(1234); 40 | 41 | final MBeanQuery mBeanQuery = MBeanQuery.newInstance(mBeanServer, ObjectName.WILDCARD, testAttribute); 42 | 43 | assertInstanceOf(MBeanSimpleQuery.class, mBeanQuery); 44 | 45 | verify(mBeanServer).getAttribute(ObjectName.WILDCARD, testAttribute); 46 | assertEquals(testAttribute, mBeanQuery.getAttribute()); 47 | assertEquals(ObjectName.WILDCARD, mBeanQuery.getName()); 48 | assertEquals(mBeanServer, mBeanQuery.getMBeanServer()); 49 | } 50 | 51 | @Test 52 | public void testNewInstanceLong() throws JmxMBeanServerQueryException, AttributeNotFoundException, MBeanException, 53 | ReflectionException, InstanceNotFoundException, IOException { 54 | when(mBeanServer.getAttribute(ObjectName.WILDCARD, "Attribute")).thenReturn(1234L); 55 | 56 | final MBeanQuery mBeanQuery = MBeanQuery.newInstance(mBeanServer, ObjectName.WILDCARD, "Attribute"); 57 | 58 | assertInstanceOf(MBeanSimpleQuery.class, mBeanQuery); 59 | } 60 | 61 | @Test 62 | public void testNewInstanceDouble() throws AttributeNotFoundException, MBeanException, ReflectionException, 63 | InstanceNotFoundException, IOException, JmxMBeanServerQueryException { 64 | when(mBeanServer.getAttribute(ObjectName.WILDCARD, "Attribute")).thenReturn(12.34); 65 | 66 | final MBeanQuery mBeanQuery = MBeanQuery.newInstance(mBeanServer, ObjectName.WILDCARD, "Attribute"); 67 | 68 | assertInstanceOf(MBeanSimpleQuery.class, mBeanQuery); 69 | } 70 | 71 | @Test 72 | public void testNewInstanceCompositeData() throws JmxMBeanServerQueryException, AttributeNotFoundException, 73 | MBeanException, ReflectionException, InstanceNotFoundException, IOException { 74 | when(mBeanServer.getAttribute(ObjectName.WILDCARD, "Attribute")).thenReturn(buildCompositeData()); 75 | 76 | final MBeanQuery mBeanQuery = MBeanQuery.newInstance(mBeanServer, ObjectName.WILDCARD, "Attribute.compkey"); 77 | 78 | assertInstanceOf(MBeanCompositeDataQuery.class, mBeanQuery); 79 | } 80 | 81 | private void assertInstanceOf(final Class expectedClass, final MBeanQuery mBeanQuery) { 82 | if (!expectedClass.isInstance(mBeanQuery)) { 83 | fail(String.format("%s should be instance of %s but is instance of %s", mBeanQuery.toString(), 84 | expectedClass.toString(), mBeanQuery.getClass().toString())); 85 | } 86 | } 87 | 88 | private CompositeData buildCompositeData() { 89 | return new CompositeData() { 90 | @Override 91 | public CompositeType getCompositeType() { 92 | return null; 93 | } 94 | 95 | @Override 96 | public Object get(final String key) { 97 | return null; 98 | } 99 | 100 | @Override 101 | public Object[] getAll(final String[] keys) { 102 | return new Object[0]; 103 | } 104 | 105 | @Override 106 | public boolean containsKey(final String key) { 107 | return false; 108 | } 109 | 110 | @Override 111 | public boolean containsValue(final Object value) { 112 | return false; 113 | } 114 | 115 | @Override 116 | public Collection values() { 117 | return null; 118 | } 119 | }; 120 | } 121 | 122 | @Test 123 | public void testQueryLong() throws JmxMBeanServerQueryException, MalformedObjectNameException, 124 | AttributeNotFoundException, MBeanException, ReflectionException, InstanceNotFoundException, IOException { 125 | testQuery(1234L); 126 | } 127 | 128 | @Test 129 | public void testQueryDouble() throws JmxMBeanServerQueryException, MalformedObjectNameException, 130 | AttributeNotFoundException, MBeanException, ReflectionException, InstanceNotFoundException, IOException { 131 | testQuery(12.34); 132 | 133 | } 134 | 135 | @Test 136 | public void testQueryInteger() throws JmxMBeanServerQueryException, MalformedObjectNameException, 137 | AttributeNotFoundException, MBeanException, ReflectionException, InstanceNotFoundException, IOException { 138 | testQuery(1234); 139 | } 140 | 141 | public void testQuery(Object queryResult) throws JmxMBeanServerQueryException, MalformedObjectNameException, 142 | AttributeNotFoundException, MBeanException, ReflectionException, InstanceNotFoundException, IOException { 143 | final ObjectName name = new ObjectName("*:type=MBean"); 144 | when(mBeanServer.getAttribute(name, "MBeanAttributeName")).thenReturn(queryResult); 145 | 146 | final MBeanQuery query = MBeanQuery.newInstance(mBeanServer, name, "MBeanAttributeName"); 147 | final Dimension dim1 = new Dimension(); 148 | dim1.setName("Dimension 1"); 149 | query.getDimensions().add(dim1); 150 | final Dimension dim2 = new Dimension(); 151 | dim2.setName("Dimension 2"); 152 | query.getDimensions().add(dim2); 153 | 154 | PowerMockito.mockStatic(MBeanServerUtils.class); 155 | when(MBeanServerUtils.getAttribute(ArgumentMatchers.any(), ArgumentMatchers.any(), ArgumentMatchers.any())) 156 | .thenReturn(queryResult); 157 | 158 | // test 159 | query.query(); 160 | 161 | // assert 162 | for (Dimension dimension : query.getDimensions()) { 163 | Assert.assertEquals(dimension.getName(), (Long) 1234L, dimension.getCurrentValue()); 164 | } 165 | } 166 | 167 | @Test 168 | public void testAddDimension() throws JmxMBeanServerQueryException, AttributeNotFoundException, MBeanException, 169 | ReflectionException, InstanceNotFoundException, IOException { 170 | when(mBeanServer.getAttribute(ObjectName.WILDCARD, "attribute")).thenReturn(1234L); 171 | final MBeanQuery query = MBeanQuery.newInstance(mBeanServer, ObjectName.WILDCARD, "attribute"); 172 | final Dimension dimension = new Dimension(); 173 | 174 | query.addDimension(dimension, "attribute"); 175 | 176 | assertEquals(dimension, query.getDimensions().get(0)); 177 | } 178 | 179 | @Test(expected = IllegalArgumentException.class) 180 | public void testAddDimensionAttributeNotMatch() throws JmxMBeanServerQueryException, AttributeNotFoundException, 181 | MBeanException, ReflectionException, InstanceNotFoundException, IOException { 182 | when(mBeanServer.getAttribute(ObjectName.WILDCARD, "attribute")).thenReturn(1234L); 183 | final MBeanQuery query = MBeanQuery.newInstance(mBeanServer, ObjectName.WILDCARD, "attribute"); 184 | final Dimension dimension = new Dimension(); 185 | 186 | query.addDimension(dimension, "no match"); 187 | } 188 | 189 | @Test(expected = IllegalArgumentException.class) 190 | public void testAddDimensionAttributeNull() throws JmxMBeanServerQueryException, AttributeNotFoundException, 191 | MBeanException, ReflectionException, InstanceNotFoundException, IOException { 192 | when(mBeanServer.getAttribute(ObjectName.WILDCARD, "attribute")).thenReturn(1234L); 193 | final MBeanQuery query = MBeanQuery.newInstance(mBeanServer, ObjectName.WILDCARD, "attribute"); 194 | final Dimension dimension = new Dimension(); 195 | 196 | query.addDimension(dimension, null); 197 | } 198 | 199 | @Test() 200 | public void testAddDimensionCompositeData() throws JmxMBeanServerQueryException, AttributeNotFoundException, 201 | MBeanException, ReflectionException, InstanceNotFoundException, IOException { 202 | when(mBeanServer.getAttribute(ObjectName.WILDCARD, "attribute")).thenReturn(buildCompositeData()); 203 | final MBeanQuery query = MBeanQuery.newInstance(mBeanServer, ObjectName.WILDCARD, "attribute"); 204 | final Dimension dimension = new Dimension(); 205 | 206 | query.addDimension(dimension, "attribute.key"); 207 | 208 | assertEquals(dimension, query.getDimensions().get(0)); 209 | } 210 | 211 | } 212 | -------------------------------------------------------------------------------- /src/test/java/org/firehol/netdata/module/jmx/query/MBeanValueStoreTest.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.module.jmx.query; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | 7 | import java.util.List; 8 | import java.util.stream.Collectors; 9 | 10 | import org.firehol.netdata.model.Dimension; 11 | import org.junit.Test; 12 | 13 | public class MBeanValueStoreTest { 14 | 15 | @Test 16 | public void testNewInstance() { 17 | final long valueToHandle = 1234; 18 | final MBeanValueStore store = MBeanValueStore.newInstance(valueToHandle); 19 | 20 | assertEquals(MBeanLongStore.class, store.getClass()); 21 | } 22 | 23 | @Test 24 | public void testNewInstanceDouble() { 25 | final double valueToHandle = 12.34; 26 | final MBeanValueStore store = MBeanValueStore.newInstance(valueToHandle); 27 | 28 | assertEquals(MBeanDoubleStore.class, store.getClass()); 29 | } 30 | 31 | @Test 32 | public void addDimension() { 33 | final MBeanValueStore store = MBeanValueStore.newInstance(1234); 34 | final Dimension dimension = new Dimension(); 35 | 36 | store.addDimension(dimension); 37 | 38 | assertEquals(dimension, store.streamAllDimension().findFirst().orElse(null)); 39 | } 40 | 41 | @Test 42 | public void streamAllDimension() { 43 | final MBeanValueStore store = MBeanValueStore.newInstance(1234); 44 | final Dimension dimension = new Dimension(); 45 | store.addDimension(dimension); 46 | 47 | final List allDimension = store.streamAllDimension().collect(Collectors.toList()); 48 | 49 | assertEquals(1, allDimension.size()); 50 | assertEquals(dimension, allDimension.get(0)); 51 | } 52 | 53 | @Test 54 | public void testUpdateValueLong() { 55 | final MBeanValueStore store = MBeanValueStore.newInstance(1234L); 56 | final Dimension dimension = new Dimension(); 57 | store.addDimension(dimension); 58 | 59 | store.updateValue(1234L); 60 | 61 | assertEquals(1234L, (long) dimension.getCurrentValue()); 62 | } 63 | 64 | @Test 65 | public void testUpdateValueInteger() { 66 | final MBeanValueStore store = MBeanValueStore.newInstance(1234); 67 | final Dimension dimension = new Dimension(); 68 | store.addDimension(dimension); 69 | 70 | store.updateValue(1234); 71 | 72 | assertEquals(1234L, (long) dimension.getCurrentValue()); 73 | } 74 | 75 | @Test 76 | public void testUpdateValueDouble() { 77 | final MBeanValueStore store = MBeanValueStore.newInstance(12.34); 78 | final Dimension dimension = new Dimension(); 79 | store.addDimension(dimension); 80 | 81 | store.updateValue(12.34); 82 | 83 | assertEquals(1234L, (long) dimension.getCurrentValue()); 84 | assertEquals("Add Dimension should set divisor", 100, dimension.getDivisor()); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/test/java/org/firehol/netdata/module/jmx/utils/MBeanServerUtilsTest.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.module.jmx.utils; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | import static org.mockito.Mockito.when; 7 | 8 | import java.io.IOException; 9 | 10 | import javax.management.*; 11 | 12 | import org.firehol.netdata.module.jmx.exception.JmxMBeanServerQueryException; 13 | import org.junit.Test; 14 | import org.junit.runner.RunWith; 15 | import org.mockito.Mock; 16 | import org.mockito.junit.MockitoJUnitRunner; 17 | 18 | @RunWith(MockitoJUnitRunner.class) 19 | public class MBeanServerUtilsTest { 20 | 21 | @Mock 22 | private MBeanServerConnection mBeanServer; 23 | 24 | @Test 25 | public void testGetAttribute() throws MalformedObjectNameException, AttributeNotFoundException, 26 | InstanceNotFoundException, MBeanException, ReflectionException, IOException, JmxMBeanServerQueryException { 27 | // Static Objects 28 | ObjectName name = new ObjectName("org.firehol.netdata.module.jmx", "key", "value"); 29 | String attribute = "attribute"; 30 | 31 | // Mock 32 | when(mBeanServer.getAttribute(name, attribute)).thenReturn(1234L); 33 | 34 | // Test 35 | Object value = MBeanServerUtils.getAttribute(mBeanServer, name, attribute); 36 | 37 | // Verify 38 | assertEquals(1234L, value); 39 | } 40 | 41 | @Test(expected = JmxMBeanServerQueryException.class) 42 | public void testGetAttributeFailure() throws MalformedObjectNameException, AttributeNotFoundException, 43 | InstanceNotFoundException, MBeanException, ReflectionException, IOException, JmxMBeanServerQueryException { 44 | // Static Objects 45 | ObjectName name = new ObjectName("org.firehol.netdata.module.jmx", "key", "value"); 46 | String attribute = "attribute"; 47 | 48 | // Mock 49 | when(mBeanServer.getAttribute(name, attribute)).thenThrow(new AttributeNotFoundException()); 50 | 51 | // Test 52 | MBeanServerUtils.getAttribute(mBeanServer, name, attribute); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/test/java/org/firehol/netdata/orchestrator/PrinterTest.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.orchestrator; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | import static org.junit.Assert.assertNull; 7 | 8 | import org.firehol.netdata.model.Chart; 9 | import org.firehol.netdata.model.Dimension; 10 | import org.firehol.netdata.testutils.TestObjectBuilder; 11 | import org.junit.Rule; 12 | import org.junit.Test; 13 | import org.junit.contrib.java.lang.system.SystemOutRule; 14 | 15 | public class PrinterTest { 16 | 17 | @Rule 18 | public final SystemOutRule systemOutRule = new SystemOutRule().enableLog().muteForSuccessfulTests(); 19 | 20 | @Test 21 | public void testInitializeChart() { 22 | 23 | // Static Objects 24 | Chart chart = TestObjectBuilder.buildChart(); 25 | chart.setUpdateEvery(1); 26 | Dimension dim = TestObjectBuilder.buildDimension(); 27 | chart.getAllDimension().add(dim); 28 | 29 | // Test 30 | Printer.initializeChart(chart); 31 | 32 | // Verify 33 | assertEquals( 34 | "CHART type.id name 'title' units family context line 1000 1\nDIMENSION id name absolute 1 1 hidden\n", 35 | systemOutRule.getLog()); 36 | } 37 | 38 | @Test 39 | public void testAppendInitializeChart() { 40 | 41 | // Static Objects 42 | Chart chart = TestObjectBuilder.buildChart(); 43 | StringBuilder sb = new StringBuilder(); 44 | 45 | // Test 46 | Printer.appendInitializeChart(sb, chart); 47 | 48 | // Verify 49 | assertEquals("CHART type.id name 'title' units family context line 1000", sb.toString()); 50 | } 51 | 52 | @Test 53 | public void testAppendInitializeChartNoName() { 54 | 55 | // Static Objects 56 | Chart chart = TestObjectBuilder.buildChart(); 57 | chart.setName(null); 58 | StringBuilder sb = new StringBuilder(); 59 | 60 | // Test 61 | Printer.appendInitializeChart(sb, chart); 62 | 63 | // Verify 64 | assertEquals("CHART type.id null 'title' units family context line 1000", sb.toString()); 65 | } 66 | 67 | @Test 68 | public void testAppendInitializeChartNoFamily() { 69 | 70 | // Static Objects 71 | Chart chart = TestObjectBuilder.buildChart(); 72 | chart.setFamily(null); 73 | StringBuilder sb = new StringBuilder(); 74 | 75 | // Test 76 | Printer.appendInitializeChart(sb, chart); 77 | 78 | // Verify 79 | assertEquals("CHART type.id name 'title' units id context line 1000", sb.toString()); 80 | } 81 | 82 | @Test 83 | public void testAppendInitializeChartNoContext() { 84 | 85 | // Static Objects 86 | Chart chart = TestObjectBuilder.buildChart(); 87 | chart.setContext(null); 88 | StringBuilder sb = new StringBuilder(); 89 | 90 | // Test 91 | Printer.appendInitializeChart(sb, chart); 92 | 93 | // Verify 94 | assertEquals("CHART type.id name 'title' units family id line 1000", sb.toString()); 95 | } 96 | 97 | @Test 98 | public void testAppendInitializeDimension() { 99 | 100 | // Static Objects 101 | Dimension dimension = TestObjectBuilder.buildDimension(); 102 | StringBuilder sb = new StringBuilder(); 103 | 104 | // Test 105 | Printer.appendInitializeDimension(sb, dimension); 106 | 107 | // Verify 108 | assertEquals("DIMENSION id name absolute 1 1 hidden", sb.toString()); 109 | } 110 | 111 | @Test 112 | public void testAppendInitializeDimensionNotHidden() { 113 | 114 | // Static Objects 115 | Dimension dimension = TestObjectBuilder.buildDimension(); 116 | dimension.setHidden(false); 117 | StringBuilder sb = new StringBuilder(); 118 | 119 | // Test 120 | Printer.appendInitializeDimension(sb, dimension); 121 | 122 | // Verify 123 | assertEquals("DIMENSION id name absolute 1 1", sb.toString()); 124 | } 125 | 126 | @Test 127 | public void testAppendInitializeDimensionNoName() { 128 | 129 | // Static Objects 130 | Dimension dimension = TestObjectBuilder.buildDimension(); 131 | dimension.setName(null); 132 | StringBuilder sb = new StringBuilder(); 133 | 134 | // Test 135 | Printer.appendInitializeDimension(sb, dimension); 136 | 137 | // Verify 138 | assertEquals("DIMENSION id id absolute 1 1 hidden", sb.toString()); 139 | } 140 | 141 | @Test 142 | public void testCollect() { 143 | 144 | // Static Objects 145 | Chart chart = TestObjectBuilder.buildChart(); 146 | Dimension dim = TestObjectBuilder.buildDimension(); 147 | dim.setCurrentValue(1L); 148 | chart.getAllDimension().add(dim); 149 | 150 | // Test 151 | Printer.collect(chart); 152 | 153 | // Verify 154 | assertEquals("BEGIN type.id\nSET id = 1\nEND\n", systemOutRule.getLog()); 155 | // collect should delete currentValue after printing. 156 | assertNull(dim.getCurrentValue()); 157 | } 158 | 159 | @Test 160 | public void testCollectNoValue() { 161 | 162 | // Static Objects 163 | Chart chart = TestObjectBuilder.buildChart(); 164 | Dimension dim = TestObjectBuilder.buildDimension(); 165 | dim.setCurrentValue(null); 166 | chart.getAllDimension().add(dim); 167 | 168 | // Test 169 | Printer.collect(chart); 170 | 171 | // Verify 172 | assertEquals("BEGIN type.id\nEND\n", systemOutRule.getLog()); 173 | // collect should delete currentValue after printing. 174 | assertNull(dim.getCurrentValue()); 175 | } 176 | 177 | @Test 178 | public void testAppendCollectBegin() { 179 | 180 | // Static Objects 181 | Chart chart = TestObjectBuilder.buildChart(); 182 | StringBuilder sb = new StringBuilder(); 183 | 184 | // Test 185 | Printer.appendCollectBegin(sb, chart); 186 | 187 | // Verify 188 | assertEquals("BEGIN type.id", sb.toString()); 189 | } 190 | 191 | @Test 192 | public void testAppendCollectDimension() { 193 | 194 | // Static Objects 195 | Dimension dimension = TestObjectBuilder.buildDimension(); 196 | StringBuilder sb = new StringBuilder(); 197 | 198 | // Test 199 | Printer.appendCollectDimension(sb, dimension); 200 | 201 | // Verify 202 | assertEquals("SET id = 1", sb.toString()); 203 | } 204 | 205 | @Test 206 | public void testAppendCollectEnd() { 207 | // Static Objects 208 | StringBuilder sb = new StringBuilder(); 209 | 210 | // Test 211 | Printer.appendCollectEnd(sb); 212 | 213 | // Verify 214 | assertEquals("END", sb.toString()); 215 | } 216 | 217 | @Test 218 | public void testDisable() { 219 | // Test 220 | Printer.disable(); 221 | 222 | // Verify 223 | assertEquals("DISABLE\n", systemOutRule.getLog()); 224 | } 225 | 226 | } 227 | -------------------------------------------------------------------------------- /src/test/java/org/firehol/netdata/orchestrator/configuration/ConfigurationServiceTest.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.orchestrator.configuration; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | 7 | import java.io.File; 8 | import java.io.IOException; 9 | import java.nio.file.Files; 10 | 11 | import org.firehol.netdata.orchestrator.configuration.exception.ConfigurationSchemeInstantiationException; 12 | import org.firehol.netdata.orchestrator.configuration.schema.OrchestratorConfiguration; 13 | import org.junit.Before; 14 | import org.junit.Rule; 15 | import org.junit.Test; 16 | import org.junit.contrib.java.lang.system.EnvironmentVariables; 17 | import org.junit.rules.TemporaryFolder; 18 | 19 | public class ConfigurationServiceTest { 20 | 21 | // We cannot instantiate ConfigurationService here because it depends on an 22 | // environment Variable. 23 | 24 | @Rule 25 | public TemporaryFolder tmpFolder = new TemporaryFolder(); 26 | 27 | @Rule 28 | public final EnvironmentVariables environmentVariables = new EnvironmentVariables(); 29 | 30 | @Before 31 | public void setUp() { 32 | environmentVariables.set("NETDATA_CONFIG_DIR", tmpFolder.getRoot().toString()); 33 | } 34 | 35 | /** 36 | * Test reading valid {@code TestConfiguration} 37 | */ 38 | @Test 39 | public void testReadConfiguration() throws IOException, ConfigurationSchemeInstantiationException { 40 | // Object under test 41 | ConfigurationService configService = ConfigurationService.getInstance(); 42 | 43 | // Write a TestConfiguration to a temporary file. 44 | File testConfigurationFile = tmpFolder.newFile(); 45 | Files.write(testConfigurationFile.toPath(), "{ \"testProperty\": \"testValue\" }".getBytes()); 46 | 47 | // Test 48 | TestConfiguration testConfig = configService.readConfiguration(testConfigurationFile, TestConfiguration.class); 49 | 50 | // Verify 51 | assertEquals("testValue", testConfig.testProperty); 52 | } 53 | 54 | /** 55 | * Test reading invalid {@code TestConfiguration} 56 | */ 57 | @Test 58 | public void testReadConfigurationInvalid() throws IOException, ConfigurationSchemeInstantiationException { 59 | // Object under test 60 | ConfigurationService configService = ConfigurationService.getInstance(); 61 | 62 | // Write a TestConfiguration to a temporary file. 63 | File testConfigurationFile = tmpFolder.newFile(); 64 | Files.write(testConfigurationFile.toPath(), "{ \"noClassProperty\": \"testValue\" }".getBytes()); 65 | 66 | // Test 67 | TestConfiguration testConfig = configService.readConfiguration(testConfigurationFile, TestConfiguration.class); 68 | 69 | // Verify 70 | assertEquals("defaultValue", testConfig.testProperty); 71 | } 72 | 73 | /** 74 | * Test reading invalid {@code NoTestConfiguration} 75 | */ 76 | @Test(expected = ConfigurationSchemeInstantiationException.class) 77 | public void testReadConfigurationFailure() throws IOException, ConfigurationSchemeInstantiationException { 78 | // Object under test 79 | ConfigurationService configService = ConfigurationService.getInstance(); 80 | 81 | // Write a TestConfiguration to a temporary file. 82 | File testConfigurationFile = tmpFolder.newFile(); 83 | Files.write(testConfigurationFile.toPath(), "{ \"noClassProperty\": \"testValue\" }".getBytes()); 84 | 85 | // Test 86 | NoTestConfiguration testConfig = configService.readConfiguration(testConfigurationFile, 87 | NoTestConfiguration.class); 88 | 89 | // Verify 90 | assertEquals("defaultValue", testConfig.testProperty); 91 | } 92 | 93 | @Test 94 | public void testReadGlobalConfiguration() throws IOException, ConfigurationSchemeInstantiationException { 95 | // Object under test 96 | ConfigurationService configService = ConfigurationService.getInstance(); 97 | 98 | // Write a TestConfiguration to a temporary file. 99 | File testConfigurationFile = tmpFolder.newFile("java.d.conf"); 100 | Files.write(testConfigurationFile.toPath(), "{ }".getBytes()); 101 | 102 | // Test 103 | OrchestratorConfiguration testConfig = configService.readConfiguration(testConfigurationFile, 104 | OrchestratorConfiguration.class); 105 | 106 | // Verify 107 | assertEquals(OrchestratorConfiguration.class, testConfig.getClass()); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/test/java/org/firehol/netdata/orchestrator/configuration/EnvironmentConfigurationServiceTest.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.orchestrator.configuration; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | 7 | import java.nio.file.Path; 8 | import java.nio.file.Paths; 9 | 10 | import org.firehol.netdata.orchestrator.configuration.exception.EnvironmentConfigurationException; 11 | import org.junit.Rule; 12 | import org.junit.Test; 13 | import org.junit.contrib.java.lang.system.EnvironmentVariables; 14 | 15 | public class EnvironmentConfigurationServiceTest { 16 | 17 | @Rule 18 | public final EnvironmentVariables environmentVariables = new EnvironmentVariables(); 19 | 20 | @Test 21 | public void testReadNetdataConfigDir() throws EnvironmentConfigurationException { 22 | Path path = Paths.get("/test/folder"); 23 | environmentVariables.set("NETDATA_CONFIG_DIR", path.toString()); 24 | 25 | Path result = EnvironmentConfigurationService.getInstance().readNetdataConfigDir(); 26 | 27 | assertEquals(path, result); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/org/firehol/netdata/orchestrator/configuration/NoTestConfiguration.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.orchestrator.configuration; 4 | 5 | public class NoTestConfiguration { 6 | public String testProperty = "defaultValue"; 7 | 8 | /** 9 | * Don't let anyone instantiate this class. 10 | */ 11 | private NoTestConfiguration() { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/test/java/org/firehol/netdata/orchestrator/configuration/TestConfiguration.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.orchestrator.configuration; 4 | 5 | public class TestConfiguration { 6 | public String testProperty = "defaultValue"; 7 | } 8 | -------------------------------------------------------------------------------- /src/test/java/org/firehol/netdata/test/architecture/UtilsTest.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.test.architecture; 4 | 5 | import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes; 6 | 7 | import org.junit.Test; 8 | 9 | import com.tngtech.archunit.core.domain.JavaClasses; 10 | import com.tngtech.archunit.core.domain.JavaModifier; 11 | import com.tngtech.archunit.core.importer.ClassFileImporter; 12 | import com.tngtech.archunit.lang.ArchRule; 13 | 14 | public class UtilsTest { 15 | @Test 16 | public void testUtils() { 17 | JavaClasses importedClasses = new ClassFileImporter().importPackages("org.firehol"); 18 | 19 | final ArchRule rule = classes().that() 20 | .haveSimpleNameEndingWith("Utils") 21 | .should() 22 | .haveModifier(JavaModifier.FINAL) 23 | .andShould() 24 | .haveOnlyPrivateConstructors(); 25 | 26 | rule.check(importedClasses); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/org/firehol/netdata/testutils/ExitException.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.testutils; 4 | 5 | import lombok.Getter; 6 | 7 | @Getter 8 | public class ExitException extends SecurityException { 9 | private static final long serialVersionUID = 1000706666595954099L; 10 | 11 | private final int status; 12 | 13 | public ExitException(int status) { 14 | super(); 15 | this.status = status; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/java/org/firehol/netdata/testutils/NoExitSecurityManager.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.testutils; 4 | 5 | /** 6 | * A Security Manager that allowes everything but throws an ExitException on 7 | * calls to System.exit() 8 | * 9 | * @author Simon Nagl 10 | * 11 | */ 12 | public class NoExitSecurityManager extends SecurityManager { 13 | @Override 14 | public void checkExit(int status) { 15 | super.checkExit(status); 16 | throw new ExitException(status); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/org/firehol/netdata/testutils/ReflectionUtils.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.testutils; 4 | 5 | import java.lang.reflect.Field; 6 | 7 | public final class ReflectionUtils { 8 | 9 | private ReflectionUtils() { 10 | } 11 | 12 | /** 13 | * Getter for private field {@code filedName} of {@code object}. 14 | * 15 | * @param object 16 | * to access 17 | * @param fieldName 18 | * Name of field to read. 19 | * @return the value of the field. 20 | * @throws NoSuchFieldException 21 | * if a field with the specified name is not found 22 | * @throws IllegalAccessException 23 | * if this Field object is enforcing Java language access 24 | * control and the underlying field is inaccessible. 25 | * @throws SecurityException 26 | * If a security manager, s, is present and any of the 27 | * following conditions is met: 28 | *
    29 | *
  • the caller's class loader is not the same as the class 30 | * loader of this class and invocation of 31 | * {@link SecurityManager#checkPermission s.checkPermission} 32 | * method with 33 | * {@code RuntimePermission("accessDeclaredMembers")} denies 34 | * access to the declared field 35 | *
  • the caller's class loader is not the same as or an 36 | * ancestor of the class loader for the current class and 37 | * invocation of {@link SecurityManager#checkPackageAccess 38 | * s.checkPackageAccess()} denies access to the package of this 39 | * class 40 | *
  • if s denies making the field accessible. 41 | *
42 | */ 43 | public static Object getPrivateField(Object object, String fieldName) 44 | throws NoSuchFieldException, IllegalAccessException, SecurityException { 45 | Field field = object.getClass().getDeclaredField(fieldName); 46 | field.setAccessible(true); 47 | return field.get(object); 48 | } 49 | 50 | /** 51 | * Setter for private filed {@code filedName} of {@code object}. 52 | * 53 | * @param object 54 | * to modify 55 | * @param fieldName 56 | * Name of field to set. 57 | * @param value 58 | * to set 59 | * @throws NoSuchFieldException 60 | * if a field with the specified name is not found. 61 | * @throws NullPointerException 62 | * If any of the following conditions is met: 63 | *
    64 | *
  • if {@code filedName} is null
  • 65 | *
  • if the {@code object} is {@code null} and the field is an 66 | * instance field.
  • 67 | *
68 | * @throws SecurityException 69 | * If a security manager, s, is present and any of the 70 | * following conditions is met: 71 | * 72 | *
    73 | *
  • the caller's class loader is not the same as the class 74 | * loader of this class and invocation of 75 | * {@link SecurityManager#checkPermission s.checkPermission} 76 | * method with 77 | * {@code RuntimePermission("accessDeclaredMembers")} denies 78 | * access to the declared field 79 | *
  • the caller's class loader is not the same as or an 80 | * ancestor of the class loader for the current class and 81 | * invocation of {@link SecurityManager#checkPackageAccess 82 | * s.checkPackageAccess()} denies access to the package of this 83 | * class 84 | *
  • if s denies making the field accessible. 85 | *
86 | * @throws IllegalArgumentException 87 | * if the specified object is not an instance of the class or 88 | * interface declaring the underlying field (or a subclass or 89 | * implementor thereof), or if an unwrapping conversion fails. 90 | * @throws IllegalAccessException 91 | * if this Field object is enforcing Java language access 92 | * control and the underlying field is either inaccessible or 93 | * final. 94 | * @throws ExceptionInInitializerError 95 | * if the initialization provoked by this method fails. 96 | */ 97 | public static void setPrivateFiled(Object object, String fieldName, Object value) 98 | throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, 99 | NullPointerException, ExceptionInInitializerError { 100 | Field field = object.getClass().getDeclaredField(fieldName); 101 | field.setAccessible(true); 102 | field.set(object, value); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/test/java/org/firehol/netdata/testutils/TestObjectBuilder.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.testutils; 4 | 5 | import org.firehol.netdata.model.Chart; 6 | import org.firehol.netdata.model.ChartType; 7 | import org.firehol.netdata.model.Dimension; 8 | import org.firehol.netdata.module.jmx.configuration.JmxChartConfiguration; 9 | import org.firehol.netdata.module.jmx.configuration.JmxDimensionConfiguration; 10 | 11 | /** 12 | * Build standard Test Objects. 13 | * 14 | * A standard Test Object is a instance of a Class where all Properties are set: 15 | *
    16 | *
  • Properties with standard values get their standard values
  • 17 | *
  • String properties are set with the name of the property
  • 18 | *
  • For enum the most likely value is choosen.
  • 19 | *
  • Numbers are initialized with 1
  • 20 | *
  • Booleans get true
  • 21 | *
22 | * 23 | * @author Simon Nagl 24 | */ 25 | public abstract class TestObjectBuilder { 26 | public static Chart buildChart() { 27 | Chart chart = new Chart(); 28 | chart.setType("type"); 29 | chart.setId("id"); 30 | chart.setName("name"); 31 | chart.setTitle("title"); 32 | chart.setUnits("units"); 33 | chart.setFamily("family"); 34 | chart.setContext("context"); 35 | chart.setChartType(ChartType.LINE); 36 | return chart; 37 | } 38 | 39 | public static Dimension buildDimension() { 40 | Dimension dim = new Dimension(); 41 | dim.setId("id"); 42 | dim.setName("name"); 43 | dim.setHidden(true); 44 | dim.setCurrentValue(1L); 45 | return dim; 46 | } 47 | 48 | public static JmxChartConfiguration buildJmxChartConfiguration() { 49 | JmxChartConfiguration chartConfig = new JmxChartConfiguration(); 50 | chartConfig.setId("id"); 51 | chartConfig.setTitle("title"); 52 | chartConfig.setFamily("family"); 53 | chartConfig.setUnits("units"); 54 | return chartConfig; 55 | } 56 | 57 | public static JmxDimensionConfiguration buildJmxDimensionConfiguration() { 58 | JmxDimensionConfiguration dimensionConfig = new JmxDimensionConfiguration(); 59 | dimensionConfig.setFrom("from"); 60 | dimensionConfig.setValue("value"); 61 | dimensionConfig.setName("name"); 62 | return dimensionConfig; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/test/java/org/firehol/netdata/utils/AlignToTimeIntervalServiceTest.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.utils; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | 7 | import java.sql.Time; 8 | import java.util.concurrent.TimeUnit; 9 | 10 | import org.firehol.netdata.testutils.ReflectionUtils; 11 | import org.junit.Rule; 12 | import org.junit.Test; 13 | import org.junit.contrib.java.lang.system.SystemErrRule; 14 | 15 | public class AlignToTimeIntervalServiceTest { 16 | 17 | @Rule 18 | public final SystemErrRule systemErrRule = new SystemErrRule().enableLog(); 19 | 20 | @Test 21 | public void testAlignToTimeIntervalService() 22 | throws NoSuchFieldException, IllegalAccessException, SecurityException { 23 | 24 | // Test 25 | AlignToTimeIntervalService service = new AlignToTimeIntervalService(100, TimeUnit.NANOSECONDS); 26 | 27 | // Verify 28 | assertEquals(100L, ReflectionUtils.getPrivateField(service, "intervalInNSec")); 29 | } 30 | 31 | @Test 32 | public void testAlignToTimeIntervalServiceSeconds() 33 | throws NoSuchFieldException, IllegalAccessException, SecurityException { 34 | 35 | // Test 36 | AlignToTimeIntervalService service = new AlignToTimeIntervalService(100, TimeUnit.SECONDS); 37 | 38 | // Verify 39 | assertEquals(TimeUnit.SECONDS.toNanos(100), ReflectionUtils.getPrivateField(service, "intervalInNSec")); 40 | } 41 | 42 | @Test(timeout = 2000) 43 | // Just test it does not fail. 44 | public void testAlignToNextInterval() throws InterruptedException { 45 | // Build object under test 46 | AlignToTimeIntervalService service = new AlignToTimeIntervalService(UnitConversion.NANO_PER_PLAIN / 100, 47 | TimeUnit.NANOSECONDS); 48 | 49 | for (int i = 0; i < 100; i++) { 50 | service.alignToNextInterval(); 51 | } 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/test/java/org/firehol/netdata/utils/LoggingUtilsTest.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.utils; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | 7 | import java.util.function.Supplier; 8 | 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | 12 | public class LoggingUtilsTest { 13 | 14 | private Exception exception; 15 | 16 | @Before 17 | public void init() { 18 | Exception fine = new Exception("Here are the details."); 19 | Exception detail = new Exception("This is the reason.", fine); 20 | exception = new Exception("Something went wrong.", detail); 21 | } 22 | 23 | @Test 24 | public void testBuildMessageThrowable() { 25 | // Test 26 | String message = LoggingUtils.buildMessage(exception); 27 | 28 | // Verify 29 | assertEquals( 30 | "[java.lang.Exception] Something went wrong. Detail: This is the reason. Detail: Here are the details.", 31 | message); 32 | } 33 | 34 | @Test 35 | public void testBuildMessageStringThrowable() { 36 | // Test 37 | String message = LoggingUtils.buildMessage("Could not do it.", exception); 38 | 39 | // Verify 40 | assertEquals( 41 | "Could not do it. Reason: [java.lang.Exception] Something went wrong. Detail: This is the reason. Detail: Here are the details.", 42 | message); 43 | } 44 | 45 | @Test 46 | public void testBuildMessageStrings() { 47 | // Test 48 | String message = LoggingUtils.buildMessage("This ", "should ", "be ", "one ", "message."); 49 | 50 | // Verify 51 | assertEquals("This should be one message.", message); 52 | } 53 | 54 | @Test 55 | public void testBuildMessageStringsNoArg() { 56 | // Test 57 | String message = LoggingUtils.buildMessage(); 58 | 59 | // Verify 60 | assertEquals("", message); 61 | } 62 | 63 | @Test 64 | public void testBuildMessageStringsOneArg() { 65 | // Test 66 | String message = LoggingUtils.buildMessage("One Argument."); 67 | 68 | // Verify 69 | assertEquals("One Argument.", message); 70 | } 71 | 72 | @Test 73 | public void getMessageSupplierThrowable() { 74 | // Test 75 | Supplier messageSupplier = LoggingUtils.getMessageSupplier(exception); 76 | 77 | // Verify 78 | assertEquals( 79 | "[java.lang.Exception] Something went wrong. Detail: This is the reason. Detail: Here are the details.", 80 | messageSupplier.get()); 81 | } 82 | 83 | @Test 84 | public void getMessageSupplierStringThrowable() { 85 | // Test 86 | Supplier messageSupplier = LoggingUtils.getMessageSupplier("Could not do it.", exception); 87 | 88 | // Verify 89 | assertEquals( 90 | "Could not do it. Reason: [java.lang.Exception] Something went wrong. Detail: This is the reason. Detail: Here are the details.", 91 | messageSupplier.get()); 92 | 93 | } 94 | 95 | public void getMessageSuplierStrings() { 96 | // Test 97 | Supplier messageSupplier = LoggingUtils.getMessageSupplier("This ", "should ", "be ", "one ", 98 | "message."); 99 | 100 | // Verify 101 | assertEquals("This should be one message.", messageSupplier.get()); 102 | 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/test/java/org/firehol/netdata/utils/ResourceUtilsTest.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.utils; 4 | 5 | import static org.junit.Assert.assertFalse; 6 | import static org.junit.Assert.assertTrue; 7 | 8 | import java.io.Closeable; 9 | import java.io.IOException; 10 | import java.util.concurrent.CompletableFuture; 11 | import java.util.concurrent.ExecutionException; 12 | 13 | import org.junit.Test; 14 | 15 | public class ResourceUtilsTest { 16 | 17 | @Test 18 | public void testClose() throws InterruptedException, ExecutionException { 19 | 20 | // Static Objects 21 | Closeable resource = new Closeable() { 22 | @Override 23 | public void close() throws IOException { 24 | // Close with success. 25 | } 26 | }; 27 | 28 | // Test 29 | CompletableFuture result = ResourceUtils.close(resource); 30 | 31 | // Verify 32 | assertTrue(result.get()); 33 | } 34 | 35 | @Test 36 | public void testCloseFailure() throws InterruptedException, ExecutionException { 37 | 38 | // Static Objects 39 | Closeable resource = new Closeable() { 40 | @Override 41 | public void close() throws IOException { 42 | throw new IOException("Can not close resource"); 43 | } 44 | }; 45 | 46 | // Test 47 | CompletableFuture result = ResourceUtils.close(resource); 48 | 49 | // Verify 50 | assertFalse(result.get()); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/test/java/org/firehol/netdata/utils/StringUtilsTest.java: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | package org.firehol.netdata.utils; 4 | 5 | import static org.junit.Assert.assertFalse; 6 | import static org.junit.Assert.assertTrue; 7 | 8 | import org.junit.Test; 9 | 10 | public class StringUtilsTest { 11 | 12 | @Test 13 | public void testIsBlankNull() { 14 | assertTrue(StringUtils.isBlank(null)); 15 | } 16 | 17 | @Test 18 | public void testIsBlankEmpty() { 19 | assertTrue(StringUtils.isBlank("")); 20 | } 21 | 22 | @Test 23 | public void testIsBlankWhitespace() { 24 | assertTrue(StringUtils.isBlank(" ")); 25 | } 26 | 27 | @Test 28 | public void testIsBlankEmptyFilled() { 29 | assertFalse(StringUtils.isBlank("bob")); 30 | } 31 | 32 | @Test 33 | public void testIsBlankEmptyFilledWithWhitespace() { 34 | assertFalse(StringUtils.isBlank(" bob ")); 35 | } 36 | 37 | } 38 | --------------------------------------------------------------------------------