From 0106a7cd3042492c406d7a838865e29b2fba98f7 Mon Sep 17 00:00:00 2001 From: crusader Date: Wed, 13 Dec 2017 15:39:34 +0900 Subject: [PATCH] ing --- ..._ch_qos_logback_logback_classic_1_2_3.xml} | 8 +- ...en__ch_qos_logback_logback_core_1_2_3.xml} | 8 +- .../Maven__com_hynnet_jacob_1_18.xml | 13 + ...n__com_jayway_jsonpath_json_path_2_2_0.xml | 13 - ...rosoft_sqlserver_mssql_jdbc_6_2_2_jre8.xml | 13 + ...ogle_android_json_0_0_20131108_vaadin1.xml | 13 - .idea/libraries/Maven__log4j_log4j_1_2_14.xml | 13 + ...aven__mysql_mysql_connector_java_6_0_6.xml | 13 + ...Maven__net_minidev_accessors_smart_1_1.xml | 13 - .../Maven__net_minidev_json_smart_2_2_1.xml | 13 - ...org_apache_commons_commons_pool2_2_4_2.xml | 13 + .../Maven__org_assertj_assertj_core_2_6_0.xml | 13 - ...ven__org_hamcrest_hamcrest_library_1_3.xml | 13 - ...aven__org_mockito_mockito_core_1_10_19.xml | 13 - ...n__org_mongodb_mongo_java_driver_3_6_0.xml | 13 + .../Maven__org_objenesis_objenesis_2_1.xml | 13 - .../Maven__org_ow2_asm_asm_5_0_3.xml | 13 - ...aven__org_postgresql_postgresql_42_1_4.xml | 13 + ...aven__org_skyscreamer_jsonassert_1_4_0.xml | 13 - ...Maven__org_slf4j_jcl_over_slf4j_1_7_25.xml | 13 - .../Maven__org_slf4j_jul_to_slf4j_1_7_25.xml | 13 - ...ven__org_slf4j_log4j_over_slf4j_1_7_25.xml | 13 - .../Maven__org_snmp4j_snmp4j_2_5_8.xml | 13 + ...amework_boot_spring_boot_1_5_9_RELEASE.xml | 13 - ...pring_boot_autoconfigure_1_5_9_RELEASE.xml | 13 - ...boot_spring_boot_starter_1_5_9_RELEASE.xml | 13 - ...ing_boot_starter_logging_1_5_9_RELEASE.xml | 13 - ...spring_boot_starter_test_1_5_9_RELEASE.xml | 13 - ...rk_boot_spring_boot_test_1_5_9_RELEASE.xml | 13 - ..._boot_test_autoconfigure_1_5_9_RELEASE.xml | 13 - ...ingframework_spring_aop_4_3_13_RELEASE.xml | 13 - ...gframework_spring_beans_4_3_13_RELEASE.xml | 13 - ...ramework_spring_context_4_3_13_RELEASE.xml | 13 - ...ngframework_spring_core_4_3_13_RELEASE.xml | 13 - ...ework_spring_expression_4_3_13_RELEASE.xml | 13 - ...ngframework_spring_test_4_3_13_RELEASE.xml | 13 - .../Maven__org_yaml_snakeyaml_1_17.xml | 13 - .../Maven__redis_clients_jedis_2_9_0.xml | 13 + lib/jacob-1.18-x64.dll | Bin 0 -> 205312 bytes lib/jacob-1.18-x86.dll | Bin 0 -> 167936 bytes overflow_probe_container_general.iml | 42 +- pom.xml | 63 ++- .../overflow/probe/container/Application.java | 25 -- .../overflow/probe/container/Container.java | 12 + .../probe/container/crawler/Crawler.java | 60 +++ .../container/crawler/config/Config.java | 53 +++ .../container/crawler/config/Connection.java | 41 ++ .../container/crawler/config/Crawler.java | 22 + .../probe/container/crawler/config/Item.java | 35 ++ .../probe/container/crawler/config/Keys.java | 24 ++ .../container/crawler/config/MappingInfo.java | 44 ++ .../container/crawler/config/QueryInfo.java | 25 ++ .../container/crawler/config/Schedule.java | 14 + .../container/crawler/config/Target.java | 25 ++ .../impl/database/DatabaseCrawler.java | 78 ++++ .../impl/database/DatabaseMetaInfo.java | 11 + .../impl/database/mysql/MySQLCrawler.java | 13 + .../impl/database/oracle/OracleCrawler.java | 14 + .../postgresql/PostgreSQLCrawler.java | 13 + .../database/sqlserver/SQLServerCrawler.java | 13 + .../crawler/impl/jmx/JMXCrawler.java | 190 +++++++++ .../crawler/impl/mongodb/MongoDBCrawler.java | 88 ++++ .../crawler/impl/redis/RedisCralwer.java | 110 +++++ .../crawler/impl/snmp/SNMPCrawler.java | 309 ++++++++++++++ .../crawler/impl/snmp/version/SNMP.java | 82 ++++ .../crawler/impl/snmp/version/SNMPv2c.java | 63 +++ .../crawler/impl/snmp/version/SNMPv3.java | 148 +++++++ .../crawler/impl/wmi/WMICrawler.java | 74 ++++ .../crawler/impl/wmi/WMICrawlerLinux.java | 153 +++++++ .../crawler/impl/wmi/WMICrawlerOS.java | 47 +++ .../crawler/impl/wmi/WMICrawlerWindows.java | 254 +++++++++++ .../container/crawler/result/ResultSet.java | 75 ++++ .../crawler/result/ResultSetCol.java | 106 +++++ .../crawler/result/ResultSetRow.java | 104 +++++ .../SimpleInvoker.java} | 44 +- .../server/ContainerChannelInitializer.java | 11 +- .../server/ContainerConfiguration.java | 104 +++-- .../server/ContainerJSONHandler.java | 14 +- .../container/server/ContainerServer.java | 43 +- .../container/service/ConfigService.java | 27 ++ .../probe/container/service/DataService.java | 18 + .../probe/container/service/Service.java | 19 + .../probe/container/service/StateService.java | 15 + .../probe/container/ApplicationTests.java | 25 -- .../probe/container/crawler/CrawlerTest.java | 13 + .../impl/database/DatabaseCrawlerTest.java | 62 +++ .../impl/database/mysql/MySQLCrawlerTest.java | 15 + .../database/oracle/OracleCrawlerTest.java | 15 + .../postgresql/PostgreSQLCrawlerTest.java | 15 + .../sqlserver/SQLServerCrawlerTest.java | 22 + .../crawler/impl/jmx/JMXCrawlerTest.java | 6 + .../impl/jmx/tomcat/TomcatCrawlerTest.java | 65 +++ .../impl/mongodb/MongoDBCrawlerTest.java | 45 ++ .../crawler/impl/redis/RedisCralwerTest.java | 47 +++ .../crawler/impl/snmp/SNMPCrawlerTest.java | 79 ++++ .../crawler/impl/wmi/WMICrawlerTest.java | 313 ++++++++++++++ .../resources/config/mongodb/example.json | 43 ++ .../resources/config/mysql/mysql-test.json | 395 ++++++++++++++++++ src/test/resources/config/mysql/mysql.json | 44 ++ .../config/postgresql/postgresql.json | 36 ++ src/test/resources/config/redis/example.json | 67 +++ src/test/resources/config/snmp/examplev2.json | 38 ++ src/test/resources/config/snmp/examplev3.json | 42 ++ .../sqlserver/sqlserver_connection_count.json | 38 ++ .../sqlserver_multiple_key_array.json | 50 +++ src/test/resources/config/tomcat/example.json | 46 ++ .../resources/config/tomcat/example1.json | 130 ++++++ .../resources/config/tomcat/example2.json | 47 +++ .../resources/config/tomcat/generate1.json | 106 +++++ src/test/resources/config/wmi/example.json | 63 +++ .../resources/config/wmi/meta/meta_cpu.json | 49 +++ .../config/wmi/meta/meta_filesystem.json | 61 +++ .../config/wmi/meta/meta_memory.json | 53 +++ .../config/wmi/meta/meta_network.json | 53 +++ src/test/resources/config/wmi/test.json | 130 ++++++ 115 files changed, 4880 insertions(+), 542 deletions(-) rename .idea/libraries/{Maven__ch_qos_logback_logback_classic_1_1_11.xml => Maven__ch_qos_logback_logback_classic_1_2_3.xml} (59%) rename .idea/libraries/{Maven__ch_qos_logback_logback_core_1_1_11.xml => Maven__ch_qos_logback_logback_core_1_2_3.xml} (61%) create mode 100644 .idea/libraries/Maven__com_hynnet_jacob_1_18.xml delete mode 100644 .idea/libraries/Maven__com_jayway_jsonpath_json_path_2_2_0.xml create mode 100644 .idea/libraries/Maven__com_microsoft_sqlserver_mssql_jdbc_6_2_2_jre8.xml delete mode 100644 .idea/libraries/Maven__com_vaadin_external_google_android_json_0_0_20131108_vaadin1.xml create mode 100644 .idea/libraries/Maven__log4j_log4j_1_2_14.xml create mode 100644 .idea/libraries/Maven__mysql_mysql_connector_java_6_0_6.xml delete mode 100644 .idea/libraries/Maven__net_minidev_accessors_smart_1_1.xml delete mode 100644 .idea/libraries/Maven__net_minidev_json_smart_2_2_1.xml create mode 100644 .idea/libraries/Maven__org_apache_commons_commons_pool2_2_4_2.xml delete mode 100644 .idea/libraries/Maven__org_assertj_assertj_core_2_6_0.xml delete mode 100644 .idea/libraries/Maven__org_hamcrest_hamcrest_library_1_3.xml delete mode 100644 .idea/libraries/Maven__org_mockito_mockito_core_1_10_19.xml create mode 100644 .idea/libraries/Maven__org_mongodb_mongo_java_driver_3_6_0.xml delete mode 100644 .idea/libraries/Maven__org_objenesis_objenesis_2_1.xml delete mode 100644 .idea/libraries/Maven__org_ow2_asm_asm_5_0_3.xml create mode 100644 .idea/libraries/Maven__org_postgresql_postgresql_42_1_4.xml delete mode 100644 .idea/libraries/Maven__org_skyscreamer_jsonassert_1_4_0.xml delete mode 100644 .idea/libraries/Maven__org_slf4j_jcl_over_slf4j_1_7_25.xml delete mode 100644 .idea/libraries/Maven__org_slf4j_jul_to_slf4j_1_7_25.xml delete mode 100644 .idea/libraries/Maven__org_slf4j_log4j_over_slf4j_1_7_25.xml create mode 100644 .idea/libraries/Maven__org_snmp4j_snmp4j_2_5_8.xml delete mode 100644 .idea/libraries/Maven__org_springframework_boot_spring_boot_1_5_9_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_boot_spring_boot_autoconfigure_1_5_9_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_boot_spring_boot_starter_1_5_9_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_boot_spring_boot_starter_logging_1_5_9_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_boot_spring_boot_starter_test_1_5_9_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_boot_spring_boot_test_1_5_9_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_boot_spring_boot_test_autoconfigure_1_5_9_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_spring_aop_4_3_13_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_spring_beans_4_3_13_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_spring_context_4_3_13_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_spring_core_4_3_13_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_spring_expression_4_3_13_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_springframework_spring_test_4_3_13_RELEASE.xml delete mode 100644 .idea/libraries/Maven__org_yaml_snakeyaml_1_17.xml create mode 100644 .idea/libraries/Maven__redis_clients_jedis_2_9_0.xml create mode 100644 lib/jacob-1.18-x64.dll create mode 100644 lib/jacob-1.18-x86.dll delete mode 100644 src/main/java/com/loafle/overflow/probe/container/Application.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/Container.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/Crawler.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/config/Config.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/config/Connection.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/config/Crawler.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/config/Item.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/config/Keys.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/config/MappingInfo.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/config/QueryInfo.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/config/Schedule.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/config/Target.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/impl/database/DatabaseCrawler.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/impl/database/DatabaseMetaInfo.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/impl/database/mysql/MySQLCrawler.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/impl/database/oracle/OracleCrawler.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/impl/database/postgresql/PostgreSQLCrawler.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/impl/database/sqlserver/SQLServerCrawler.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/impl/jmx/JMXCrawler.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/impl/mongodb/MongoDBCrawler.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/impl/redis/RedisCralwer.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/impl/snmp/SNMPCrawler.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/impl/snmp/version/SNMP.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/impl/snmp/version/SNMPv2c.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/impl/snmp/version/SNMPv3.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/impl/wmi/WMICrawler.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/impl/wmi/WMICrawlerLinux.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/impl/wmi/WMICrawlerOS.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/impl/wmi/WMICrawlerWindows.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/result/ResultSet.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/result/ResultSetCol.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/crawler/result/ResultSetRow.java rename src/main/java/com/loafle/overflow/probe/container/rpc/invoker/{spring/SpringInvoker.java => impl/SimpleInvoker.java} (81%) create mode 100644 src/main/java/com/loafle/overflow/probe/container/service/ConfigService.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/service/DataService.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/service/Service.java create mode 100644 src/main/java/com/loafle/overflow/probe/container/service/StateService.java delete mode 100644 src/test/java/com/loafle/overflow/probe/container/ApplicationTests.java create mode 100644 src/test/java/com/loafle/overflow/probe/container/crawler/CrawlerTest.java create mode 100644 src/test/java/com/loafle/overflow/probe/container/crawler/impl/database/DatabaseCrawlerTest.java create mode 100644 src/test/java/com/loafle/overflow/probe/container/crawler/impl/database/mysql/MySQLCrawlerTest.java create mode 100644 src/test/java/com/loafle/overflow/probe/container/crawler/impl/database/oracle/OracleCrawlerTest.java create mode 100644 src/test/java/com/loafle/overflow/probe/container/crawler/impl/database/postgresql/PostgreSQLCrawlerTest.java create mode 100644 src/test/java/com/loafle/overflow/probe/container/crawler/impl/database/sqlserver/SQLServerCrawlerTest.java create mode 100644 src/test/java/com/loafle/overflow/probe/container/crawler/impl/jmx/JMXCrawlerTest.java create mode 100644 src/test/java/com/loafle/overflow/probe/container/crawler/impl/jmx/tomcat/TomcatCrawlerTest.java create mode 100644 src/test/java/com/loafle/overflow/probe/container/crawler/impl/mongodb/MongoDBCrawlerTest.java create mode 100644 src/test/java/com/loafle/overflow/probe/container/crawler/impl/redis/RedisCralwerTest.java create mode 100644 src/test/java/com/loafle/overflow/probe/container/crawler/impl/snmp/SNMPCrawlerTest.java create mode 100644 src/test/java/com/loafle/overflow/probe/container/crawler/impl/wmi/WMICrawlerTest.java create mode 100644 src/test/resources/config/mongodb/example.json create mode 100644 src/test/resources/config/mysql/mysql-test.json create mode 100644 src/test/resources/config/mysql/mysql.json create mode 100644 src/test/resources/config/postgresql/postgresql.json create mode 100644 src/test/resources/config/redis/example.json create mode 100644 src/test/resources/config/snmp/examplev2.json create mode 100644 src/test/resources/config/snmp/examplev3.json create mode 100644 src/test/resources/config/sqlserver/sqlserver_connection_count.json create mode 100644 src/test/resources/config/sqlserver/sqlserver_multiple_key_array.json create mode 100644 src/test/resources/config/tomcat/example.json create mode 100644 src/test/resources/config/tomcat/example1.json create mode 100644 src/test/resources/config/tomcat/example2.json create mode 100644 src/test/resources/config/tomcat/generate1.json create mode 100644 src/test/resources/config/wmi/example.json create mode 100644 src/test/resources/config/wmi/meta/meta_cpu.json create mode 100644 src/test/resources/config/wmi/meta/meta_filesystem.json create mode 100644 src/test/resources/config/wmi/meta/meta_memory.json create mode 100644 src/test/resources/config/wmi/meta/meta_network.json create mode 100644 src/test/resources/config/wmi/test.json diff --git a/.idea/libraries/Maven__ch_qos_logback_logback_classic_1_1_11.xml b/.idea/libraries/Maven__ch_qos_logback_logback_classic_1_2_3.xml similarity index 59% rename from .idea/libraries/Maven__ch_qos_logback_logback_classic_1_1_11.xml rename to .idea/libraries/Maven__ch_qos_logback_logback_classic_1_2_3.xml index c6ea67e..6fec8f4 100644 --- a/.idea/libraries/Maven__ch_qos_logback_logback_classic_1_1_11.xml +++ b/.idea/libraries/Maven__ch_qos_logback_logback_classic_1_2_3.xml @@ -1,13 +1,13 @@ - + - + - + - + \ No newline at end of file diff --git a/.idea/libraries/Maven__ch_qos_logback_logback_core_1_1_11.xml b/.idea/libraries/Maven__ch_qos_logback_logback_core_1_2_3.xml similarity index 61% rename from .idea/libraries/Maven__ch_qos_logback_logback_core_1_1_11.xml rename to .idea/libraries/Maven__ch_qos_logback_logback_core_1_2_3.xml index f538e36..9eb8596 100644 --- a/.idea/libraries/Maven__ch_qos_logback_logback_core_1_1_11.xml +++ b/.idea/libraries/Maven__ch_qos_logback_logback_core_1_2_3.xml @@ -1,13 +1,13 @@ - + - + - + - + \ No newline at end of file diff --git a/.idea/libraries/Maven__com_hynnet_jacob_1_18.xml b/.idea/libraries/Maven__com_hynnet_jacob_1_18.xml new file mode 100644 index 0000000..1362ca2 --- /dev/null +++ b/.idea/libraries/Maven__com_hynnet_jacob_1_18.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__com_jayway_jsonpath_json_path_2_2_0.xml b/.idea/libraries/Maven__com_jayway_jsonpath_json_path_2_2_0.xml deleted file mode 100644 index 578b079..0000000 --- a/.idea/libraries/Maven__com_jayway_jsonpath_json_path_2_2_0.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__com_microsoft_sqlserver_mssql_jdbc_6_2_2_jre8.xml b/.idea/libraries/Maven__com_microsoft_sqlserver_mssql_jdbc_6_2_2_jre8.xml new file mode 100644 index 0000000..c205dec --- /dev/null +++ b/.idea/libraries/Maven__com_microsoft_sqlserver_mssql_jdbc_6_2_2_jre8.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__com_vaadin_external_google_android_json_0_0_20131108_vaadin1.xml b/.idea/libraries/Maven__com_vaadin_external_google_android_json_0_0_20131108_vaadin1.xml deleted file mode 100644 index b8581a6..0000000 --- a/.idea/libraries/Maven__com_vaadin_external_google_android_json_0_0_20131108_vaadin1.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__log4j_log4j_1_2_14.xml b/.idea/libraries/Maven__log4j_log4j_1_2_14.xml new file mode 100644 index 0000000..2825a67 --- /dev/null +++ b/.idea/libraries/Maven__log4j_log4j_1_2_14.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__mysql_mysql_connector_java_6_0_6.xml b/.idea/libraries/Maven__mysql_mysql_connector_java_6_0_6.xml new file mode 100644 index 0000000..10e7222 --- /dev/null +++ b/.idea/libraries/Maven__mysql_mysql_connector_java_6_0_6.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__net_minidev_accessors_smart_1_1.xml b/.idea/libraries/Maven__net_minidev_accessors_smart_1_1.xml deleted file mode 100644 index 88d626e..0000000 --- a/.idea/libraries/Maven__net_minidev_accessors_smart_1_1.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__net_minidev_json_smart_2_2_1.xml b/.idea/libraries/Maven__net_minidev_json_smart_2_2_1.xml deleted file mode 100644 index 6c692c8..0000000 --- a/.idea/libraries/Maven__net_minidev_json_smart_2_2_1.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_apache_commons_commons_pool2_2_4_2.xml b/.idea/libraries/Maven__org_apache_commons_commons_pool2_2_4_2.xml new file mode 100644 index 0000000..2970b5e --- /dev/null +++ b/.idea/libraries/Maven__org_apache_commons_commons_pool2_2_4_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_assertj_assertj_core_2_6_0.xml b/.idea/libraries/Maven__org_assertj_assertj_core_2_6_0.xml deleted file mode 100644 index 58bdc9a..0000000 --- a/.idea/libraries/Maven__org_assertj_assertj_core_2_6_0.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_hamcrest_hamcrest_library_1_3.xml b/.idea/libraries/Maven__org_hamcrest_hamcrest_library_1_3.xml deleted file mode 100644 index 78dbe45..0000000 --- a/.idea/libraries/Maven__org_hamcrest_hamcrest_library_1_3.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_mockito_mockito_core_1_10_19.xml b/.idea/libraries/Maven__org_mockito_mockito_core_1_10_19.xml deleted file mode 100644 index a523703..0000000 --- a/.idea/libraries/Maven__org_mockito_mockito_core_1_10_19.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_mongodb_mongo_java_driver_3_6_0.xml b/.idea/libraries/Maven__org_mongodb_mongo_java_driver_3_6_0.xml new file mode 100644 index 0000000..7935f5c --- /dev/null +++ b/.idea/libraries/Maven__org_mongodb_mongo_java_driver_3_6_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_objenesis_objenesis_2_1.xml b/.idea/libraries/Maven__org_objenesis_objenesis_2_1.xml deleted file mode 100644 index 7ab319b..0000000 --- a/.idea/libraries/Maven__org_objenesis_objenesis_2_1.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_ow2_asm_asm_5_0_3.xml b/.idea/libraries/Maven__org_ow2_asm_asm_5_0_3.xml deleted file mode 100644 index da69f6c..0000000 --- a/.idea/libraries/Maven__org_ow2_asm_asm_5_0_3.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_postgresql_postgresql_42_1_4.xml b/.idea/libraries/Maven__org_postgresql_postgresql_42_1_4.xml new file mode 100644 index 0000000..9e59f23 --- /dev/null +++ b/.idea/libraries/Maven__org_postgresql_postgresql_42_1_4.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_skyscreamer_jsonassert_1_4_0.xml b/.idea/libraries/Maven__org_skyscreamer_jsonassert_1_4_0.xml deleted file mode 100644 index f86d2c8..0000000 --- a/.idea/libraries/Maven__org_skyscreamer_jsonassert_1_4_0.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_slf4j_jcl_over_slf4j_1_7_25.xml b/.idea/libraries/Maven__org_slf4j_jcl_over_slf4j_1_7_25.xml deleted file mode 100644 index bae9949..0000000 --- a/.idea/libraries/Maven__org_slf4j_jcl_over_slf4j_1_7_25.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_slf4j_jul_to_slf4j_1_7_25.xml b/.idea/libraries/Maven__org_slf4j_jul_to_slf4j_1_7_25.xml deleted file mode 100644 index 6073e53..0000000 --- a/.idea/libraries/Maven__org_slf4j_jul_to_slf4j_1_7_25.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_slf4j_log4j_over_slf4j_1_7_25.xml b/.idea/libraries/Maven__org_slf4j_log4j_over_slf4j_1_7_25.xml deleted file mode 100644 index a14ac63..0000000 --- a/.idea/libraries/Maven__org_slf4j_log4j_over_slf4j_1_7_25.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_snmp4j_snmp4j_2_5_8.xml b/.idea/libraries/Maven__org_snmp4j_snmp4j_2_5_8.xml new file mode 100644 index 0000000..6db16f5 --- /dev/null +++ b/.idea/libraries/Maven__org_snmp4j_snmp4j_2_5_8.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_1_5_9_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_1_5_9_RELEASE.xml deleted file mode 100644 index 44dc419..0000000 --- a/.idea/libraries/Maven__org_springframework_boot_spring_boot_1_5_9_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_autoconfigure_1_5_9_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_autoconfigure_1_5_9_RELEASE.xml deleted file mode 100644 index 4c3a2b7..0000000 --- a/.idea/libraries/Maven__org_springframework_boot_spring_boot_autoconfigure_1_5_9_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_1_5_9_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_1_5_9_RELEASE.xml deleted file mode 100644 index c6ba5e1..0000000 --- a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_1_5_9_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_logging_1_5_9_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_logging_1_5_9_RELEASE.xml deleted file mode 100644 index 33c0b1c..0000000 --- a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_logging_1_5_9_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_test_1_5_9_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_test_1_5_9_RELEASE.xml deleted file mode 100644 index d7db397..0000000 --- a/.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_test_1_5_9_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_test_1_5_9_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_test_1_5_9_RELEASE.xml deleted file mode 100644 index 9312efe..0000000 --- a/.idea/libraries/Maven__org_springframework_boot_spring_boot_test_1_5_9_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_boot_spring_boot_test_autoconfigure_1_5_9_RELEASE.xml b/.idea/libraries/Maven__org_springframework_boot_spring_boot_test_autoconfigure_1_5_9_RELEASE.xml deleted file mode 100644 index 07d7bca..0000000 --- a/.idea/libraries/Maven__org_springframework_boot_spring_boot_test_autoconfigure_1_5_9_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_spring_aop_4_3_13_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_aop_4_3_13_RELEASE.xml deleted file mode 100644 index e06e71e..0000000 --- a/.idea/libraries/Maven__org_springframework_spring_aop_4_3_13_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_spring_beans_4_3_13_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_beans_4_3_13_RELEASE.xml deleted file mode 100644 index 0a8cafe..0000000 --- a/.idea/libraries/Maven__org_springframework_spring_beans_4_3_13_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_spring_context_4_3_13_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_context_4_3_13_RELEASE.xml deleted file mode 100644 index 8050852..0000000 --- a/.idea/libraries/Maven__org_springframework_spring_context_4_3_13_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_spring_core_4_3_13_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_core_4_3_13_RELEASE.xml deleted file mode 100644 index b95dd78..0000000 --- a/.idea/libraries/Maven__org_springframework_spring_core_4_3_13_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_spring_expression_4_3_13_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_expression_4_3_13_RELEASE.xml deleted file mode 100644 index 7a825ff..0000000 --- a/.idea/libraries/Maven__org_springframework_spring_expression_4_3_13_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_springframework_spring_test_4_3_13_RELEASE.xml b/.idea/libraries/Maven__org_springframework_spring_test_4_3_13_RELEASE.xml deleted file mode 100644 index 0c0fcbf..0000000 --- a/.idea/libraries/Maven__org_springframework_spring_test_4_3_13_RELEASE.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_yaml_snakeyaml_1_17.xml b/.idea/libraries/Maven__org_yaml_snakeyaml_1_17.xml deleted file mode 100644 index 20e2920..0000000 --- a/.idea/libraries/Maven__org_yaml_snakeyaml_1_17.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__redis_clients_jedis_2_9_0.xml b/.idea/libraries/Maven__redis_clients_jedis_2_9_0.xml new file mode 100644 index 0000000..77144ff --- /dev/null +++ b/.idea/libraries/Maven__redis_clients_jedis_2_9_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/jacob-1.18-x64.dll b/lib/jacob-1.18-x64.dll new file mode 100644 index 0000000000000000000000000000000000000000..b09c6335ebd4d3087268a1c012515819c455149f GIT binary patch literal 205312 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

^4?S;!0)MIj7m>a_mrLs?F7ZKB7(aI`->8 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 L{`c{Jtq1-W3=yMk literal 0 HcmV?d00001 diff --git a/lib/jacob-1.18-x86.dll b/lib/jacob-1.18-x86.dll new file mode 100644 index 0000000000000000000000000000000000000000..a53cc77b1349033004f6c9d3fff05539344d2cae GIT binary patch literal 167936 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�@GpW3^Fjst!$RrhX3bR73> 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 - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + - - - - - - - + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 83ead1b..1f4dd57 100644 --- a/pom.xml +++ b/pom.xml @@ -5,9 +5,8 @@ com.loafle - maven_parent_spring_boot - 1.5.9-RELEASE - + maven_parent_jar + 1.0.0-RELEASE com.loafle.overflow @@ -21,6 +20,18 @@ 4.1.17.Final 2.9.2 + + 6.0.6 + 42.1.4 + 6.2.2.jre8 + + 1.18 + + 2.9.0 + + 3.6.0 + + 2.5.8 @@ -40,6 +51,52 @@ ${jackson.version} + + + mysql + mysql-connector-java + ${mysql-connector-java.version} + + + + org.postgresql + postgresql + ${postgresql.version} + + + + com.microsoft.sqlserver + mssql-jdbc + ${mssql-jdbc.version} + + + + + com.hynnet + jacob + ${jacob.version} + + + + + redis.clients + jedis + ${jedis.version} + + + + + org.mongodb + mongo-java-driver + ${mongo-java-driver.version} + + + + + org.snmp4j + snmp4j + ${snmp4j.version} + \ No newline at end of file diff --git a/src/main/java/com/loafle/overflow/probe/container/Application.java b/src/main/java/com/loafle/overflow/probe/container/Application.java deleted file mode 100644 index 1763122..0000000 --- a/src/main/java/com/loafle/overflow/probe/container/Application.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.loafle.overflow.probe.container; - -import com.loafle.overflow.probe.container.server.ContainerServer; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.Banner; -import org.springframework.boot.CommandLineRunner; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class Application implements CommandLineRunner { - @Autowired - private ContainerServer containerServer; - - @Override - public void run(String... strings) throws Exception { - containerServer.start(); - } - - public static void main(String[] args) { - SpringApplication app = new SpringApplication(Application.class); - app.setBannerMode(Banner.Mode.OFF); - app.run(args); - } -} diff --git a/src/main/java/com/loafle/overflow/probe/container/Container.java b/src/main/java/com/loafle/overflow/probe/container/Container.java new file mode 100644 index 0000000..2d40adb --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/Container.java @@ -0,0 +1,12 @@ +package com.loafle.overflow.probe.container; + +import com.loafle.overflow.probe.container.server.ContainerServer; + +public class Container { + + public static void main(String[] args) throws Exception { + ContainerServer server = new ContainerServer(); + + server.start(); + } +} diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/Crawler.java b/src/main/java/com/loafle/overflow/probe/container/crawler/Crawler.java new file mode 100644 index 0000000..b26faf9 --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/Crawler.java @@ -0,0 +1,60 @@ +package com.loafle.overflow.probe.container.crawler; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.loafle.overflow.probe.container.crawler.config.Config; +import com.loafle.overflow.probe.container.crawler.result.ResultSet; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public abstract class Crawler { + protected ObjectMapper objectMapper; + private Map configs; + private String configPath; + + protected Crawler() { + objectMapper = new ObjectMapper(); + } + + public Config getConfig(String id) throws Exception { + return configs.get(id); + } + + public void putConfig(String id, Config config) throws Exception { + if (configs == null) { + configs = new HashMap<>(); + } + configs.put(id, config); + } + + public boolean add(Config config) throws Exception { + this.putConfig(config.getId(), config); + return true; + } + + public List get(String id) throws Exception { + + List rsList = (List)getInternal(getConfig(id)); + + return rsList; + } + + public boolean init(Config config) throws Exception { + add(config); + return true; + } + + public boolean remove(String id) throws Exception { + this.configs.remove(id); + return true; + } + + public abstract String name(); + public abstract List getInternal(Config c) throws Exception; + + public Object getInternalMeta(Config c) throws Exception { + return null; + } +} + diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/config/Config.java b/src/main/java/com/loafle/overflow/probe/container/crawler/config/Config.java new file mode 100644 index 0000000..0caa4a6 --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/config/Config.java @@ -0,0 +1,53 @@ +package com.loafle.overflow.probe.container.crawler.config; + +import java.util.List; + +public class Config { + + private String id; + private Target target; + private Schedule schedule; + private Crawler crawler; + private List items; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public Target getTarget() { + return target; + } + + public void setTarget(Target target) { + this.target = target; + } + + public Schedule getSchedule() { + return schedule; + } + + public void setSchedule(Schedule schedule) { + this.schedule = schedule; + } + + public Crawler getCrawler() { + return crawler; + } + + public void setCrawler(Crawler crawler) { + this.crawler = crawler; + } + + public List getItems() { + return items; + } + + public void setItems(List items) { + this.items = items; + } +} + diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/config/Connection.java b/src/main/java/com/loafle/overflow/probe/container/crawler/config/Connection.java new file mode 100644 index 0000000..8d1a13b --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/config/Connection.java @@ -0,0 +1,41 @@ +package com.loafle.overflow.probe.container.crawler.config; + +public class Connection { + private String ip; + private String port; + private String portType; + private boolean ssl; + + public String getIp() { + return ip; + } + + public void setIp(String ip) { + this.ip = ip; + } + + public String getPort() { + return port; + } + + public void setPort(String port) { + this.port = port; + } + + public String getPortType() { + return portType; + } + + public void setPortType(String portType) { + this.portType = portType; + } + + public boolean isSsl() { + return ssl; + } + + public void setSsl(boolean ssl) { + this.ssl = ssl; + } +} + diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/config/Crawler.java b/src/main/java/com/loafle/overflow/probe/container/crawler/config/Crawler.java new file mode 100644 index 0000000..645f63d --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/config/Crawler.java @@ -0,0 +1,22 @@ +package com.loafle.overflow.probe.container.crawler.config; + +public class Crawler { + private String name; + private String container; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getContainer() { + return container; + } + + public void setContainer(String container) { + this.container = container; + } +} diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/config/Item.java b/src/main/java/com/loafle/overflow/probe/container/crawler/config/Item.java new file mode 100644 index 0000000..2ea58b0 --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/config/Item.java @@ -0,0 +1,35 @@ +package com.loafle.overflow.probe.container.crawler.config; + +import java.util.List; + +public class Item { + + private List keys; + private QueryInfo queryInfo; + private MappingInfo mappingInfo; + + public List getKeys() { + return keys; + } + + public void setKeys(List keys) { + this.keys = keys; + } + + public QueryInfo getQueryInfo() { + return queryInfo; + } + + public void setQueryInfo(QueryInfo queryInfo) { + this.queryInfo = queryInfo; + } + + public MappingInfo getMappingInfo() { + return mappingInfo; + } + + public void setMappingInfo(MappingInfo mappingInfo) { + this.mappingInfo = mappingInfo; + } +} + diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/config/Keys.java b/src/main/java/com/loafle/overflow/probe/container/crawler/config/Keys.java new file mode 100644 index 0000000..f42b0a9 --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/config/Keys.java @@ -0,0 +1,24 @@ +package com.loafle.overflow.probe.container.crawler.config; + +public class Keys { + + private String metric; + private String key; + + public String getMetric() { + return metric; + } + + public void setMetric(String metric) { + this.metric = metric; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } +} + diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/config/MappingInfo.java b/src/main/java/com/loafle/overflow/probe/container/crawler/config/MappingInfo.java new file mode 100644 index 0000000..faff14d --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/config/MappingInfo.java @@ -0,0 +1,44 @@ +package com.loafle.overflow.probe.container.crawler.config; + +import java.util.List; + +public class MappingInfo { + + private String parseDirection; + private List arrayColumns; + private List keyColumns; + private String valueColumn; + + public String getParseDirection() { + return parseDirection; + } + + public void setParseDirection(String parseDirection) { + this.parseDirection = parseDirection; + } + + public List getArrayColumns() { + return arrayColumns; + } + + public void setArrayColumns(List arrayColumns) { + this.arrayColumns = arrayColumns; + } + + public List getKeyColumns() { + return keyColumns; + } + + public void setKeyColumns(List keyColumns) { + this.keyColumns = keyColumns; + } + + public String getValueColumn() { + return valueColumn; + } + + public void setValueColumn(String valueColumn) { + this.valueColumn = valueColumn; + } +} + diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/config/QueryInfo.java b/src/main/java/com/loafle/overflow/probe/container/crawler/config/QueryInfo.java new file mode 100644 index 0000000..5ebda72 --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/config/QueryInfo.java @@ -0,0 +1,25 @@ +package com.loafle.overflow.probe.container.crawler.config; + +import java.util.Map; + +public class QueryInfo { + private String query; + private Map extend; + + public String getQuery() { + return query; + } + + public void setQuery(String query) { + this.query = query; + } + + public Map getExtend() { + return extend; + } + + public void setExtend(Map extend) { + this.extend = extend; + } +} + diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/config/Schedule.java b/src/main/java/com/loafle/overflow/probe/container/crawler/config/Schedule.java new file mode 100644 index 0000000..96f1587 --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/config/Schedule.java @@ -0,0 +1,14 @@ +package com.loafle.overflow.probe.container.crawler.config; + +public class Schedule { + private String interval; + + public String getInterval() { + return interval; + } + + public void setInterval(String interval) { + this.interval = interval; + } +} + diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/config/Target.java b/src/main/java/com/loafle/overflow/probe/container/crawler/config/Target.java new file mode 100644 index 0000000..a03199a --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/config/Target.java @@ -0,0 +1,25 @@ +package com.loafle.overflow.probe.container.crawler.config; + +import java.util.Map; + +public class Target { + private Map auth; + private Connection connection; + + public Map getAuth() { + return auth; + } + + public void setAuth(Map auth) { + this.auth = auth; + } + + public Connection getConnection() { + return connection; + } + + public void setConnection(Connection connection) { + this.connection = connection; + } +} + diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/impl/database/DatabaseCrawler.java b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/database/DatabaseCrawler.java new file mode 100644 index 0000000..b34fbb3 --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/database/DatabaseCrawler.java @@ -0,0 +1,78 @@ +package com.loafle.overflow.probe.container.crawler.impl.database; + +import com.loafle.overflow.probe.container.crawler.Crawler; +import com.loafle.overflow.probe.container.crawler.config.Config; +import com.loafle.overflow.probe.container.crawler.config.Item; +import com.loafle.overflow.probe.container.crawler.result.ResultSet; +import com.loafle.overflow.probe.container.crawler.result.ResultSetRow; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +public abstract class DatabaseCrawler extends Crawler { + + public DatabaseCrawler() { + } + + @Override + public List getInternal(Config config) throws Exception { + return getMetrics(config); + } + + private List getMetrics(Config config) throws Exception { + + Connection conn = null; + Statement stmt = null; + java.sql.ResultSet rs = null; + + String url = (String)config.getTarget().getAuth().get("url"); + String id = (String)config.getTarget().getAuth().get("id"); + String pw = (String)config.getTarget().getAuth().get("pw"); + + loadDriverClass(); + + List resultSets = new ArrayList<>(); + + try { + conn = java.sql.DriverManager.getConnection(url, id, pw); + stmt = conn.createStatement(); + + for (Item item : config.getItems()) { + + ResultSet resultSet = ResultSetRow.newInstance(item); + Map meta = resultSet.getMeta(); + + rs = stmt.executeQuery((String)item.getQueryInfo().getQuery()); + + while(rs.next()) { + List row = new ArrayList<>(Arrays.asList(new String[meta.size()])); + for (Map.Entry info : meta.entrySet()) { + String data = rs.getString(info.getKey()); + data = data.trim(); + row.set(info.getValue().intValue(),data); + } + resultSet.addRow(row); + } + + resultSets.add(resultSet); + rs.close(); + } + return resultSets; + + } catch (Exception e) { + throw e; + } finally { + if (conn != null) {try {conn.close();} catch (SQLException e) {e.printStackTrace();}} + if (rs != null) {try {rs.close();} catch (SQLException e) {e.printStackTrace();}} + if (stmt != null) {try {stmt.close();} catch (SQLException e) {e.printStackTrace();}} + } + } + + protected abstract void loadDriverClass() throws ClassNotFoundException; + +} diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/impl/database/DatabaseMetaInfo.java b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/database/DatabaseMetaInfo.java new file mode 100644 index 0000000..4e3d8f0 --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/database/DatabaseMetaInfo.java @@ -0,0 +1,11 @@ +package com.loafle.overflow.probe.container.crawler.impl.database; + +public class DatabaseMetaInfo { + private String name; + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } +} diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/impl/database/mysql/MySQLCrawler.java b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/database/mysql/MySQLCrawler.java new file mode 100644 index 0000000..0d5f5c5 --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/database/mysql/MySQLCrawler.java @@ -0,0 +1,13 @@ +package com.loafle.overflow.probe.container.crawler.impl.database.mysql; + +import com.loafle.overflow.probe.container.crawler.impl.database.DatabaseCrawler; + +public class MySQLCrawler extends DatabaseCrawler { + public String name() { + return "MYSQL_CRAWLER"; + } + + protected void loadDriverClass() throws ClassNotFoundException { + Class.forName("com.mysql.cj.jdbc.Driver"); + } +} diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/impl/database/oracle/OracleCrawler.java b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/database/oracle/OracleCrawler.java new file mode 100644 index 0000000..8ac3aaf --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/database/oracle/OracleCrawler.java @@ -0,0 +1,14 @@ +package com.loafle.overflow.probe.container.crawler.impl.database.oracle; + +import com.loafle.overflow.probe.container.crawler.impl.database.DatabaseCrawler; + +public class OracleCrawler extends DatabaseCrawler { + public String name() { + return "ORACLE_CRAWLER"; + } + + @Override + protected void loadDriverClass() throws ClassNotFoundException { + Class.forName("oracle.jdbc.driver.OracleDriver"); + } +} diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/impl/database/postgresql/PostgreSQLCrawler.java b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/database/postgresql/PostgreSQLCrawler.java new file mode 100644 index 0000000..9271808 --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/database/postgresql/PostgreSQLCrawler.java @@ -0,0 +1,13 @@ +package com.loafle.overflow.probe.container.crawler.impl.database.postgresql; + +import com.loafle.overflow.probe.container.crawler.impl.database.DatabaseCrawler; + +public class PostgreSQLCrawler extends DatabaseCrawler { + public String name() { + return "POSTGRESQL_CRAWLER"; + } + + protected void loadDriverClass() throws ClassNotFoundException { + Class.forName("org.postgresql.Driver"); + } +} diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/impl/database/sqlserver/SQLServerCrawler.java b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/database/sqlserver/SQLServerCrawler.java new file mode 100644 index 0000000..6609031 --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/database/sqlserver/SQLServerCrawler.java @@ -0,0 +1,13 @@ +package com.loafle.overflow.probe.container.crawler.impl.database.sqlserver; + +import com.loafle.overflow.probe.container.crawler.impl.database.DatabaseCrawler; + +public class SQLServerCrawler extends DatabaseCrawler { + public String name() { + return "SQLSERVER_CRAWLER"; + } + + protected void loadDriverClass() throws ClassNotFoundException { + Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); + } +} diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/impl/jmx/JMXCrawler.java b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/jmx/JMXCrawler.java new file mode 100644 index 0000000..a5ad30e --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/jmx/JMXCrawler.java @@ -0,0 +1,190 @@ +package com.loafle.overflow.probe.container.crawler.impl.jmx; + +import com.loafle.overflow.probe.container.crawler.Crawler; +import com.loafle.overflow.probe.container.crawler.config.Config; +import com.loafle.overflow.probe.container.crawler.config.Item; +import com.loafle.overflow.probe.container.crawler.result.ResultSet; + +import javax.management.*; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; +import javax.management.remote.rmi.RMIConnectorServer; +import javax.naming.Context; +import javax.rmi.ssl.SslRMIClientSocketFactory; +import java.io.IOException; +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class JMXCrawler extends Crawler { + private static final Logger logger = Logger.getLogger(JMXCrawler.class.getName()); + + private String jmxUrl; + private String username; + private String password; + private boolean ssl; + + public JMXCrawler() {} + + public String name() { + return "JMX_CRAWLER"; + } + + private List parse(Map dataMap, Map meta) { + + List row = new ArrayList<>(Arrays.asList(new String[meta.size()])); + for (Map.Entry info : meta.entrySet()) { + String data = dataMap.get(info.getKey()); + data = data.trim(); + row.set(info.getValue().intValue(),data); + } + return row; + } + + private Map parseAttribute(MBeanServerConnection beanCon, ObjectName mbeanName) throws IntrospectionException, ReflectionException, InstanceNotFoundException, IOException, AttributeNotFoundException, MBeanException { + + Map returnMap = new HashMap<>(); + MBeanInfo info = beanCon.getMBeanInfo(mbeanName); + + for (MBeanAttributeInfo attr : info.getAttributes()) { + + if (!attr.isReadable()) { + logCrawler(mbeanName, attr, "not readable"); + continue; + } + +// System.out.println("========================================================================"); +// System.out.println("PropertyListString"+mbeanName.getCanonicalKeyPropertyListString()); +// System.out.println("canonicaName="+mbeanName.getCanonicalName()); +// System.out.println(mbeanName.getDomain()); +// System.out.println(mbeanName.getKeyPropertyListString().compareTo("http")); +// System.out.println("========================================================================"); + Object att = null; + + try { + att = beanCon.getAttribute(mbeanName, attr.getName()); + }catch (Exception e) { + logCrawler(mbeanName, attr, "fail: " + e); + continue; + } + + if (att != null) + returnMap.put(attr.getName(), att.toString()); + } + return returnMap; + } + + @Override + public List getInternal(Config config) throws Exception { + + String hostIp = config.getTarget().getConnection().getIp(); + String port = config.getTarget().getConnection().getPort(); + + this.jmxUrl = "service:jmx:rmi:///jndi/rmi://" + hostIp + ":" +port + "/jmxrmi"; + this.username = (String) config.getTarget().getAuth().get("id"); + this.password = (String) config.getTarget().getAuth().get("pw"); + + // connection + MBeanServerConnection beanCon; + JMXConnector jmxconn = null; + try { + + + Map environment = getAuthority(); + jmxconn = JMXConnectorFactory.connect(new JMXServiceURL(this.jmxUrl), environment); + beanCon = jmxconn.getMBeanServerConnection(); + + List resultSetList = new ArrayList<>(); + List objectNames = new LinkedList(); + objectNames.add(null); + ObjectName on = null; + + for (Item item : config.getItems()) { + + ResultSet resultSet = ResultSet.newInstance(item); + + // get object + String query = item.getQueryInfo().getQuery(); + on = new ObjectName(query); + Set names = beanCon.queryMBeans(on, null); + + List> keys = (List>) item.getQueryInfo().getExtend().get("aliases"); + + for (ObjectInstance name : names) { + + Map attrs = parseAttribute(beanCon,name.getObjectName()); + if (keys != null) { + for ( Map keyMap : keys ) { + String key = (String) keyMap.get("key"); + int index = (int) keyMap.get("index"); + String objectName = parseObjectName(name.toString(),key); + String alias = item.getMappingInfo().getArrayColumns().get(index); + attrs.put(alias,objectName); + } + } + + resultSet.addRow(parse(attrs, resultSet.getMeta())); + } + + resultSetList.add(resultSet); + } + + return resultSetList; + } catch(Exception e) { + e.printStackTrace(); + throw e; + } finally { + if (jmxconn != null) { + jmxconn.close(); + } + } + } + + private String parseObjectName(String s, String key) { + + int start = s.indexOf("["); + int end = s.lastIndexOf("]"); + s = s.substring(start+1,end); + + String [] slices = s.split(","); + String returnData = ""; + for (String item : slices) { + String [] itemSplit = item.split("="); + if (itemSplit == null || itemSplit.length != 2) {continue;} + if (itemSplit[0].equals(key)) { + returnData = itemSplit[1]; + } + } + + return returnData; + } + + private Map getAuthority() { + + Map environment = new HashMap(); + + if (this.username != null && this.username.length() != 0 && this.password != null && this.password.length() != 0) { + String[] credent = new String[] {this.username, this.password}; + environment.put(JMXConnector.CREDENTIALS, credent); + } + + if (this.ssl) { + environment.put(Context.SECURITY_PROTOCOL, "ssl"); + SslRMIClientSocketFactory clientSocketFactory = new SslRMIClientSocketFactory(); + environment.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, clientSocketFactory); + environment.put("com.sun.jndi.rmi.factory.socket", clientSocketFactory); + } + + return environment; + } + + private static void logCrawler(String name, String msg) { + logger.log(Level.FINE, "crawler : '" + name + "': " + msg); + } + + private static void logCrawler(ObjectName mbeanName, MBeanAttributeInfo attr, String msg) { + logCrawler(mbeanName + "'_'" + attr.getName(), msg); + } + +} diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/impl/mongodb/MongoDBCrawler.java b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/mongodb/MongoDBCrawler.java new file mode 100644 index 0000000..8b56ab1 --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/mongodb/MongoDBCrawler.java @@ -0,0 +1,88 @@ +package com.loafle.overflow.probe.container.crawler.impl.mongodb; + +import com.loafle.overflow.probe.container.crawler.Crawler; +import com.loafle.overflow.probe.container.crawler.config.Config; +import com.loafle.overflow.probe.container.crawler.config.Item; +import com.loafle.overflow.probe.container.crawler.result.ResultSet; +import com.mongodb.MongoClient; +import com.mongodb.MongoClientOptions; +import com.mongodb.ServerAddress; +import com.mongodb.client.MongoDatabase; +import org.bson.Document; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +public class MongoDBCrawler extends Crawler { + public String name() { + return "MONGODB_CRAWLER"; + } + + public List collectMetric(Config c) throws Exception { + + MongoClient mongoClient = null; +// Map returnMap = new HashMap(); + + String dataBaseName = null; + String statusCommand = null; + + String targetIP = c.getTarget().getConnection().getIp(); + short targetPort = Short.parseShort(c.getTarget().getConnection().getPort()); + List ofResultSets = null; + try { + + mongoClient = new MongoClient(new ServerAddress(targetIP, targetPort), + MongoClientOptions.builder() + .serverSelectionTimeout(1000) + .connectTimeout(1000) + .socketTimeout(1000).build() + ); + + ofResultSets = new ArrayList<>(); + ResultSet ofResultSet = null; + List items = c.getItems(); + List row = null; + for (Item item : items) { + + ofResultSet = ResultSet.newInstance(item); + Map metaMap = ofResultSet.getMeta(); + row = new ArrayList<>(Arrays.asList(new String[metaMap.size()])); + + + + + + dataBaseName = (String)item.getQueryInfo().getExtend().get("dataBaseName"); + statusCommand = (String)item.getQueryInfo().getExtend().get("statusCommand"); + + MongoDatabase database = mongoClient.getDatabase(dataBaseName); + Document serverStatus = database.runCommand(new Document(statusCommand, 1)); + + + Map re = (Map)serverStatus.get(item.getQueryInfo().getQuery()); + + for (Map.Entry info : metaMap.entrySet()) { + row.set(info.getValue().intValue(), String.valueOf(re.get(info.getKey()))); + } + + ofResultSet.addRow(row); + ofResultSets.add(ofResultSet); + + } + }catch (Exception e) { + throw e; + }finally { + if (mongoClient != null) { + mongoClient.close(); + } + } + return ofResultSets; + } + + @Override + public List getInternal(Config config) throws Exception { + return this.collectMetric(config); + } +} diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/impl/redis/RedisCralwer.java b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/redis/RedisCralwer.java new file mode 100644 index 0000000..5523b61 --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/redis/RedisCralwer.java @@ -0,0 +1,110 @@ +package com.loafle.overflow.probe.container.crawler.impl.redis; + +import com.loafle.overflow.probe.container.crawler.Crawler; +import com.loafle.overflow.probe.container.crawler.config.Config; +import com.loafle.overflow.probe.container.crawler.config.Item; +import com.loafle.overflow.probe.container.crawler.result.ResultSet; +import redis.clients.jedis.Jedis; + +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class RedisCralwer extends Crawler { + + private static final Logger LOGGER = Logger.getLogger(RedisCralwer.class.getName()); + + public RedisCralwer() { + + } + + public String name() { + return "REDIS_CRAWLER"; + } + + @Override + public List getInternal(Config c) throws Exception { + LOGGER.log(Level.INFO ,"getInternal call"); + return collectMetric(c); + } + + protected List collectMetric(Config c) { + + String targetIP = c.getTarget().getConnection().getIp(); + int targetPort = Integer.valueOf(c.getTarget().getConnection().getPort()); + + String authpw = (String)c.getTarget().getAuth().get("authpw"); + + Jedis jedis = null; + List items = c.getItems(); + + try { + jedis = new Jedis(targetIP, targetPort,false); + if (authpw != null && !authpw.equals("")) { + String code = jedis.auth(authpw); + if (!code.equals("")) { + // set error auth + } + } + + List resultSetList = new ArrayList<>(); + for (Item item : items) { + ResultSet resultSet = ResultSet.newInstance(item); + + String queryString = (String) item.getQueryInfo().getQuery(); + String info = jedis.info(queryString); + Map resultMap = (Map) parseToMap(info).get(queryString); + + resultSet.addRow(parse(resultMap,resultSet.getMeta())); + resultSetList.add(resultSet); + } + + return resultSetList; + } catch (Exception e) { + throw e; + } finally { + if (jedis != null) { + jedis.close(); + } + } + + } + + private List parse(Map dataMap, Map meta) { + + List row = new ArrayList<>(Arrays.asList(new String[meta.size()])); + for (Map.Entry info : meta.entrySet()) { + String data = dataMap.get(info.getKey()); + data = data.trim(); + row.set(info.getValue().intValue(),data); + } + return row; + } + + public Map parseToMap(String source) { + String[] categorys = source.split("\r\n\r\n"); + Map result = new HashMap(); + + for (String category : categorys) { + + if (category.length() == 0) {continue;} + Map sm = new HashMap(); + String[] lines = category.split("\r\n"); + + int idx = 0; + for (String line : lines) { + + if (idx == 0) {idx++;continue;} + if (line.length() == 0) {continue;} + + String[] items = line.split(":"); + if (items.length != 0 && items.length > 1) { + sm.put(items[0], items[1]); + } + } + String[] ca = lines[0].split(" "); + result.put(ca[1], sm); + } + return result; + } +} diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/impl/snmp/SNMPCrawler.java b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/snmp/SNMPCrawler.java new file mode 100644 index 0000000..e1cc279 --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/snmp/SNMPCrawler.java @@ -0,0 +1,309 @@ +package com.loafle.overflow.probe.container.crawler.impl.snmp; + +import com.loafle.overflow.probe.container.crawler.Crawler; +import com.loafle.overflow.probe.container.crawler.config.Config; +import com.loafle.overflow.probe.container.crawler.config.Connection; +import com.loafle.overflow.probe.container.crawler.config.Item; +import com.loafle.overflow.probe.container.crawler.impl.snmp.version.SNMPv2c; +import com.loafle.overflow.probe.container.crawler.impl.snmp.version.SNMPv3; +import com.loafle.overflow.probe.container.crawler.result.ResultSet; +import org.snmp4j.Snmp; +import org.snmp4j.TransportMapping; +import org.snmp4j.smi.Address; +import org.snmp4j.transport.DefaultUdpTransportMapping; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +public class SNMPCrawler extends Crawler { + public String name() { + return "SNMP_CRAWLER"; + } + + @Override + public List getInternal(Config config) { + + +// String targetVer = (String)config.getTarget().getAuth().get("version"); +// switch (targetVer) { +// case "v2c": +// retObj = getByV2c(config); +// break; +// case "v3": +// retObj = getByV3(config); +// break; +// default: +// new Exception("Unknown SNMP protocol : " + targetVer).printStackTrace(); +// } + + return getSNMP(config); + } + + private List getSNMP(Config config) { + + Snmp snmp = null; + TransportMapping transport = null; + + List rslist = null; + + try { + transport = new DefaultUdpTransportMapping(); + snmp = new Snmp(transport); + transport.listen(); + + rslist = new ArrayList<>(); + + List items = config.getItems(); + String[] oids = null; + + Map snmpResultMap = null; + for (Item item : items) { + oids = new String[item.getKeys().size()]; + for (int i=0; i getSNMPV(Snmp snmp, Config config, String[] oids) throws Exception { + + String targetVer = (String)config.getTarget().getAuth().get("version"); + switch (targetVer) { + case "v2c": + return getV2c(snmp, config, oids); + case "v3": + return getV3(snmp, config, oids); + default: + new Exception("Unknown SNMP protocol : " + targetVer).printStackTrace(); + } + + + return null; + } + + private Map getV2c(Snmp snmp, Config config, String[] oids) throws Exception { + + SNMPv2c snmpV2 = new SNMPv2c(snmp); + + Map authInfo = config.getTarget().getAuth(); + Connection connInfo = config.getTarget().getConnection(); + + String ip = connInfo.getIp(); + String port = connInfo.getPort(); + String community = (String)authInfo.get("community"); + + return snmpV2.get(ip, port, community, oids); + } + + private Map getV3(Snmp snmp, Config config, String[] oids) throws Exception { + SNMPv3 snmpV3 = new SNMPv3(snmp); + + Map authInfo = config.getTarget().getAuth(); + Connection connInfo = config.getTarget().getConnection(); + + String ip = connInfo.getIp(); + String port = connInfo.getPort(); +// String method = config.get; + + String user = (String)authInfo.get("user"); + String authType = (String)authInfo.get("authType"); + String authPass = (String)authInfo.get("authPass"); + String privType = (String)authInfo.get("privType"); + String privPass = (String)authInfo.get("privPass"); + + return snmpV3.get(ip, port, user, authType, authPass, privType, privPass, oids); + } + + protected ResultSet convertResultSet(Map map, Item item) { + + ResultSet rs = ResultSet.newInstance(item); + + List row = new ArrayList<>(Arrays.asList(new String[map.size()])); + + Map metaMap = rs.getMeta(); + + for (Map.Entry info : metaMap.entrySet()) { + row.set(info.getValue().intValue(), map.get(info.getKey())); + } + rs.addRow(row); + + return rs; + } +// +// private List getByV2c(Config config) { +// Snmp snmp = null; +// TransportMapping transport = null; +// +// List rslist = null; +// +// try { +// transport = new DefaultUdpTransportMapping(); +// snmp = new Snmp(transport); +// transport.listen(); +// SNMPv2c snmpV2 = new SNMPv2c(snmp); +// +// rslist = new ArrayList<>(); +// +// Map authInfo = config.getTarget().getAuth(); +// Connection connInfo = config.getTarget().getConnection(); +// +// String ip = connInfo.getIp(); +// String port = connInfo.getPort(); +// String community = (String)authInfo.get("community"); +// +// List items = config.getItems(); +// String[] oids = null; +// for (Item item : items) { +// oids = new String[item.getKeys().size()]; +//// List queries = item.getQueries(); +// for (int i=0; i transport = null; +// +// List rslist = null; +// +// try { +// transport = new DefaultUdpTransportMapping(); +// snmp = new Snmp(transport); +// transport.listen(); +// SNMPv3 snmpV3 = new SNMPv3(snmp); +// +// rslist = new ArrayList<>(); +// +// Map authInfo = config.getTarget().getAuth(); +// Connection connInfo = config.getTarget().getConnection(); +// +// String ip = connInfo.getIp(); +// String port = connInfo.getPort(); +//// String method = config.get; +// +// String user = (String)authInfo.get("user"); +// String authType = (String)authInfo.get("authType"); +// String authPass = (String)authInfo.get("authPass"); +// String privType = (String)authInfo.get("privType"); +// String privPass = (String)authInfo.get("privPass"); +// +// List items = config.getItems(); +// String[] oids = null; +// for (Item item : items) { +// oids = new String[item.getKeys().size()]; +//// List queries = item.getQueries(); +// for (int i=0; i get(Snmp snmp, PDU pdu, Target target) throws Exception { + + ResponseEvent response = snmp.get(pdu, target); + + if (response == null) { + throw new Exception("Error: No response from SNMP Agent."); + } + + PDU responsePDU = response.getResponse(); + if (responsePDU == null) { + throw new Exception("Error: Response PDU is null"); + } + + int errorStatus = responsePDU.getErrorStatus(); + int errorIndex = responsePDU.getErrorIndex(); + String errorStatusText = responsePDU.getErrorStatusText(); + + if (errorStatus != PDU.noError) { + throw new Exception("Error: " + errorIndex + " " + errorStatusText); + } + + Map result = new LinkedHashMap(); + for (VariableBinding varBinding : responsePDU.getVariableBindings()) { + if (varBinding == null) { + continue; + } + result.put(varBinding.getOid().toString(), varBinding.getVariable().toString()); + } + return result; + } + + protected Map walk(String oidStr, Target target, TreeUtils treeUtils) throws Exception { + OID oid = new OID(oidStr); + List events = treeUtils.getSubtree(target, oid); + + if(events == null || events.size() == 0){ + throw new Exception("No data."); + } + + Map result = new LinkedHashMap(); + for (TreeEvent event : events) { + if(event == null) { + continue; + } + if (event.isError()) { + System.err.println(event.getErrorMessage()); + continue; + } + + VariableBinding[] varBindings = event.getVariableBindings(); + + for (VariableBinding varBinding : varBindings) { + if (varBinding == null) { + continue; + } + result.put(varBinding.getOid().toString(), varBinding.getVariable().toString()); + } + } + return result; + } +} + diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/impl/snmp/version/SNMPv2c.java b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/snmp/version/SNMPv2c.java new file mode 100644 index 0000000..08f07a5 --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/snmp/version/SNMPv2c.java @@ -0,0 +1,63 @@ +package com.loafle.overflow.probe.container.crawler.impl.snmp.version; + +import org.snmp4j.CommunityTarget; +import org.snmp4j.PDU; +import org.snmp4j.Snmp; +import org.snmp4j.mp.SnmpConstants; +import org.snmp4j.smi.*; +import org.snmp4j.util.DefaultPDUFactory; +import org.snmp4j.util.TreeUtils; + +import java.util.Map; + +public class SNMPv2c extends SNMP { + + private Snmp snmp = null; + + public SNMPv2c(Snmp snmp) { + this.snmp = snmp; + } + + private CommunityTarget getTarget(String addr, String port, String community) { + UdpAddress address = new UdpAddress(addr + "/" + port); + CommunityTarget target = new CommunityTarget(); + target.setCommunity(new OctetString(community)); + target.setAddress(address); + target.setRetries(2); + target.setTimeout(5000); + target.setVersion(SnmpConstants.version2c); + return target; + } + + public Boolean validate(String addr, String port, String community) throws Exception { + String testOid = "1.3.6.1.2.1.1.3.0"; + Map result = this.get(addr, port, community, new String[]{testOid}); + if (result.get(testOid) != null) return true; + return false; + } + + public Map walk(String addr, String port, String community, String oidStr) throws Exception { + + TreeUtils treeUtils = new TreeUtils(this.snmp, new DefaultPDUFactory()); + CommunityTarget target = getTarget(addr, port, community); + + return super.walk(oidStr, target, treeUtils); + } + + + public Map get(String addr, String port, String community, String[] oids) throws Exception { + + CommunityTarget target = getTarget(addr, port, community); + + PDU pdu = new PDU(); + for (String oid : oids) { + pdu.add(new VariableBinding(new OID(oid))); + } + pdu.setType(PDU.GET); + pdu.setRequestID(new Integer32(1)); + + return super.get(this.snmp, pdu, target); + } + +} + diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/impl/snmp/version/SNMPv3.java b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/snmp/version/SNMPv3.java new file mode 100644 index 0000000..67b0adc --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/snmp/version/SNMPv3.java @@ -0,0 +1,148 @@ +package com.loafle.overflow.probe.container.crawler.impl.snmp.version; + +import org.snmp4j.*; +import org.snmp4j.mp.MPv3; +import org.snmp4j.mp.MessageProcessingModel; +import org.snmp4j.mp.SnmpConstants; +import org.snmp4j.security.*; +import org.snmp4j.smi.*; +import org.snmp4j.transport.DefaultUdpTransportMapping; +import org.snmp4j.util.PDUFactory; +import org.snmp4j.util.TreeUtils; + +import java.util.Map; + +/** + * Created by insanity on 17. 4. 10. + */ +public class SNMPv3 extends SNMP { + + private Snmp snmp = null; + + public SNMPv3(Snmp snmp) { + this.snmp = snmp; + } + + public Boolean validate(String addr, String port, String user, String authType, String authPass, String privType, String privPass) throws Exception { + String testOid = "1.3.6.1.2.1.1.3.0"; + Map result = this.get(addr, port, user, authType, authPass, privType, privPass, new String[]{testOid}); + if (result.get(testOid) != null) return true; + return false; + } + + public Map walk(String addr, String port, String user, String authType, String authPass, String privType, String privPass, String oidStr) + throws Exception { + USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0); + SecurityModels.getInstance().addSecurityModel(usm); + + UsmUser usmUser = getUser(user, authType, authPass, privType, privPass); + this.snmp.getUSM().addUser(new OctetString(user), usmUser); + + + TreeUtils treeUtils = new TreeUtils(this.snmp, new PDUFactory() { + public PDU createPDU(Target target) { + ScopedPDU sp = new ScopedPDU(); + sp.setRequestID(new Integer32(1)); + return sp; + } + + public PDU createPDU(MessageProcessingModel messageProcessingModel) { + return new ScopedPDU(); + } + }); + + Target target = getTarget(addr, port, usmUser); + return super.walk(oidStr, target, treeUtils); + } + + public Map get(String addr, String port, String user, String authType, String authPass, String privType, String privPass, String[] oids) + throws Exception { + + TransportMapping transport = new DefaultUdpTransportMapping(); + Snmp snmp = new Snmp(transport); + transport.listen(); + + USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0); + SecurityModels.getInstance().addSecurityModel(usm); + + UsmUser usmUser = getUser(user, authType, authPass, privType, privPass); + this.snmp.getUSM().addUser(new OctetString(user), usmUser); + + PDU pdu = new ScopedPDU(); + for (String oid : oids) { + pdu.addOID(new VariableBinding(new OID(oid))); + } + pdu.setType(PDU.GET); + pdu.setRequestID(new Integer32(1)); + + Target target = getTarget(addr, port, usmUser); + + return super.get(snmp, pdu, target); + } + + private UserTarget getTarget(String addr, String port, UsmUser user) { + + UdpAddress address = new UdpAddress(addr + "/" + port); + UserTarget target = new UserTarget(); + target.setAddress(address); + target.setRetries(2); + target.setTimeout(5000); + target.setVersion(SnmpConstants.version3); + target.setSecurityModel(user.getSecurityModel()); + + int secLv; + OID autyType = user.getAuthenticationProtocol(); + OID privType = user.getPrivacyProtocol(); + if (autyType != null && privType != null) { + secLv = SecurityLevel.AUTH_PRIV; + }else if (autyType != null && privType == null) { + secLv = SecurityLevel.AUTH_NOPRIV; + }else { + secLv = SecurityLevel.NOAUTH_NOPRIV; + } + target.setSecurityLevel(secLv); + target.setSecurityName(new OctetString(user.getSecurityName())); + return target; + } + + private UsmUser getUser(String user, String authType, String authPass, String privType, String privPass) { + OctetString octetUser = new OctetString(user); + OctetString octetAuthPass = authPass.equals("") ? null : new OctetString(authPass); + OctetString octetPrivPass = privPass.equals("") ? null : new OctetString(privPass); + + UsmUser usmUser = new UsmUser(octetUser, getAuthOID(authType), octetAuthPass, getPrivOID(privType), octetPrivPass); + return usmUser; + } + + private OID getAuthOID(String authType) { + OID authOID = null; + switch(authType) { + case "": + authOID = null; + break; + case "MD5": + authOID = AuthMD5.ID; + break; + case "SHA": + authOID = AuthSHA.ID; + break; + } + return authOID; + } + + private OID getPrivOID(String privType) { + OID privOID = null; + switch(privType) { + case "": + privOID = null; + break; + case "DES": + privOID = PrivDES.ID; + break; + case "AES": + privOID = PrivAES128.ID; + break; + } + return privOID; + } +} diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/impl/wmi/WMICrawler.java b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/wmi/WMICrawler.java new file mode 100644 index 0000000..36b09b8 --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/wmi/WMICrawler.java @@ -0,0 +1,74 @@ +package com.loafle.overflow.probe.container.crawler.impl.wmi; + +import com.loafle.overflow.probe.container.crawler.Crawler; +import com.loafle.overflow.probe.container.crawler.config.Config; +import com.loafle.overflow.probe.container.crawler.result.ResultSet; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +public class WMICrawler extends Crawler { + public String name() { + return "WMI_CRAWLER"; + } + + @Override + public List getInternal(Config config) throws Exception { + + return WMICrawlerOS.getInstance().process(config); + } + + @Override + public Object getInternalMeta(Config c) throws Exception { + + List metaConfigList = loadMetaConfig(); + + + List retlist = new ArrayList<>(); + WMICrawlerOS os = WMICrawlerOS.getInstance(); + ResultSet ofResultSet = null; + for(Config metaConfig : metaConfigList) { + + for(int indexI = 0; indexI < metaConfig.getItems().size(); ++indexI) { + ofResultSet = os.processWMI(c, metaConfig.getItems().get(indexI)); + if(ofResultSet != null) { + retlist.add(ofResultSet); + } + } + } + + return null; + } + + + private List loadMetaConfig() throws IOException { + ClassLoader classLoader = getClass().getClassLoader(); + + URL url = classLoader.getResource("config/meta"); + if(url == null) { + return null; + } + + String path = url.getFile(); + + File pathFile = new File(path); + + System.out.println(path); + String[] metaFiles = pathFile.list(); + List retList = new ArrayList<>(); + Config metaConfig = null; + for(String fi : metaFiles) { + if(fi.indexOf("meta_") > -1) { + metaConfig = objectMapper.readValue(new File(path+"/"+fi), Config.class); + if(metaConfig != null) { + retList.add(metaConfig); + } + } + } + + return retList; + } +} diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/impl/wmi/WMICrawlerLinux.java b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/wmi/WMICrawlerLinux.java new file mode 100644 index 0000000..92262e9 --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/wmi/WMICrawlerLinux.java @@ -0,0 +1,153 @@ +package com.loafle.overflow.probe.container.crawler.impl.wmi; + +import com.loafle.overflow.probe.container.crawler.config.Config; +import com.loafle.overflow.probe.container.crawler.config.Item; +import com.loafle.overflow.probe.container.crawler.result.ResultSet; + +import java.util.*; + +public class WMICrawlerLinux extends WMICrawlerOS { + + private final String DELIMITER = "||"; + private final String DELIMITER_SPLIT = "\\|\\|"; + + public ResultSet processWMI(Config config, Item item) throws Exception { + + List argList = createCommand(config, item); + + String result = execute(argList.toArray(new String[argList.size()])); + + ResultSet ofResultSet = parseResult(result, item); + + return ofResultSet; + } + + public List createCommand(Config config, Item item) throws Exception { + + String id = (String)config.getTarget().getAuth().get("id"); + String pw = (String)config.getTarget().getAuth().get("pw"); + String nameSpace = (String)item.getQueryInfo().getExtend().get("nameSpace"); + String ip = config.getTarget().getConnection().getIp(); + String query = item.getQueryInfo().getQuery(); + + String wmicPath = (String)item.getQueryInfo().getExtend().get("wmicPath"); + //FIXME:: where is wmic ?? + List argList = new ArrayList(); + + argList.add(wmicPath); + argList.add("-U"); + argList.add(id + "%" + pw); + argList.add("//" + ip); + argList.add(query); + argList.add("--namespace=" + nameSpace); + argList.add("--delimiter=" + DELIMITER); + + return argList; + } + + public String execute(String... args) throws Exception { + System.out.println(""); + ProcessBuilder builder = new ProcessBuilder(args); + Process process = builder.start(); + + byte[] msg = new byte[1024]; + + StringBuffer buf = new StringBuffer(); + + while(process.getInputStream().read(msg) > 0) { + buf.append(new String(msg)); + Arrays.fill(msg, (byte)0); + } + + return buf.toString(); + } + + public ResultSet parseResult(String result, Item item) throws Exception { + + if(result == null || result.length() <= 0) { + return null; + } + + result = result.trim(); + + String errStr = checkError(result); + if(errStr.length() > 0) { + throw new Exception(errStr); + } + + String[] lines = result.split("\\n"); + String line = ""; + + ResultSet ofResultSet = ResultSet.newInstance(item); + Map metaMap = ofResultSet.getMeta(); + + List columns = null; + Map tempMap = new HashMap(); + List row = null; + for (int indexI = 0 ; indexI < lines.length; ++indexI) { + tempMap.clear(); + + line = lines[indexI].trim(); + if (line.length() <= 0) continue; + if(indexI == 0) { + int idx = line.indexOf("CLASS:"); + if (idx >= 0 ) { + continue; + } + } + + if (columns == null) { + String[] datas = line.split(DELIMITER_SPLIT); + columns = Arrays.asList(datas); + continue; + } + + row = new ArrayList<>(Arrays.asList(new String[metaMap.size()])); + + String[] datas = line.split(DELIMITER_SPLIT); + + for(int indexJ = 0; indexJ < columns.size(); ++indexJ) { + tempMap.put(columns.get(indexJ), datas[indexJ]); + } + + int tempSize = tempMap.size(); + int metaSize = metaMap.size(); + int resultSize = tempSize - metaSize; + + int currentIdx = 0; + for (Map.Entry info : metaMap.entrySet()) { + currentIdx = info.getValue().intValue(); + if(currentIdx >= metaSize) { + currentIdx -= resultSize; + } + row.set(currentIdx, tempMap.get(info.getKey())); + } + + + ofResultSet.addRow(row); + + } + + return ofResultSet; + } + + public String checkError(String result) { + int errIdx = result.indexOf("ERROR:"); + String retErrStr = ""; + if(errIdx >= 0) { + + int enterIdx = result.indexOf("\\n", errIdx); + if(enterIdx < 0) enterIdx = result.length(); + String errStr = result.substring(errIdx + "ERROR:".length(), enterIdx); + + +// Map map = new HashMap<>(); + +// map.put("ERROR", errStr); +// resultMapList.add(map); +// return resultMapList; + retErrStr = errStr; + } + return retErrStr; + } +} diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/impl/wmi/WMICrawlerOS.java b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/wmi/WMICrawlerOS.java new file mode 100644 index 0000000..540457e --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/wmi/WMICrawlerOS.java @@ -0,0 +1,47 @@ +package com.loafle.overflow.probe.container.crawler.impl.wmi; + +import com.loafle.overflow.probe.container.crawler.config.Config; +import com.loafle.overflow.probe.container.crawler.config.Item; +import com.loafle.overflow.probe.container.crawler.result.ResultSet; + +import java.util.ArrayList; +import java.util.List; + +public abstract class WMICrawlerOS { + + private static WMICrawlerOS wmiCrawlerOS = null; + + public static WMICrawlerOS getInstance() { + + if(WMICrawlerOS.wmiCrawlerOS == null) { + + String os = System.getProperty("os.name").toLowerCase(); + + if(os.indexOf("linux") >= 0) { + WMICrawlerOS.wmiCrawlerOS = new WMICrawlerLinux(); + } else if(os.indexOf("") >= 0) { + WMICrawlerOS.wmiCrawlerOS = new WMICrawlerWindows(); + } + + } + + return WMICrawlerOS.wmiCrawlerOS; + } + + public List process(Config config) throws Exception { + + List retlist = new ArrayList<>(); + ResultSet ofResultSet = null; + for(int cIndexI = 0 ; cIndexI < config.getItems().size() ; ++cIndexI) { + + ofResultSet = processWMI(config, config.getItems().get(cIndexI)); + retlist.add(ofResultSet); + } + + + return retlist; + } + + public abstract ResultSet processWMI(Config config, Item item) throws Exception ; +} + diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/impl/wmi/WMICrawlerWindows.java b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/wmi/WMICrawlerWindows.java new file mode 100644 index 0000000..5e63bce --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/impl/wmi/WMICrawlerWindows.java @@ -0,0 +1,254 @@ +package com.loafle.overflow.probe.container.crawler.impl.wmi; + +import com.jacob.activeX.ActiveXComponent; +import com.jacob.com.Dispatch; +import com.jacob.com.EnumVariant; +import com.jacob.com.Variant; +import com.loafle.overflow.probe.container.crawler.config.Config; +import com.loafle.overflow.probe.container.crawler.config.Item; +import com.loafle.overflow.probe.container.crawler.result.ResultSet; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +public class WMICrawlerWindows extends WMICrawlerOS { + + public ResultSet processWMI(Config config, Item item) throws Exception { + + String query = ""; + ActiveXComponent wmiconnect = null; + ResultSet ofResultSet = null; + + + query = item.getQueryInfo().getQuery(); + wmiconnect = connectServer(config, item); + + Variant vQuery = new Variant(query); + Variant vCollection = wmiconnect.invoke("ExecQuery", vQuery); + wmiconnect.safeRelease(); + vQuery.safeRelease(); + + Dispatch dConnection = vCollection.toDispatch(); + vCollection.safeRelease(); +// int count = getCount(dConnection); + + EnumVariant enumVariant = new EnumVariant(dConnection); + dConnection.safeRelease(); + + ofResultSet = getResultSet(enumVariant, item); + enumVariant.safeRelease(); + return ofResultSet; + } + + protected ResultSet getResultSet(EnumVariant enumVariant, Item citem) { + + ResultSet ofResultSet = ResultSet.newInstance(citem); + + Variant vItem = null; + Dispatch item = null; + + Variant vValue = null; + String value = null; + + List row = null; + Map metaMap = ofResultSet.getMeta(); + + while (enumVariant.hasMoreElements()) { + + row = new ArrayList<>(Arrays.asList(new String[metaMap.size()])); + + vItem = enumVariant.nextElement(); + item = vItem.toDispatch(); + + for (Map.Entry info : metaMap.entrySet()) { + vValue = Dispatch.call(item, info.getKey()); + value = vValue.toString(); + vValue.safeRelease(); + row.set(info.getValue().intValue(), value); + } + + vItem.safeRelease(); + item.safeRelease(); + + ofResultSet.addRow(row); + } + + + return ofResultSet; + } +// +// protected void getMultiValue(EnumVariant enumVariant, Query cQuery, Item cItem, int idxMetric, Map resultMap) { +// +// Variant vItem = null; +// Dispatch item = null; +// +// +// int keyIdx = 0; +// while (enumVariant.hasMoreElements()) { +// +// vItem = enumVariant.nextElement(); +// item = vItem.toDispatch(); +// +// +// String name = null; +// String value = null; +// Variant vValue = null; +// +// for(int indexI = 0 ; indexI < cQuery.getKeys().size(); ++indexI) { +// name = cQuery.getKeys().get(indexI); +// vValue = Dispatch.call(item, name); +// value = vValue.toString(); +// String keyStr = convertArrayKey(cItem.getMetrics().get(indexI),keyIdx ); +// resultMap.put(keyStr, value); +// vValue.safeRelease(); +// } +// +// vItem.safeRelease(); +// item.safeRelease(); +// ++idxMetric; +// ++keyIdx; +// } +// +// } + + protected String convertArrayKey(String key, int index) { + int idx = key.indexOf("["); + String ret = ""; + + if(idx <= 0) { + idx = key.indexOf("."); + ret += key.substring(0, idx); + ret += "["; + ret += String.valueOf(index); + ret += "]"; + ret += key.substring(idx +1); + }else { + + ret += key.substring(0, idx +1); + ret += String.valueOf(index); + ret += key.substring(idx +1); + } + + + return ret; + } + +// protected void getSingleValue(EnumVariant enumVariant, Query cQuery, Item cItem, int idxMetric, Map resultMap) { +// +// Variant vItem = null; +// Dispatch item = null; +// +// while (enumVariant.hasMoreElements()) { +// +// vItem = enumVariant.nextElement(); +// item = vItem.toDispatch(); +// +// String name = null; +// String value = null; +// Variant vValue = null; +// +// for(int indexI = 0 ; indexI < cQuery.getKeys().size(); ++indexI) { +// name = cQuery.getKeys().get(indexI); +// vValue = Dispatch.call(item, name); +// value = vValue.toString(); +// resultMap.put(cItem.getMetrics().get(idxMetric++), value); +// vValue.safeRelease(); +// } +// +// vItem.safeRelease(); +// item.safeRelease(); +// } +// +// } + + protected List getColumns(Dispatch item) { + + List columns = new ArrayList(); + + Variant propertyesa = Dispatch.call(item, "Properties_"); + + Dispatch disProperty = propertyesa.toDispatch(); + + + Variant newEnum = Dispatch.call(disProperty, "_NewEnum"); + + propertyesa.safeRelease(); + disProperty.safeRelease(); + + EnumVariant enumv = newEnum.toEnumVariant(); + + newEnum.safeRelease(); + + Variant vElem = null; + Dispatch disElem = null; + Variant vName = null; + + while (enumv.hasMoreElements()) { + vElem = enumv.nextElement(); + disElem = vElem.toDispatch(); + + vName = Dispatch.call(disElem, "Name"); + String vs = vName.toString(); + + columns.add(vs); + + disElem.safeRelease(); + vElem.safeRelease(); + vName.safeRelease(); + } + + enumv.safeRelease(); + return columns; + } + + + protected int getCount(Dispatch d) { + + Variant c = Dispatch.call(d, "Count"); + + int retInt = Integer.valueOf(c.toString()); + + c.safeRelease(); + + return retInt; + } + + protected ActiveXComponent connectServer(Config config, Item item) { + + String id = (String)config.getTarget().getAuth().get("id"); + String pw = (String)config.getTarget().getAuth().get("pw"); + String nameSpace = (String)item.getQueryInfo().getExtend().get("nameSpace"); +// String query = (String)config.get.get("query"); + + String ip = config.getTarget().getConnection().getIp(); + + ActiveXComponent wmi = null; + wmi = new ActiveXComponent("WbemScripting.SWbemLocator"); + + Variant vIp = new Variant(ip); + Variant vNs = new Variant(nameSpace); + Variant vId = new Variant(id); + Variant vPw = new Variant(pw); + + Variant conRet = wmi.invoke("ConnectServer", vIp, vNs, vId, vPw); + + vIp.safeRelease(); + vNs.safeRelease(); + vId.safeRelease(); + vPw.safeRelease(); + + Dispatch disConret = conRet.toDispatch(); + + ActiveXComponent wmiconnect = new ActiveXComponent(disConret); + disConret.safeRelease(); + + wmi.safeRelease(); + conRet.safeRelease(); + + return wmiconnect; + + } + +} diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/result/ResultSet.java b/src/main/java/com/loafle/overflow/probe/container/crawler/result/ResultSet.java new file mode 100644 index 0000000..5b2a0a9 --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/result/ResultSet.java @@ -0,0 +1,75 @@ +package com.loafle.overflow.probe.container.crawler.result; + +import com.loafle.overflow.probe.container.crawler.config.Item; +import com.loafle.overflow.probe.container.crawler.config.MappingInfo; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public abstract class ResultSet { + // properties + protected Item item; + protected List> rows; + protected Map meta = null; + + public Map getMeta() { + return meta; + } + + public void setMeta(Map meta) { + this.meta = meta; + } + + public List> getRows() { + return rows; + } + + public void setRows(List> rows) { + this.rows = rows; + } + + public Item getItem() { + return item; + } + + public void setItem(Item item) { + this.item = item; + } + + // methods + static public ResultSet newInstance(Item item) { + if (item.getMappingInfo() == null) { + item.setMappingInfo(new MappingInfo()); + } + String type = (String) item.getMappingInfo().getParseDirection(); + if (type != null && type.equals("row")) { + return new ResultSetRow(item); + } else { + return new ResultSetCol(item); + } + } + + + public ResultSet(Item item) { + this.item = item; + this.rows = new ArrayList<>(); + this.setMeta(); + } + + public void addRow(List row) { + rows.add(row); + } + + + public Map getData() { + return parse(); + } + + // abstracts + public abstract void setMeta(); + public abstract Map parse(); + + +} + diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/result/ResultSetCol.java b/src/main/java/com/loafle/overflow/probe/container/crawler/result/ResultSetCol.java new file mode 100644 index 0000000..343c146 --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/result/ResultSetCol.java @@ -0,0 +1,106 @@ +package com.loafle.overflow.probe.container.crawler.result; + +import com.loafle.overflow.probe.container.crawler.config.Item; +import com.loafle.overflow.probe.container.crawler.config.Keys; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ResultSetCol extends ResultSet{ + + public ResultSetCol(Item item) { + super(item); + } + + public void setMeta() { + + List meta = this.item.getKeys(); + List arrayColumns = this.item.getMappingInfo().getArrayColumns(); + + if(this.meta == null) { + this.meta = new HashMap<>(); + } + + for(int indexI = 0; indexI < meta.size(); ++indexI) { + this.meta.put(meta.get(indexI).getKey(), indexI); + } + + if( arrayColumns != null) { + for( int indexI = 0 ; indexI < arrayColumns.size(); ++indexI) { + if(this.meta.containsKey(arrayColumns.get(indexI))) { + continue; + } + this.meta.put(arrayColumns.get(indexI), indexI+ meta.size()); + } + } + + + + } + + public Map parse() { + + List metrics = this.item.getKeys(); + List arrayColumns = this.item.getMappingInfo().getArrayColumns(); + + Map resultMap = new HashMap<>(); + + List row = null; + + String metric = null; + List arrayValue = new ArrayList<>(); + + + int columnIdx = 0; + + for(int indexI = 0; indexI < this.rows.size(); ++indexI) { + + row = this.rows.get(indexI); + for (int indexJ= 0; indexJ < row.size(); ++indexJ) { + + arrayValue.clear(); + + if(arrayColumns != null ) { + for(int indexL =0; indexL < arrayColumns.size(); ++indexL) { + columnIdx = this.meta.get(arrayColumns.get(indexL)); + + arrayValue.add(row.get(columnIdx)); + } + } + + for(int indexK = 0 ; indexK < metrics.size(); ++indexK) { + metric = metrics.get(indexK).getMetric(); + metric = convertMetric(metric, arrayValue); + resultMap.put(metric, row.get(indexK)); + } + + } + + } + + return resultMap; + + } + + private String convertMetric(String metric, List arrayValue) { + + if(arrayValue == null || arrayValue.size() <= 0) { + return metric; + } + + String convertChar = "$"; + String convertStr = null; + + for(int indexI = 0 ; indexI < arrayValue.size(); ++indexI) { + + convertStr = convertChar + String.valueOf(indexI); + + metric = metric.replace(convertStr, arrayValue.get(indexI)); + + } + + return metric; + } +} diff --git a/src/main/java/com/loafle/overflow/probe/container/crawler/result/ResultSetRow.java b/src/main/java/com/loafle/overflow/probe/container/crawler/result/ResultSetRow.java new file mode 100644 index 0000000..38559a7 --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/crawler/result/ResultSetRow.java @@ -0,0 +1,104 @@ +package com.loafle.overflow.probe.container.crawler.result; + +import com.loafle.overflow.probe.container.crawler.config.Item; +import com.loafle.overflow.probe.container.crawler.config.Keys; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ResultSetRow extends ResultSet{ + + public ResultSetRow(Item item) { + super(item); + } + + public void setMeta() { + + List meta = new ArrayList<>(); + + List arrayColumns = (List) this.item.getMappingInfo().getArrayColumns(); + List keyColumns = (List) this.item.getMappingInfo().getKeyColumns(); + String valueColumn = (String) this.item.getMappingInfo().getValueColumn(); + if (arrayColumns != null) { + for (String c : arrayColumns) { + meta.add(c); + } + } + + if (keyColumns != null) { + for (String c: keyColumns) { + meta.add(c); + } + } + + if (valueColumn != null && !valueColumn.equals("")) + meta.add(valueColumn); + + if(this.meta == null) { + this.meta = new HashMap<>(); + } + + for(int indexI = 0; indexI < meta.size(); ++indexI) { + this.meta.put(meta.get(indexI), indexI); + } + + } + + public Map parse() { + + Map returnMap = new HashMap<>(); + + String valueColumn = (String) this.item.getMappingInfo().getValueColumn(); + + for (List row : this.rows) { + String key = makeKey(row); + if(key == null) continue; + returnMap.put(key,row.get(this.meta.get(valueColumn))); + } + + return returnMap; + } + + private String makeKey(List data) { + + List metrics = this.item.getKeys(); + + List arrayColumns = (List) this.item.getMappingInfo().getArrayColumns(); + List keyColumns = (List) this.item.getMappingInfo().getKeyColumns(); + List keys = this.item.getKeys(); + + boolean find = false; + int findIndex = -1; + for (String keyColumn: keyColumns) { + String row = data.get(this.meta.get(keyColumn)); + for (int i =0 ; i < keys.size() ; ++i) { + if (row.equals(keys.get(i).getKey())) { + findIndex = i; + find = true; + break; + } + } + if (find == true) {break;} + } + + if(findIndex < 0) { + return null; + } + + String metric = metrics.get(findIndex).getMetric(); + + if (arrayColumns != null) { + for (int i =0 ; i< arrayColumns.size() ; ++i) { + // replace + String k = "$" + i; + int dataIndex = this.meta.get(arrayColumns.get(i)); + String replaceString = data.get(dataIndex); + metric = metric.replace(k,"'" + replaceString + "'"); + } + } + return metric; + } + +} diff --git a/src/main/java/com/loafle/overflow/probe/container/rpc/invoker/spring/SpringInvoker.java b/src/main/java/com/loafle/overflow/probe/container/rpc/invoker/impl/SimpleInvoker.java similarity index 81% rename from src/main/java/com/loafle/overflow/probe/container/rpc/invoker/spring/SpringInvoker.java rename to src/main/java/com/loafle/overflow/probe/container/rpc/invoker/impl/SimpleInvoker.java index cd8e2c1..52184a1 100644 --- a/src/main/java/com/loafle/overflow/probe/container/rpc/invoker/spring/SpringInvoker.java +++ b/src/main/java/com/loafle/overflow/probe/container/rpc/invoker/impl/SimpleInvoker.java @@ -1,14 +1,9 @@ -package com.loafle.overflow.probe.container.rpc.invoker.spring; +package com.loafle.overflow.probe.container.rpc.invoker.impl; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.ObjectMapper; import com.loafle.overflow.probe.container.rpc.invoker.Invoker; import com.loafle.overflow.probe.container.util.Primitives; -import org.springframework.aop.support.AopUtils; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.stereotype.Component; import java.io.IOException; import java.lang.reflect.Method; @@ -18,17 +13,16 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -@Component -public class SpringInvoker implements Invoker { - @Autowired - private ApplicationContext applicationContext; - @Autowired +public class SimpleInvoker implements Invoker { private ObjectMapper objectMapper; + private Map services; private Map serviceCacheMap; - public SpringInvoker() { + public SimpleInvoker(ObjectMapper objectMapper, Map services) { + this.objectMapper = objectMapper; + this.services = services; serviceCacheMap = new HashMap<>(); } @@ -36,15 +30,15 @@ public class SpringInvoker implements Invoker { private ServiceCache serviceCache; private Map methodCacheMap; - private Cache(Object bean) { + private Cache(Object service) { serviceCache = new ServiceCache(); - serviceCache.bean = bean; + serviceCache.service = service; methodCacheMap = new HashMap<>(10); } - private Object getBean() { - return serviceCache.bean; + private Object getService() { + return serviceCache.service; } private MethodCache getMethodCache(String methodName) throws NoSuchMethodException { @@ -74,7 +68,7 @@ public class SpringInvoker implements Invoker { } private Method getMethod(String methodName) { - Class clazz = AopUtils.getTargetClass(serviceCache.bean); + Class clazz = serviceCache.service.getClass(); Method[] methods = clazz.getMethods(); Method targetMethod = null; @@ -88,7 +82,7 @@ public class SpringInvoker implements Invoker { } private static class ServiceCache { - private Object bean; + private Object service; private Map methodCacheMap; } private static class MethodCache { @@ -103,13 +97,13 @@ public class SpringInvoker implements Invoker { if (null != serviceCache) { return serviceCache; } - try { - Object bean = applicationContext.getBean(serviceName); - serviceCache = new Cache(bean); - serviceCacheMap.put(serviceName, serviceCache); - } catch (BeansException e) { - throw new Exception(); + + Object service = services.get(serviceName); + if (null == service) { + throw new Exception(String.format("Invoker: Service[%s] is not exist", serviceName)); } + serviceCache = new Cache(service); + serviceCacheMap.put(serviceName, serviceCache); return serviceCache; } @@ -171,7 +165,7 @@ public class SpringInvoker implements Invoker { Object result = null; try { - result = methodCache.method.invoke(serviceCache.getBean(), parameters); + result = methodCache.method.invoke(serviceCache.getService(), parameters); } catch (Exception e) { throw e; } diff --git a/src/main/java/com/loafle/overflow/probe/container/server/ContainerChannelInitializer.java b/src/main/java/com/loafle/overflow/probe/container/server/ContainerChannelInitializer.java index 84d52af..7034d6f 100644 --- a/src/main/java/com/loafle/overflow/probe/container/server/ContainerChannelInitializer.java +++ b/src/main/java/com/loafle/overflow/probe/container/server/ContainerChannelInitializer.java @@ -1,26 +1,17 @@ package com.loafle.overflow.probe.container.server; import io.netty.channel.Channel; -import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.handler.codec.json.JsonObjectDecoder; import io.netty.handler.codec.string.StringDecoder; import io.netty.handler.codec.string.StringEncoder; import io.netty.util.CharsetUtil; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Component; -@Component -@Qualifier("containerChannelInitializer") public class ContainerChannelInitializer extends ChannelInitializer { private static final StringDecoder STRING_DECODER = new StringDecoder(CharsetUtil.UTF_8); private static final StringEncoder STRING_ENCODER = new StringEncoder(CharsetUtil.UTF_8); - @Autowired - @Qualifier("containerJSONHandler") - private ChannelInboundHandlerAdapter containerJSONHandler; @Override protected void initChannel(Channel channel) throws Exception { @@ -30,7 +21,7 @@ public class ContainerChannelInitializer extends ChannelInitializer { .addLast(new JsonObjectDecoder(Integer.MAX_VALUE)) .addLast(STRING_DECODER) .addLast(STRING_ENCODER) - .addLast(containerJSONHandler); + .addLast(ContainerConfiguration.channelInboundHandlerAdapter()); } } diff --git a/src/main/java/com/loafle/overflow/probe/container/server/ContainerConfiguration.java b/src/main/java/com/loafle/overflow/probe/container/server/ContainerConfiguration.java index 503834b..9dd055c 100644 --- a/src/main/java/com/loafle/overflow/probe/container/server/ContainerConfiguration.java +++ b/src/main/java/com/loafle/overflow/probe/container/server/ContainerConfiguration.java @@ -1,52 +1,86 @@ package com.loafle.overflow.probe.container.server; import com.fasterxml.jackson.databind.ObjectMapper; -import io.netty.bootstrap.ServerBootstrap; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.nio.NioServerSocketChannel; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; +import com.loafle.overflow.probe.container.crawler.Crawler; +import com.loafle.overflow.probe.container.crawler.impl.database.mysql.MySQLCrawler; +import com.loafle.overflow.probe.container.crawler.impl.database.oracle.OracleCrawler; +import com.loafle.overflow.probe.container.crawler.impl.database.postgresql.PostgreSQLCrawler; +import com.loafle.overflow.probe.container.crawler.impl.database.sqlserver.SQLServerCrawler; +import com.loafle.overflow.probe.container.crawler.impl.jmx.JMXCrawler; +import com.loafle.overflow.probe.container.crawler.impl.mongodb.MongoDBCrawler; +import com.loafle.overflow.probe.container.crawler.impl.redis.RedisCralwer; +import com.loafle.overflow.probe.container.crawler.impl.snmp.SNMPCrawler; +import com.loafle.overflow.probe.container.crawler.impl.wmi.WMICrawler; +import com.loafle.overflow.probe.container.rpc.invoker.Invoker; +import com.loafle.overflow.probe.container.rpc.invoker.impl.SimpleInvoker; +import com.loafle.overflow.probe.container.service.ConfigService; +import com.loafle.overflow.probe.container.service.DataService; +import com.loafle.overflow.probe.container.service.StateService; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.ChannelInitializer; -import java.net.InetSocketAddress; +import java.util.HashMap; +import java.util.Map; -@Configuration -public class ContainerConfiguration { - private int port = 19390; +public abstract class ContainerConfiguration { + private static ObjectMapper objectMapper; + private static ContainerChannelInitializer channelInitializer; + private static ChannelInboundHandlerAdapter channelInboundHandlerAdapter; + private static Invoker invoker; + private static Map crawlers = new HashMap<>(); + private static Map services = new HashMap<>(); - @Autowired - private ContainerChannelInitializer containerChannelInitializer; + static { + addCrawler(new MySQLCrawler()); + addCrawler(new OracleCrawler()); + addCrawler(new PostgreSQLCrawler()); + addCrawler(new SQLServerCrawler()); + addCrawler(new JMXCrawler()); + addCrawler(new MongoDBCrawler()); + addCrawler(new RedisCralwer()); + addCrawler(new SNMPCrawler()); + addCrawler(new WMICrawler()); - @Bean(destroyMethod = "shutdownGracefully") - public NioEventLoopGroup bossGroup() { - return new NioEventLoopGroup(); + addService(new ConfigService(crawlers)); + addService(new DataService(crawlers)); + addService(new StateService(crawlers)); } - @Bean(destroyMethod = "shutdownGracefully") - public NioEventLoopGroup workerGroup() { - return new NioEventLoopGroup(); - + private static void addCrawler(Crawler crawler) { + String name = crawler.name(); + crawlers.put(name, crawler); } - @Bean - public InetSocketAddress socketAddress() { - return new InetSocketAddress("127.0.0.1", port); + private static void addService(Object service) { + String name = service.getClass().getSimpleName(); + services.put(name, service); } - @Bean - public ServerBootstrap serverBootstrap() { - ServerBootstrap serverBootstrap = new ServerBootstrap(); - - serverBootstrap - .group(bossGroup(), workerGroup()) - .channel(NioServerSocketChannel.class) - .childHandler(containerChannelInitializer); - - return serverBootstrap; + public static ObjectMapper objectMapper() { + if (null == objectMapper) { + objectMapper = new ObjectMapper(); + } + return objectMapper; } - @Bean - public ObjectMapper objectMapper() { - return new ObjectMapper(); + public static ChannelInitializer channelInitializer() { + if (null == channelInitializer) { + channelInitializer = new ContainerChannelInitializer(); + } + return channelInitializer; + } + + public static ChannelInboundHandlerAdapter channelInboundHandlerAdapter() { + if (null == channelInboundHandlerAdapter) { + channelInboundHandlerAdapter = new ContainerJSONHandler(); + } + return channelInboundHandlerAdapter; + } + + public static Invoker invoker() { + if (null == invoker) { + invoker = new SimpleInvoker(objectMapper(), services); + } + return invoker; } } diff --git a/src/main/java/com/loafle/overflow/probe/container/server/ContainerJSONHandler.java b/src/main/java/com/loafle/overflow/probe/container/server/ContainerJSONHandler.java index 7b0f88b..11fa327 100644 --- a/src/main/java/com/loafle/overflow/probe/container/server/ContainerJSONHandler.java +++ b/src/main/java/com/loafle/overflow/probe/container/server/ContainerJSONHandler.java @@ -8,23 +8,15 @@ import com.loafle.overflow.probe.container.rpc.protocol.json.ServerResponse; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Component; -import java.io.IOException; - -@Component -@Qualifier("containerJSONHandler") @ChannelHandler.Sharable public class ContainerJSONHandler extends SimpleChannelInboundHandler { - @Autowired - private ObjectMapper objectMapper; - @Autowired - private Invoker invoker; @Override protected void channelRead0(ChannelHandlerContext ctx, String s) throws Exception { + ObjectMapper objectMapper = ContainerConfiguration.objectMapper(); + Invoker invoker = ContainerConfiguration.invoker(); + ServerRequest req = objectMapper.readValue(s, ServerRequest.class); ServerResponse res = null; try { diff --git a/src/main/java/com/loafle/overflow/probe/container/server/ContainerServer.java b/src/main/java/com/loafle/overflow/probe/container/server/ContainerServer.java index 0a822b2..ab9ebd2 100644 --- a/src/main/java/com/loafle/overflow/probe/container/server/ContainerServer.java +++ b/src/main/java/com/loafle/overflow/probe/container/server/ContainerServer.java @@ -1,34 +1,39 @@ package com.loafle.overflow.probe.container.server; import io.netty.bootstrap.ServerBootstrap; -import io.netty.channel.Channel; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; +import io.netty.channel.*; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.nio.NioServerSocketChannel; -import javax.annotation.PreDestroy; import java.net.InetSocketAddress; -@Component public class ContainerServer { - @Autowired - private ServerBootstrap serverBootstrap; - - @Autowired - private InetSocketAddress socketAddress; - - private Channel channel; + private int port = 19390; public ContainerServer() { - } public void start() throws Exception { - channel = serverBootstrap.bind(socketAddress).sync().channel().closeFuture().sync().channel(); + InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1", port); + + EventLoopGroup bossGroup = new NioEventLoopGroup(1); + EventLoopGroup workerGroup = new NioEventLoopGroup(10); + try { + ServerBootstrap b = new ServerBootstrap(); + + b.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .childHandler(ContainerConfiguration.channelInitializer()) + .option(ChannelOption.SO_BACKLOG, 128) + .childOption(ChannelOption.SO_KEEPALIVE, true); + + ChannelFuture f = b.bind(socketAddress).sync(); + + f.channel().closeFuture().sync(); + } finally { + workerGroup.shutdownGracefully(); + bossGroup.shutdownGracefully(); + } } - @PreDestroy - public void stop() throws Exception { - channel.close(); - channel.parent().close(); - } } diff --git a/src/main/java/com/loafle/overflow/probe/container/service/ConfigService.java b/src/main/java/com/loafle/overflow/probe/container/service/ConfigService.java new file mode 100644 index 0000000..8219bde --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/service/ConfigService.java @@ -0,0 +1,27 @@ +package com.loafle.overflow.probe.container.service; + +import com.loafle.overflow.probe.container.crawler.Crawler; +import com.loafle.overflow.probe.container.crawler.config.Config; + +import java.util.Map; + +public class ConfigService extends Service { + public ConfigService(Map crawlers) { + super(crawlers); + } + + public boolean init(String crawlerName, Config config) throws Exception { + Crawler crawler = getCrawler(crawlerName); + return crawler.init(config); + } + + public boolean add(String crawlerName, Config config) throws Exception { + Crawler crawler = getCrawler(crawlerName); + return crawler.add(config); + } + + public boolean remove(String crawlerName, String id) throws Exception { + Crawler crawler = getCrawler(crawlerName); + return crawler.remove(id); + } +} diff --git a/src/main/java/com/loafle/overflow/probe/container/service/DataService.java b/src/main/java/com/loafle/overflow/probe/container/service/DataService.java new file mode 100644 index 0000000..30a1fb0 --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/service/DataService.java @@ -0,0 +1,18 @@ +package com.loafle.overflow.probe.container.service; + +import com.loafle.overflow.probe.container.crawler.Crawler; +import com.loafle.overflow.probe.container.crawler.result.ResultSet; + +import java.util.List; +import java.util.Map; + +public class DataService extends Service { + public DataService(Map crawlers) { + super(crawlers); + } + + public List get(String crawlerName, String id) throws Exception { + Crawler crawler = getCrawler(crawlerName); + return crawler.get(id); + } +} diff --git a/src/main/java/com/loafle/overflow/probe/container/service/Service.java b/src/main/java/com/loafle/overflow/probe/container/service/Service.java new file mode 100644 index 0000000..0cc56b0 --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/service/Service.java @@ -0,0 +1,19 @@ +package com.loafle.overflow.probe.container.service; + +import com.loafle.overflow.probe.container.crawler.Crawler; + +import java.util.Map; + +public abstract class Service { + private Map crawlers; + protected Service(Map crawlers) { + this.crawlers = crawlers; + } + + protected Crawler getCrawler(String crawlerName) throws Exception { + if (!this.crawlers.containsKey(crawlerName)) { + throw new Exception(String.format("Container: Crawler[%s] is not exist", crawlerName)); + } + return this.crawlers.get(crawlerName); + } +} diff --git a/src/main/java/com/loafle/overflow/probe/container/service/StateService.java b/src/main/java/com/loafle/overflow/probe/container/service/StateService.java new file mode 100644 index 0000000..34f7d3a --- /dev/null +++ b/src/main/java/com/loafle/overflow/probe/container/service/StateService.java @@ -0,0 +1,15 @@ +package com.loafle.overflow.probe.container.service; + +import com.loafle.overflow.probe.container.crawler.Crawler; + +import java.util.Map; + +public class StateService extends Service { + public StateService(Map crawlers) { + super(crawlers); + } + + public boolean status() throws Exception { + return true; + } +} diff --git a/src/test/java/com/loafle/overflow/probe/container/ApplicationTests.java b/src/test/java/com/loafle/overflow/probe/container/ApplicationTests.java deleted file mode 100644 index 01b85a0..0000000 --- a/src/test/java/com/loafle/overflow/probe/container/ApplicationTests.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.loafle.overflow.probe.container; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.ApplicationContext; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -@RunWith(SpringJUnit4ClassRunner.class) -@SpringBootTest(classes = Application.class) -public class ApplicationTests { - - @Autowired - private ApplicationContext applicationContext; - - @Test - public void testStart() throws Exception { - - } - -} - - - diff --git a/src/test/java/com/loafle/overflow/probe/container/crawler/CrawlerTest.java b/src/test/java/com/loafle/overflow/probe/container/crawler/CrawlerTest.java new file mode 100644 index 0000000..9168554 --- /dev/null +++ b/src/test/java/com/loafle/overflow/probe/container/crawler/CrawlerTest.java @@ -0,0 +1,13 @@ +package com.loafle.overflow.probe.container.crawler; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.Before; + +public abstract class CrawlerTest { + protected ObjectMapper objectMapper; + @Before + public void setUp() throws Exception { + objectMapper = new ObjectMapper(); + } + +} diff --git a/src/test/java/com/loafle/overflow/probe/container/crawler/impl/database/DatabaseCrawlerTest.java b/src/test/java/com/loafle/overflow/probe/container/crawler/impl/database/DatabaseCrawlerTest.java new file mode 100644 index 0000000..9b10106 --- /dev/null +++ b/src/test/java/com/loafle/overflow/probe/container/crawler/impl/database/DatabaseCrawlerTest.java @@ -0,0 +1,62 @@ +package com.loafle.overflow.probe.container.crawler.impl.database; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.loafle.overflow.probe.container.crawler.CrawlerTest; +import com.loafle.overflow.probe.container.crawler.config.Config; +import com.loafle.overflow.probe.container.crawler.result.ResultSet; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public abstract class DatabaseCrawlerTest extends CrawlerTest { +// //MySQL +// info.setUrl("jdbc:mysql://192.168.1.215:3306"); // ?useSSL=true&verifyServerCertificate=false +// info.setId("root"); +// info.setPw("qwe123"); +// info.setSSL(false); +// info.setQuery("show session status"); +// //MSSQL +// info.setUrl("jdbc:sqlserver://192.168.1.103:1433;"); //encrypt=false;trustServerCertificate=true" +// info.setId("sa"); +// info.setPw("qwer5795"); +// info.setSSL(true); +// info.setQuery("select * from master.dbo.sysprocesses"); +// //PGSQL +// info.setUrl("jdbc:postgresql://192.168.1.107:5432/postgres"); +// info.setId("postgres"); +// info.setPw("!@#$qwer1234"); +// info.setSSL(false); +// info.setQuery("select * from pg_stat_activity"); +// //Oracle +// info.setUrl("jdbc:oracle:thin:@192.168.1.30:1521/oracle.loafle.com"); +// info.setId("sys as sysdba"); +// info.setPw("qwer5795QWER"); +// info.setSSL(false); +// info.setQuery("select * from v$sysstat"); + protected Config getConfig(String path) throws IOException { + ClassLoader classLoader = getClass().getClassLoader(); + String filePath = classLoader.getResource(path).getFile(); + + Config c = objectMapper.readValue(new File(filePath),Config.class); + return c; + } + + protected void print(String s, List mm) { + + System.out.println(s); + + Map m = new HashMap<>(); + for(ResultSet r : mm) { + m.putAll(r.getData()); + } + + for (Map.Entry item : m.entrySet()) { + System.out.println("key=" + item.getKey() + " ||||||||||| value=" + item.getValue()); + } + } + + +} diff --git a/src/test/java/com/loafle/overflow/probe/container/crawler/impl/database/mysql/MySQLCrawlerTest.java b/src/test/java/com/loafle/overflow/probe/container/crawler/impl/database/mysql/MySQLCrawlerTest.java new file mode 100644 index 0000000..faa48b2 --- /dev/null +++ b/src/test/java/com/loafle/overflow/probe/container/crawler/impl/database/mysql/MySQLCrawlerTest.java @@ -0,0 +1,15 @@ +package com.loafle.overflow.probe.container.crawler.impl.database.mysql; + +import com.loafle.overflow.probe.container.crawler.impl.database.DatabaseCrawlerTest; +import com.loafle.overflow.probe.container.crawler.result.ResultSet; +import org.junit.Test; + +import java.util.List; + +public class MySQLCrawlerTest extends DatabaseCrawlerTest { + @Test + public void testMySQL() throws Exception { + Object result = new MySQLCrawler().getInternal( getConfig("config/mysql/mysql-test.json")); + print("MySQL row", (List) result); + } +} \ No newline at end of file diff --git a/src/test/java/com/loafle/overflow/probe/container/crawler/impl/database/oracle/OracleCrawlerTest.java b/src/test/java/com/loafle/overflow/probe/container/crawler/impl/database/oracle/OracleCrawlerTest.java new file mode 100644 index 0000000..6c82da1 --- /dev/null +++ b/src/test/java/com/loafle/overflow/probe/container/crawler/impl/database/oracle/OracleCrawlerTest.java @@ -0,0 +1,15 @@ +package com.loafle.overflow.probe.container.crawler.impl.database.oracle; + +import com.loafle.overflow.probe.container.crawler.impl.database.DatabaseCrawlerTest; +import com.loafle.overflow.probe.container.crawler.result.ResultSet; +import org.junit.Test; + +import java.util.List; + +public class OracleCrawlerTest extends DatabaseCrawlerTest { + @Test + public void testMySQL() throws Exception { + Object result = new OracleCrawler().getInternal( getConfig("config/oracle/oracle-test.json")); + print("Oracle row", (List) result); + } +} \ No newline at end of file diff --git a/src/test/java/com/loafle/overflow/probe/container/crawler/impl/database/postgresql/PostgreSQLCrawlerTest.java b/src/test/java/com/loafle/overflow/probe/container/crawler/impl/database/postgresql/PostgreSQLCrawlerTest.java new file mode 100644 index 0000000..b8e8669 --- /dev/null +++ b/src/test/java/com/loafle/overflow/probe/container/crawler/impl/database/postgresql/PostgreSQLCrawlerTest.java @@ -0,0 +1,15 @@ +package com.loafle.overflow.probe.container.crawler.impl.database.postgresql; + +import com.loafle.overflow.probe.container.crawler.impl.database.DatabaseCrawlerTest; +import com.loafle.overflow.probe.container.crawler.result.ResultSet; +import org.junit.Test; + +import java.util.List; + +public class PostgreSQLCrawlerTest extends DatabaseCrawlerTest { + @Test + public void testPostgreSQL() throws Exception { + Object result = new PostgreSQLCrawler().getInternal( getConfig("config/postgresql/postgresql.json")); + print("PostgreSQL", (List) result); + } +} \ No newline at end of file diff --git a/src/test/java/com/loafle/overflow/probe/container/crawler/impl/database/sqlserver/SQLServerCrawlerTest.java b/src/test/java/com/loafle/overflow/probe/container/crawler/impl/database/sqlserver/SQLServerCrawlerTest.java new file mode 100644 index 0000000..90cd197 --- /dev/null +++ b/src/test/java/com/loafle/overflow/probe/container/crawler/impl/database/sqlserver/SQLServerCrawlerTest.java @@ -0,0 +1,22 @@ +package com.loafle.overflow.probe.container.crawler.impl.database.sqlserver; + +import com.loafle.overflow.probe.container.crawler.impl.database.DatabaseCrawlerTest; +import com.loafle.overflow.probe.container.crawler.result.ResultSet; +import org.junit.Test; + +import java.util.List; + +public class SQLServerCrawlerTest extends DatabaseCrawlerTest { + @Test + public void testConnection_Count() throws Exception { + Object result = new SQLServerCrawler().getInternal( getConfig("config/sqlserver/sqlserver_connection_count.json")); + print("SQL Server Connection count", (List) result); + } + + @Test + public void testMultiKeyArray() throws Exception { + Object result = new SQLServerCrawler().getInternal( getConfig("config/sqlserver/sqlserver_multiple_key_array.json")); + print("SQL Server MultiArray", (List) result); + } + +} \ No newline at end of file diff --git a/src/test/java/com/loafle/overflow/probe/container/crawler/impl/jmx/JMXCrawlerTest.java b/src/test/java/com/loafle/overflow/probe/container/crawler/impl/jmx/JMXCrawlerTest.java new file mode 100644 index 0000000..39d03e8 --- /dev/null +++ b/src/test/java/com/loafle/overflow/probe/container/crawler/impl/jmx/JMXCrawlerTest.java @@ -0,0 +1,6 @@ +package com.loafle.overflow.probe.container.crawler.impl.jmx; + +import com.loafle.overflow.probe.container.crawler.CrawlerTest; + +public class JMXCrawlerTest extends CrawlerTest { +} \ No newline at end of file diff --git a/src/test/java/com/loafle/overflow/probe/container/crawler/impl/jmx/tomcat/TomcatCrawlerTest.java b/src/test/java/com/loafle/overflow/probe/container/crawler/impl/jmx/tomcat/TomcatCrawlerTest.java new file mode 100644 index 0000000..0f8881c --- /dev/null +++ b/src/test/java/com/loafle/overflow/probe/container/crawler/impl/jmx/tomcat/TomcatCrawlerTest.java @@ -0,0 +1,65 @@ +package com.loafle.overflow.probe.container.crawler.impl.jmx.tomcat; + +import com.loafle.overflow.probe.container.crawler.config.Config; +import com.loafle.overflow.probe.container.crawler.impl.jmx.JMXCrawler; +import com.loafle.overflow.probe.container.crawler.impl.jmx.JMXCrawlerTest; +import com.loafle.overflow.probe.container.crawler.result.ResultSet; +import org.junit.Test; + +import java.io.File; +import java.net.URL; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +public class TomcatCrawlerTest extends JMXCrawlerTest { + + @Test + public void testSum() { + assertEquals(1,1); + } + + @Test + public void TestDoCrawler() throws Exception { + + ClassLoader classLoader = getClass().getClassLoader(); + URL url = classLoader.getResource("config/tomcat/"); + String path = classLoader.getResource("config/tomcat/example1.json").getFile(); + + Config c = objectMapper.readValue(new File(path),Config.class); + + JMXCrawler cr = new JMXCrawler(); + List result = (List) cr.getInternal(c); + + print("",result); + } + + + //keytool -export -alias alias_name -keystore path_to_keystore_file -rfc -file path_to_certificate_file + private void print(String s, List mm) { + + System.out.println(s); + + Map m = new HashMap<>(); + for(ResultSet r : mm) { + m.putAll(r.getData()); + } + + for (Map.Entry item : m.entrySet()) { + System.out.println("key=" + item.getKey() + " ||||||||||| value=" + item.getValue()); + } + } + + @Test + public void testParseObject () { + + String s = "org.apache.catalina.mbeans.ConnectorMBean[Catalina:type=Connector,port=8080]"; + + int start = s.indexOf("["); + int end = s.lastIndexOf("]"); + s = s.substring(start + 1,end); + assertEquals("Catalina:type=Connector,port=8080",s); + } +} diff --git a/src/test/java/com/loafle/overflow/probe/container/crawler/impl/mongodb/MongoDBCrawlerTest.java b/src/test/java/com/loafle/overflow/probe/container/crawler/impl/mongodb/MongoDBCrawlerTest.java new file mode 100644 index 0000000..e30091f --- /dev/null +++ b/src/test/java/com/loafle/overflow/probe/container/crawler/impl/mongodb/MongoDBCrawlerTest.java @@ -0,0 +1,45 @@ +package com.loafle.overflow.probe.container.crawler.impl.mongodb; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.loafle.overflow.probe.container.crawler.CrawlerTest; +import com.loafle.overflow.probe.container.crawler.config.Config; +import com.loafle.overflow.probe.container.crawler.result.ResultSet; +import org.junit.Ignore; +import org.junit.Test; + +import java.io.File; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.*; + +public class MongoDBCrawlerTest extends CrawlerTest { + + @Test + @Ignore + public void TestCollectMetric() throws Exception { + + + // read test resources config/example.json + ClassLoader classLoader = getClass().getClassLoader(); + String path = classLoader.getResource("config/mongodb/example.json").getFile(); + + Config c = objectMapper.readValue(new File(path),Config.class); + + MongoDBCrawler cr = new MongoDBCrawler(); + List rl = (List)cr.collectMetric(c); + + for(int indexI = 0 ; indexI < rl.size(); ++indexI) { + Map m = rl.get(indexI).getData(); + for( String key : m.keySet()) { + System.out.print("key : " + key); + System.out.print("|| value : "); + System.out.println(m.get(key)); + } + } + + +// assertEquals(6, m.size()); + } + +} \ No newline at end of file diff --git a/src/test/java/com/loafle/overflow/probe/container/crawler/impl/redis/RedisCralwerTest.java b/src/test/java/com/loafle/overflow/probe/container/crawler/impl/redis/RedisCralwerTest.java new file mode 100644 index 0000000..bbfe332 --- /dev/null +++ b/src/test/java/com/loafle/overflow/probe/container/crawler/impl/redis/RedisCralwerTest.java @@ -0,0 +1,47 @@ +package com.loafle.overflow.probe.container.crawler.impl.redis; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.loafle.overflow.probe.container.crawler.CrawlerTest; +import com.loafle.overflow.probe.container.crawler.config.Config; +import com.loafle.overflow.probe.container.crawler.result.ResultSet; +import org.junit.Ignore; +import org.junit.Test; + +import java.io.File; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.*; + +public class RedisCralwerTest extends CrawlerTest { + + @Test + @Ignore + public void collectMetric() throws Exception { + ClassLoader classLoader = getClass().getClassLoader(); + String path = classLoader.getResource("config/redis/example.json").getFile(); + + Config c = objectMapper.readValue(new File(path),Config.class); + + RedisCralwer rc = new RedisCralwer(); + List result = (List) rc.getInternal(c); + print("",result); + } + + + private void print(String s, List mm) { + + System.out.println(s); + + Map m = new HashMap<>(); + for(ResultSet r : mm) { + m.putAll(r.getData()); + } + + for (Map.Entry item : m.entrySet()) { + System.out.println("key=" + item.getKey() + " ||||||||||| value=" + item.getValue()); + } + } + +} \ No newline at end of file diff --git a/src/test/java/com/loafle/overflow/probe/container/crawler/impl/snmp/SNMPCrawlerTest.java b/src/test/java/com/loafle/overflow/probe/container/crawler/impl/snmp/SNMPCrawlerTest.java new file mode 100644 index 0000000..27659fd --- /dev/null +++ b/src/test/java/com/loafle/overflow/probe/container/crawler/impl/snmp/SNMPCrawlerTest.java @@ -0,0 +1,79 @@ +package com.loafle.overflow.probe.container.crawler.impl.snmp; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.loafle.overflow.probe.container.crawler.CrawlerTest; +import com.loafle.overflow.probe.container.crawler.config.Config; +import com.loafle.overflow.probe.container.crawler.result.ResultSet; +import org.junit.Ignore; +import org.junit.Test; + +import java.io.File; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.*; + +public class SNMPCrawlerTest extends CrawlerTest { + /*** + * v2c test info + * private static String addr = "192.168.1.215"; + * private static String port = "161"; + * private static String community = "public"; + * + * v3 test info + * loafle MD5 "qwer5795" DES "qweqwe123" : AUTHPRIV + * loafle2 SHA "qwer5795" AES "qweqwe123" : AUTHPRIV + * loafle3 MD5 "qwer5795" : AUTHNOPRIV + * loafle4 :NOAUTHNOPRIV + */ + + @Ignore + @Test + public void testSNMP3() throws Exception { + SNMPCrawler c = new SNMPCrawler(); + ClassLoader classLoader = getClass().getClassLoader(); + String p = classLoader.getResource("config/snmp/examplev3.json").getFile(); + Config config = objectMapper.readValue(new File(p),Config.class); + + Object result = c.getInternal(config); + + if(result instanceof Boolean) { + System.out.println("validate : " + result); + }else { + printResult((List)result); + } + + } + + @Ignore + @Test + public void testSNMP2c() throws Exception { + SNMPCrawler c = new SNMPCrawler(); + + ClassLoader classLoader = getClass().getClassLoader(); + String p = classLoader.getResource("config/snmp/examplev2.json").getFile(); + Config config = objectMapper.readValue(new File(p),Config.class); + + Object result = c.getInternal(config); + + if(result instanceof Boolean) { + System.out.println("validate : " + result); + }else { + printResult((List)result); + } + + } + + private void printResult(List resultList) { + for(int indexI = 0 ; indexI < resultList.size(); ++indexI) { + Map resultMap = resultList.get(indexI).getData(); + System.out.println("============================================"); + for( String key : resultMap.keySet() ){ + System.out.println( String.format("key : %s ||| value : %s", key, resultMap.get(key)) ); + } + System.out.println("============================================"); + } + + } + +} \ No newline at end of file diff --git a/src/test/java/com/loafle/overflow/probe/container/crawler/impl/wmi/WMICrawlerTest.java b/src/test/java/com/loafle/overflow/probe/container/crawler/impl/wmi/WMICrawlerTest.java new file mode 100644 index 0000000..9037bca --- /dev/null +++ b/src/test/java/com/loafle/overflow/probe/container/crawler/impl/wmi/WMICrawlerTest.java @@ -0,0 +1,313 @@ +package com.loafle.overflow.probe.container.crawler.impl.wmi; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.loafle.overflow.probe.container.crawler.CrawlerTest; +import com.loafle.overflow.probe.container.crawler.config.Config; +import com.loafle.overflow.probe.container.crawler.result.ResultSet; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.*; + +import static org.junit.Assert.*; + +public class WMICrawlerTest extends CrawlerTest { + @Before + public void setUp() throws Exception { + + } + + @After + public void tearDown() throws Exception { + + } + + + // @Ignore + @Test + public void testLinuxExe() throws Exception { + + String command = "/home/snoop/temp/wmic"; + + ProcessBuilder builder = new ProcessBuilder(command, "-U","administrator%dbseogns18", "//192.168.1.106", "SELECT Caption FROM Win32_LogicalDisk", "--namespace=root/cimv2", "--delimiter=||"); + Process process = builder.start(); + + byte[] msg = new byte[1024]; + + StringBuffer buf = new StringBuffer(); + + while(process.getInputStream().read(msg) > 0) { + buf.append(new String(msg)); + Arrays.fill(msg, (byte)0); + } + + System.out.println(buf.toString()); + } + + @Test + public void testWMI() throws Exception { + WMICrawler wmiCrawler = new WMICrawler(); + + Map map = new HashMap(); + +// String id = "administrator"; +// String pw = "!@#$qwer1234"; +// String nameSpace = "root/cimv2"; +// String query = "select * from Win32_OperatingSystem"; +// String ip = "192.168.1.1"; + +// map.put("id", "administrator"); +// map.put("pw", "!@#$qwer1234"); +// map.put("nameSpace", "root/cimv2"); +// map.put("query", "select * from Win32_OperatingSystem"); +// map.put("ip", "192.168.1.1"); + + Config config = new Config(); + + ClassLoader classLoader = getClass().getClassLoader(); + + String s = classLoader.getResource("config/wmi").getFile(); + System.out.println(s); + +// Config c = mapper.readValue(new File(classLoader.getResource("config").getFile()),Config.class); + + +// List> resultList = (List>)wmiCrawler.getInternal(map); +// +// +// for( Map rMap : resultList) { +// for( String key : rMap.keySet() ){ +// System.out.println( String.format("key : %s ||| value : %s", key, rMap.get(key)) ); +// } +// } + + + } + + @Test + public void testOS() { + System.out.println(System.getProperty("os.name")); + + } + + @Test + public void testConfig() throws IOException { + ClassLoader classLoader = getClass().getClassLoader(); + String p = classLoader.getResource("config/wmi/example.json").getFile(); + + System.out.println(p); + + + Config c = objectMapper.readValue(new File(p),Config.class); + + System.out.println(c); + } + + // @Ignore + @Test + public void testWMIJson() throws Exception { + ClassLoader classLoader = getClass().getClassLoader(); + String p = classLoader.getResource("config/wmi/meta/meta_network.json").getFile(); + Config c = objectMapper.readValue(new File(p),Config.class); + +// Map map = new HashMap<>(); +// map.put("id", "administrator"); +// map.put("pw", "!@#$qwer1234"); + +// c.getTarget().setAuth(map); + +// c.getTarget().getAuth().put("id", "administrator"); +// c.getTarget().getAuth().put("pw", "!@#$qwer1234"); + + + WMICrawler wmiCrawler = new WMICrawler(); + + + List resultList = (List)wmiCrawler.getInternal(c); + + PrintResultList(resultList); +// for(int indexI = 0 ; indexI < resultList.size(); ++indexI) { +// Map resultMap = resultList.get(indexI).getData(); +// System.out.println("============================================"); +// for( String key : resultMap.keySet() ){ +// System.out.println( String.format("key : %s ||| value : %s", key, resultMap.get(key)) ); +// } +// System.out.println("============================================"); +// } + + + + + + } + + public void PrintResultList(List resultList) { + for(int indexI = 0 ; indexI < resultList.size(); ++indexI) { + Map resultMap = resultList.get(indexI).getData(); + System.out.println("============================================"); + for( String key : resultMap.keySet() ){ + System.out.println( String.format("key : %s ||| value : %s", key, resultMap.get(key)) ); + } + System.out.println("============================================"); + } + } + + @Test + public void testMetaProcess() throws Exception { + + // get targetinfo + ClassLoader classLoader = getClass().getClassLoader(); + String p = classLoader.getResource("config/wmi/test.json").getFile(); + Config c = objectMapper.readValue(new File(p),Config.class); + + List metaConfigList = loadMetaConfig(); + + + List retlist = new ArrayList<>(); + WMICrawlerOS os = WMICrawlerOS.getInstance(); + ResultSet ofResultSet = null; + for(Config metaConfig : metaConfigList) { + + for(int indexI = 0; indexI < metaConfig.getItems().size(); ++indexI) { + ofResultSet = os.processWMI(c, metaConfig.getItems().get(indexI)); + if(ofResultSet != null) { + retlist.add(ofResultSet); + } + } + } + + + + + + PrintResultList(retlist); + + } + + public List loadMetaConfig() throws IOException { + ClassLoader classLoader = getClass().getClassLoader(); + + URL url = classLoader.getResource("config/wmi/meta"); + if(url == null) { + return null; + } + + String path = url.getFile(); + + File pathFile = new File(path); + + System.out.println(path); + String[] metaFiles = pathFile.list(); + List retList = new ArrayList<>(); + Config metaConfig = null; + for(String fi : metaFiles) { + if(fi.indexOf("meta_") > -1) { + metaConfig = objectMapper.readValue(new File(path+"/"+fi), Config.class); + if(metaConfig != null) { + retList.add(metaConfig); + } + } + } + + return retList; + } + + @Test + public void testInt() { + + Integer a = 1; + + aaa(a); + + System.out.println(a); + + } + + public void aaa(Integer a) { + ++a; + + } + + @Test + public void testString() { + + String str = "cpu[].usage.system"; + + int idx = str.indexOf("["); + int arrIdx = 0; + + String ret = ""; + ret += str.substring(0, idx +1); + ret += String.valueOf(arrIdx); + ret += str.substring(idx +1); + + System.out.println(ret); + + } + + @Test + public void testReplace() { + + + String aaa = "cpu[$0].usage.system"; + + String bbb = "$"; + String ccc = bbb + String.valueOf(0); + + String ddd = aaa.replace(ccc, "asdfasdf"); + + + System.out.println(ddd); + + + + } + + @Test + public void testMap() { + + + Map aa = new HashMap<>(); + + aa.put("111", "123123123"); + aa.put("222", "123123123"); + + Map bb = new HashMap<>(); + + + bb.put("333", "123123123"); + bb.put("444", "123123123"); + + + aa.putAll(bb); + + for( String key : aa.keySet() ){ + System.out.println( String.format("key : %s ||| value : %s", key, aa.get(key)) ); + } + + + } + + @Test + public void testRes() throws IOException { + ClassLoader classLoader = getClass().getClassLoader(); + + URL url = classLoader.getResource("config/wmi/meta"); + + + File file = new File(url.getFile()); + + String[] fl = file.list(); + + for(String f : fl) { + System.out.println(f); + } + + + } + +} diff --git a/src/test/resources/config/mongodb/example.json b/src/test/resources/config/mongodb/example.json new file mode 100644 index 0000000..cb4c423 --- /dev/null +++ b/src/test/resources/config/mongodb/example.json @@ -0,0 +1,43 @@ +{ + "id" : "SOEJWEOJWOEJOSDJFOASDJFOSDFO2903870928734", + "target" : { + "connection" : { + "ip" : "192.168.1.215", + "port" : "27017", + "ssl" : false, + "portType" : "tcp" + }, + "auth" : { + + } + }, + "schedule" : { + "interval" : "10" + }, + "crawler" : { + "name":"mongodb", + "container":"java_proxy" + }, + "items" : [ + { + "keys" : [ + {"metric":"memory.usage.bits", "key":"bits"}, + {"metric":"memory.usage.rss", "key":"resident"}, + {"metric":"memory.usage.vmem", "key":"virtual"}, + {"metric":"memory.usage.supported", "key":"supported"}, + {"metric":"memory.usage.mapped", "key":"mapped"}, + {"metric":"memory.usage.mappedWithJournal", "key":"mappedWithJournal"} + ], + "queryInfo" : { + "query": "mem", + "extend" : { + "dataBaseName":"admin", + "statusCommand": "serverStatus" + } + }, + "mappingInfo" : { + "parseDirection" : "col" + } + } + ] +} diff --git a/src/test/resources/config/mysql/mysql-test.json b/src/test/resources/config/mysql/mysql-test.json new file mode 100644 index 0000000..7689231 --- /dev/null +++ b/src/test/resources/config/mysql/mysql-test.json @@ -0,0 +1,395 @@ +{ + "id": "3", + "target": { + "auth": { + "pw": "qwer5795QWER", + "id": "docker", + "url": "jdbc:mysql://192.168.1.15:33067" + }, + "connection": { + "ip": "192.168.1.15", + "port": "33067", + "portType": "TCP", + "ssl": false + } + }, + "schedule": { + "interval": "5" + }, + "crawler": { + "name": "MYSQL_CRAWLER", + "container": "java_proxy" + }, + "items": [{ + "keys": [{ + "metric": "Performance.mysql.schema.users.lost", + "key": "Performance_schema_users_lost" + }, + { + "metric": "Performance.mysql.schema.thread.instances.lost", + "key": "Performance_schema_thread_instances_lost" + }, + { + "metric": "Performance.mysql.schema.thread.classes.lost", + "key": "Performance_schema_thread_classes_lost" + }, + { + "metric": "Performance.mysql.schema.table.lock.stat.lost", + "key": "Performance_schema_table_lock_stat_lost" + }, + { + "metric": "Performance.mysql.schema.table.instances.lost", + "key": "Performance_schema_table_instances_lost" + }, + { + "metric": "Performance.mysql.schema.table.handles.lost", + "key": "Performance_schema_table_handles_lost" + }, + { + "metric": "Performance.mysql.schema.statement.classes.lost", + "key": "Performance_schema_statement_classes_lost" + }, + { + "metric": "Performance.mysql.schema.stage.classes.lost", + "key": "Performance_schema_stage_classes_lost" + }, + { + "metric": "Performance.mysql.schema.socket.instances.lost", + "key": "Performance_schema_socket_instances_lost" + }, + { + "metric": "Performance.mysql.schema.socket.classes.lost", + "key": "Performance_schema_socket_classes_lost" + }, + { + "metric": "Performance.mysql.schema.session.connect.attrs.lost", + "key": "Performance_schema_session_connect_attrs_lost" + }, + { + "metric": "Performance.mysql.schema.rwlock.instances.lost", + "key": "Performance_schema_rwlock_instances_lost" + }, + { + "metric": "Performance.mysql.schema.rwlock.classes.lost", + "key": "Performance_schema_rwlock_classes_lost" + }, + { + "metric": "Performance.mysql.schema.program.lost", + "key": "Performance_schema_program_lost" + }, + { + "metric": "Performance.mysql.schema.prepared.statements.lost", + "key": "Performance_schema_prepared_statements_lost" + }, + { + "metric": "Performance.mysql.schema.nested.statement.lost", + "key": "Performance_schema_nested_statement_lost" + }, + { + "metric": "Performance.mysql.schema.mutex.instances.lost", + "key": "Performance_schema_mutex_instances_lost" + }, + { + "metric": "Performance.mysql.schema.mutex.classes.lost", + "key": "Performance_schema_mutex_classes_lost" + }, + { + "metric": "Performance.mysql.schema.metadata.lock.lost", + "key": "Performance_schema_metadata_lock_lost" + }, + { + "metric": "Performance.mysql.schema.memory.classes.lost", + "key": "Performance_schema_memory_classes_lost" + }, + { + "metric": "Performance.mysql.schema.locker.lost", + "key": "Performance_schema_locker_lost" + }, + { + "metric": "Performance.mysql.schema.index.stat.lost", + "key": "Performance_schema_index_stat_lost" + }, + { + "metric": "Performance.mysql.schema.hosts.lost", + "key": "Performance_schema_hosts_lost" + }, + { + "metric": "Performance.mysql.schema.file.instances.lost", + "key": "Performance_schema_file_instances_lost" + }, + { + "metric": "Performance.mysql.schema.file.handles.lost", + "key": "Performance_schema_file_handles_lost" + }, + { + "metric": "Performance.mysql.schema.file.classes.lost", + "key": "Performance_schema_file_classes_lost" + }, + { + "metric": "Performance.mysql.schema.digest.lost", + "key": "Performance_schema_digest_lost" + }, + { + "metric": "Performance.mysql.schema.cond.instances.lost", + "key": "Performance_schema_cond_instances_lost" + }, + { + "metric": "Performance.mysql.schema.cond.classes.lost", + "key": "Performance_schema_cond_classes_lost" + }, + { + "metric": "Performance.mysql.schema.accounts.lost", + "key": "Performance_schema_accounts_lost" + }, + { + "metric": "Connection.mysql.Max.used.connections.time", + "key": "Max_used_connections_time" + }, + { + "metric": "Connection.mysql.Max.used.connections", + "key": "Max_used_connections" + }, + { + "metric": "Connection.mysql.connections", + "key": "Connections" + }, + { + "metric": "Connection.mysql.errors.tcpwrap", + "key": "Connection_errors_tcpwrap" + }, + { + "metric": "Connection.mysql.errors.select", + "key": "Connection_errors_select" + }, + { + "metric": "Connection.mysql.errors.peer.address", + "key": "Connection_errors_peer_address" + }, + { + "metric": "Connection.mysql.errors.max.connections", + "key": "Connection_errors_max_connections" + }, + { + "metric": "Connection.mysql.errors.internal", + "key": "Connection_errors_internal" + }, + { + "metric": "Connection.mysql.errors.accept", + "key": "Connection_errors_accept" + }, + { + "metric": "Innodb.mysql.available.undo.logs", + "key": "Innodb_available_undo_logs" + }, + { + "metric": "Innodb.mysql.truncated.status.writes", + "key": "Innodb_truncated_status_writes" + }, + { + "metric": "Innodb.mysql.num.open.files", + "key": "Innodb_num_open_files" + }, + { + "metric": "Innodb.mysql.rows.updated", + "key": "Innodb_rows_updated" + }, + { + "metric": "Innodb.mysql.rows.read", + "key": "Innodb_rows_read" + }, + { + "metric": "Innodb.mysql.rows.inserted", + "key": "Innodb_rows_inserted" + }, + { + "metric": "Innodb.mysql.rows.deleted", + "key": "Innodb_rows_deleted" + }, + { + "metric": "Innodb.mysql.row.lock.waits", + "key": "Innodb_row_lock_waits" + }, + { + "metric": "Innodb.mysql.row.lock.time.max", + "key": "Innodb_row_lock_time_max" + }, + { + "metric": "Innodb.mysql.row.lock.time.avg", + "key": "Innodb_row_lock_time_avg" + }, + { + "metric": "Innodb.mysql.row.lock.time", + "key": "Innodb_row_lock_time" + }, + { + "metric": "Innodb.mysql.row.lock.current.waits", + "key": "Innodb_row_lock_current_waits" + }, + { + "metric": "Innodb.mysql.pages.written", + "key": "Innodb_pages_written" + }, + { + "metric": "Innodb.mysql.pages.read", + "key": "Innodb_pages_read" + }, + { + "metric": "Innodb.mysql.pages.created", + "key": "Innodb_pages_created" + }, + { + "metric": "Innodb.mysql.page.size", + "key": "Innodb_page_size" + }, + { + "metric": "Innodb.mysql.os.log.written", + "key": "Innodb_os_log_written" + }, + { + "metric": "Innodb.mysql.os.log.pending.writes", + "key": "Innodb_os_log_pending_writes" + }, + { + "metric": "Innodb.mysql.os.log.pending.fsyncs", + "key": "Innodb_os_log_pending_fsyncs" + }, + { + "metric": "Innodb.mysql.os.log.fsyncs", + "key": "Innodb_os_log_fsyncs" + }, + { + "metric": "Innodb.mysql.log.writes", + "key": "Innodb_log_writes" + }, + { + "metric": "Innodb.mysql.log.write.requests", + "key": "Innodb_log_write_requests" + }, + { + "metric": "Innodb.mysql.log.waits", + "key": "Innodb_log_waits" + }, + { + "metric": "Innodb.mysql.dblwr.writes", + "key": "Innodb_dblwr_writes" + }, + { + "metric": "Innodb.mysql.dblwr.pages.written", + "key": "Innodb_dblwr_pages_written" + }, + { + "metric": "Innodb.mysql.data.written", + "key": "Innodb_data_written" + }, + { + "metric": "Innodb.mysql.data.writes", + "key": "Innodb_data_writes" + }, + { + "metric": "Innodb.mysql.data.reads", + "key": "Innodb_data_reads" + }, + { + "metric": "Innodb.mysql.data.read", + "key": "Innodb_data_read" + }, + { + "metric": "Innodb.mysql.data.pending.writes", + "key": "Innodb_data_pending_writes" + }, + { + "metric": "Innodb.mysql.data.pending.reads", + "key": "Innodb_data_pending_reads" + }, + { + "metric": "Innodb.mysql.data.pending.fsyncs", + "key": "Innodb_data_pending_fsyncs" + }, + { + "metric": "Innodb.mysql.data.fsyncs", + "key": "Innodb_data_fsyncs" + }, + { + "metric": "Innodb.mysql.buffer.pool.write.requests", + "key": "Innodb_buffer_pool_write_requests" + }, + { + "metric": "Innodb.mysql.buffer.pool.wait.free", + "key": "Innodb_buffer_pool_wait_free" + }, + { + "metric": "Innodb.mysql.buffer.pool.reads", + "key": "Innodb_buffer_pool_reads" + }, + { + "metric": "Innodb.mysql.buffer.pool.read.requests", + "key": "Innodb_buffer_pool_read_requests" + }, + { + "metric": "Innodb.mysql.buffer.pool.read.ahead.evicted", + "key": "Innodb_buffer_pool_read_ahead_evicted" + }, + { + "metric": "Innodb.mysql.buffer.pool.read.ahead", + "key": "Innodb_buffer_pool_read_ahead" + }, + { + "metric": "Innodb.mysql.buffer.pool.read.ahead.rnd", + "key": "Innodb_buffer_pool_read_ahead_rnd" + }, + { + "metric": "Innodb.mysql.buffer.pool.pages.total", + "key": "Innodb_buffer_pool_pages_total" + }, + { + "metric": "Innodb.mysql.buffer.pool.pages.misc", + "key": "Innodb_buffer_pool_pages_misc" + }, + { + "metric": "Innodb.mysql.buffer.pool.pages.free", + "key": "Innodb_buffer_pool_pages_free" + }, + { + "metric": "Innodb.mysql.buffer.pool.pages.flushed", + "key": "Innodb_buffer_pool_pages_flushed" + }, + { + "metric": "Innodb.mysql.buffer.pool.bytes.dirty", + "key": "Innodb_buffer_pool_bytes_dirty" + }, + { + "metric": "Innodb.mysql.buffer.pool.pages.dirty", + "key": "Innodb_buffer_pool_pages_dirty" + }, + { + "metric": "Innodb.mysql.buffer.pool.bytes.data", + "key": "Innodb_buffer_pool_bytes_data" + }, + { + "metric": "Innodb.mysql.buffer.pool.pages.data", + "key": "Innodb_buffer_pool_pages_data" + }, + { + "metric": "Innodb.mysql.buffer.pool.resize.status", + "key": "Innodb_buffer_pool_resize_status" + }, + { + "metric": "Innodb.mysql.buffer.pool.load.status", + "key": "Innodb_buffer_pool_load_status" + }, + { + "metric": "Innodb.mysql.buffer.pool.dump.status", + "key": "Innodb_buffer_pool_dump_status" + }], + "queryInfo": { + "query": "show status where variable_name = 'Performance_schema_users_lost' or variable_name = 'Performance_schema_thread_instances_lost' or variable_name = 'Performance_schema_thread_classes_lost' or variable_name = 'Performance_schema_table_lock_stat_lost' or variable_name = 'Performance_schema_table_instances_lost' or variable_name = 'Performance_schema_table_handles_lost' or variable_name = 'Performance_schema_statement_classes_lost' or variable_name = 'Performance_schema_stage_classes_lost' or variable_name = 'Performance_schema_socket_instances_lost' or variable_name = 'Performance_schema_socket_classes_lost' or variable_name = 'Performance_schema_session_connect_attrs_lost' or variable_name = 'Performance_schema_rwlock_instances_lost' or variable_name = 'Performance_schema_rwlock_classes_lost' or variable_name = 'Performance_schema_program_lost' or variable_name = 'Performance_schema_prepared_statements_lost' or variable_name = 'Performance_schema_nested_statement_lost' or variable_name = 'Performance_schema_mutex_instances_lost' or variable_name = 'Performance_schema_mutex_classes_lost' or variable_name = 'Performance_schema_metadata_lock_lost' or variable_name = 'Performance_schema_memory_classes_lost' or variable_name = 'Performance_schema_locker_lost' or variable_name = 'Performance_schema_index_stat_lost' or variable_name = 'Performance_schema_hosts_lost' or variable_name = 'Performance_schema_file_instances_lost' or variable_name = 'Performance_schema_file_handles_lost' or variable_name = 'Performance_schema_file_classes_lost' or variable_name = 'Performance_schema_digest_lost' or variable_name = 'Performance_schema_cond_instances_lost' or variable_name = 'Performance_schema_cond_classes_lost' or variable_name = 'Performance_schema_accounts_lost' or variable_name = 'Max_used_connections_time' or variable_name = 'Max_used_connections' or variable_name = 'Connections' or variable_name = 'Connection_errors_tcpwrap' or variable_name = 'Connection_errors_select' or variable_name = 'Connection_errors_peer_address' or variable_name = 'Connection_errors_max_connections' or variable_name = 'Connection_errors_internal' or variable_name = 'Connection_errors_accept' or variable_name = 'Innodb_available_undo_logs' or variable_name = 'Innodb_truncated_status_writes' or variable_name = 'Innodb_num_open_files' or variable_name = 'Innodb_rows_updated' or variable_name = 'Innodb_rows_read' or variable_name = 'Innodb_rows_inserted' or variable_name = 'Innodb_rows_deleted' or variable_name = 'Innodb_row_lock_waits' or variable_name = 'Innodb_row_lock_time_max' or variable_name = 'Innodb_row_lock_time_avg' or variable_name = 'Innodb_row_lock_time' or variable_name = 'Innodb_row_lock_current_waits' or variable_name = 'Innodb_pages_written' or variable_name = 'Innodb_pages_read' or variable_name = 'Innodb_pages_created' or variable_name = 'Innodb_page_size' or variable_name = 'Innodb_os_log_written' or variable_name = 'Innodb_os_log_pending_writes' or variable_name = 'Innodb_os_log_pending_fsyncs' or variable_name = 'Innodb_os_log_fsyncs' or variable_name = 'Innodb_log_writes' or variable_name = 'Innodb_log_write_requests' or variable_name = 'Innodb_log_waits' or variable_name = 'Innodb_dblwr_writes' or variable_name = 'Innodb_dblwr_pages_written' or variable_name = 'Innodb_data_written' or variable_name = 'Innodb_data_writes' or variable_name = 'Innodb_data_reads' or variable_name = 'Innodb_data_read' or variable_name = 'Innodb_data_pending_writes' or variable_name = 'Innodb_data_pending_reads' or variable_name = 'Innodb_data_pending_fsyncs' or variable_name = 'Innodb_data_fsyncs' or variable_name = 'Innodb_buffer_pool_write_requests' or variable_name = 'Innodb_buffer_pool_wait_free' or variable_name = 'Innodb_buffer_pool_reads' or variable_name = 'Innodb_buffer_pool_read_requests' or variable_name = 'Innodb_buffer_pool_read_ahead_evicted' or variable_name = 'Innodb_buffer_pool_read_ahead' or variable_name = 'Innodb_buffer_pool_read_ahead_rnd' or variable_name = 'Innodb_buffer_pool_pages_total' or variable_name = 'Innodb_buffer_pool_pages_misc' or variable_name = 'Innodb_buffer_pool_pages_free' or variable_name = 'Innodb_buffer_pool_pages_flushed' or variable_name = 'Innodb_buffer_pool_bytes_dirty' or variable_name = 'Innodb_buffer_pool_pages_dirty' or variable_name = 'Innodb_buffer_pool_bytes_data' or variable_name = 'Innodb_buffer_pool_pages_data' or variable_name = 'Innodb_buffer_pool_resize_status' or variable_name = 'Innodb_buffer_pool_load_status' or variable_name = 'Innodb_buffer_pool_dump_status'", + "extend": null + }, + "mappingInfo": { + "parseDirection": "row", + "arrayColumns": null, + "keyColumns": ["Variable_name"], + "valueColumn": "Value" + } + }] +} diff --git a/src/test/resources/config/mysql/mysql.json b/src/test/resources/config/mysql/mysql.json new file mode 100644 index 0000000..85496b6 --- /dev/null +++ b/src/test/resources/config/mysql/mysql.json @@ -0,0 +1,44 @@ +{ + "id" : "SOEJWEOJWOEJOSDJFOASDJFOSDFO2903870928734", + "target" : { + "connection" : { + "ip" : "192.168.1.104", + "port" : "6379", + "ssl" : false, + "portType" : "tcp" + }, + "auth" : { + "url":"jdbc:mysql://192.168.1.215:3306", + "id":"root", + "pw":"qwe123" + } + }, + "schedule" : { + "interval" : "10" + }, + "crawler" : { + "name":"mysql", + "container":"java_proxy" + }, + "items" : [ + { + "keys" : [ + { + "metric":"net.connection_count", + "key":"Connections" + } + + ], + "queryInfo" : { + "query":"show status where `variable_name` = 'Connections'" + }, + "mappingInfo" : { + "parseDirection" : "row", + "valueColumn" : "Value", + "keyColumns" : [ + "Variable_name" + ] + } + } + ] +} diff --git a/src/test/resources/config/postgresql/postgresql.json b/src/test/resources/config/postgresql/postgresql.json new file mode 100644 index 0000000..cf9e4fd --- /dev/null +++ b/src/test/resources/config/postgresql/postgresql.json @@ -0,0 +1,36 @@ +{ + "id" : "SOEJWEOJWOEJOSDJFOASDJFOSDFO2903870928734", + "target" : { + "connection" : { + "ip" : "192.168.1.107", + "port" : "5432", + "ssl" : false, + "portType" : "tcp" + }, + "auth" : { + "url":"jdbc:postgresql://192.168.1.107:5432/postgres", + "id":"postgres", + "pw":"!@#$qwer1234" + } + }, + "schedule" : { + "interval" : "10" + }, + "crawler" : { + "name":"pgsql", + "container":"java_proxy" + }, + "items" : [ + { + "keys" : [ + { + "metric":"net.connection_count", + "key" : "connection_count" + } + ], + "queryInfo":{ + "query" : "select count(pid) as connection_count from pg_catalog.pg_stat_activity where state <> 'idle'" + } + } + ] +} diff --git a/src/test/resources/config/redis/example.json b/src/test/resources/config/redis/example.json new file mode 100644 index 0000000..4371d00 --- /dev/null +++ b/src/test/resources/config/redis/example.json @@ -0,0 +1,67 @@ +{ + "id" : "SOEJWEOJWOEJOSDJFOASDJFOSDFO2903870928734", + "target" : { + "connection" : { + "ip" : "192.168.1.104", + "port" : "6379", + "ssl" : false, + "portType" : "tcp" + }, + "auth" : { + + } + }, + "schedule" : { + "interval" : "10" + }, + "crawler" : { + "name":"redis_protocol_crawler", + "container":"network_crawler" + }, + "items" : [ + { + "keys" : [ + { + "metric":"cpu.usage.system", + "key":"used_cpu_sys" + }, + { + "metric":"cpu.usage.user", + "key":"used_cpu_user" + }, + { + "metric":"cpu.usage.system_children", + "key":"used_cpu_sys_children" + }, + { + "metric":"cpu.usage.user_children", + "key":"used_cpu_user_children" + } + ], + "queryInfo" : { + "query" : "CPU" + }, + "mappingInfo" : {} + }, + { + "keys" : [ + { + "metric":"memory.usage.used", + "key":"used_memory" + }, + { + "metric":"memory.usage.rss", + "key":"used_memory_rss" + }, + { + "metric":"memory.usage.peak", + "key":"used_memory_peak" + } + ], + "queryInfo" : { + "query" : "Memory" + }, + "mappingInfo" : {} + } + ] +} diff --git a/src/test/resources/config/snmp/examplev2.json b/src/test/resources/config/snmp/examplev2.json new file mode 100644 index 0000000..d53f370 --- /dev/null +++ b/src/test/resources/config/snmp/examplev2.json @@ -0,0 +1,38 @@ +{ + "id" : "insanity", + "target" : { + "connection" : { + "ip" : "192.168.1.254", + "port" : "161", + "ssl" : false, + "portType" : "udp" + }, + "auth" : { + "version":"v2c", + "community" : "loafle" + } + }, + "schedule" : { + "interval" : "10" + }, + "crawler" : { + "name":"snmp_crawler", + "container":"java" + }, + "items" : [ + { + "keys" : [ + {"metric":"system.uptime", "key":"1.3.6.1.2.1.1.3.0"} + ], + "queryInfo" : { + "query": "mem", + "extend" : { + "method": "get" + } + }, + "mappingInfo" : { + "parseDirection" : "col" + } + } + ] +} diff --git a/src/test/resources/config/snmp/examplev3.json b/src/test/resources/config/snmp/examplev3.json new file mode 100644 index 0000000..ef2e2b2 --- /dev/null +++ b/src/test/resources/config/snmp/examplev3.json @@ -0,0 +1,42 @@ +{ + "id" : "insanity", + "target" : { + "connection" : { + "ip" : "192.168.1.215", + "port" : "161", + "ssl" : false, + "portType" : "udp" + }, + "auth" : { + "version" : "v3", + "user" : "loafle", + "authType" : "MD5", + "authPass" : "qwer5795", + "privType" : "DES", + "privPass" : "qweqwe123" + } + }, + "schedule" : { + "interval" : "10" + }, + "crawler" : { + "name":"snmp_crawler", + "container":"java" + }, + "items" : [ + { + "keys" : [ + {"metric":"system.uptime", "key":"1.3.6.1.2.1.1.3.0"} + ], + "queryInfo" : { + "query": "mem", + "extend" : { + "method": "get" + } + }, + "mappingInfo" : { + "parseDirection" : "col" + } + } + ] +} diff --git a/src/test/resources/config/sqlserver/sqlserver_connection_count.json b/src/test/resources/config/sqlserver/sqlserver_connection_count.json new file mode 100644 index 0000000..f3f0362 --- /dev/null +++ b/src/test/resources/config/sqlserver/sqlserver_connection_count.json @@ -0,0 +1,38 @@ +{ + "id" : "SOEJWEOJWOEJOSDJFOASDJFOSDFO2903870928734", + "target" : { + "connection" : { + "ip" : "192.168.1.103", + "port" : "1433", + "ssl" : false, + "portType" : "tcp" + }, + "auth" : { + "url":"jdbc:sqlserver://192.168.1.106:1433;", + "id":"sa", + "pw":"qwe123" + } + }, + "schedule" : { + "interval" : "10" + }, + "crawler" : { + "name":"mssql", + "container":"java_proxy" + }, + "items" : [ + { + "keys" : [ + { + "metric" :"net.connection_count", + "key" : "connection_count" + } + ], + "queryInfo" : { + "query": "select count(session_id) as connection_count from sys.dm_exec_connections where session_id = @@SPID" + }, + "mappingInfo" : {} + } + + ] +} diff --git a/src/test/resources/config/sqlserver/sqlserver_multiple_key_array.json b/src/test/resources/config/sqlserver/sqlserver_multiple_key_array.json new file mode 100644 index 0000000..4548709 --- /dev/null +++ b/src/test/resources/config/sqlserver/sqlserver_multiple_key_array.json @@ -0,0 +1,50 @@ +{ + "id" : "SOEJWEOJWOEJOSDJFOASDJFOSDFO2903870928734", + "target" : { + "connection" : { + "ip" : "192.168.1.103", + "port" : "1433", + "ssl" : false, + "portType" : "tcp" + }, + "auth" : { + "url":"jdbc:sqlserver://192.168.1.106:1433;", + "id":"sa", + "pw":"qwe123", + "query" : "select * from master.dbo.sysprocesses" + } + }, + "schedule" : { + "interval" : "10" + }, + "crawler" : { + "name":"mssql", + "container":"java_proxy" + }, + "items" : [ + { + "keys" : [ + { + "metric" : "object[$0].db[$1].datafile_size", + "key" : "Data File(s) Size (KB)" + }, + { + "metric" : "object[$0].db[$1].logfile_size", + "key" : "Log File(s) Size (KB)" + } + ], + "queryInfo" : { + "query": "select object_name,instance_name, counter_name, cntr_value from sys.dm_os_performance_counters where ( counter_name = 'Data File(s) Size (KB)' or counter_name = 'Log File(s) Size (KB)' ) AND object_name = 'SQLServer:Databases'", + "extend" : { + + } + }, + "mappingInfo" : { + "parseDirection" : "row", + "arrayColumns" : [ "object_name","instance_name"], + "keyColumns" : ["counter_name"], + "valueColumn" : "cntr_value" + } + } + ] +} diff --git a/src/test/resources/config/tomcat/example.json b/src/test/resources/config/tomcat/example.json new file mode 100644 index 0000000..f2a9393 --- /dev/null +++ b/src/test/resources/config/tomcat/example.json @@ -0,0 +1,46 @@ +{ + "id" : "SOEJWEOJWOEJOSDJFOASDJFOSDFO2903870928734", + "target" : { + "connection" : { + "ip" : "192.168.1.103", + "port" : "9840", + "ssl" : false, + "portType" : "tcp" + }, + "auth" : { + "id": "jmxuser", + "pw": "tomcat" + } + }, + "schedule" : { + "interval" : "10" + }, + "crawler" : { + "name":"jmx", + "container":"java_proxy" + }, + "items" : [ + { + "keys" : [ + {"metric" : "net.connector[$0].requestCount", "key" : "requestCount"}, + {"metric" : "net.connector[$0].loadOnStartup", "key" : "loadOnStartup"}, + {"metric" : "net.connector[$0].errorCount", "key" : "errorCount"}, + {"metric" : "net.connector[$0].objectName", "key" : "objectName"} + ], + "queryInfo" : { + "query": "*Catalina:j2eeType=Servlet,*", + "extend" : { + "aliases" : [ + { + "key": "WebModule", + "index":0 + } + ] + } + }, + "mappingInfo" : { + "arrayColumns" : [ "Servlet" ] + } + } + ] +} diff --git a/src/test/resources/config/tomcat/example1.json b/src/test/resources/config/tomcat/example1.json new file mode 100644 index 0000000..9d9a394 --- /dev/null +++ b/src/test/resources/config/tomcat/example1.json @@ -0,0 +1,130 @@ +{ + "id" : "SOEJWEOJWOEJOSDJFOASDJFOSDFO2903870928734", + "target" : { + "connection" : { + "ip" : "192.168.1.103", + "port" : "9840", + "ssl" : false, + "portType" : "tcp" + }, + "auth" : { + "id": "jmxuser", + "pw": "tomcat" + } + }, + "schedule" : { + "interval" : "10" + }, + "crawler" : { + "name":"jmx", + "container":"java_proxy" + }, + "items" : [ + { + "keys" : [ + {"metric" : "net.connector[$0].maxThreads", "key" : "maxThreads"}, + {"metric" : "net.connector[$0].currentThreadCount", "key" : "currentThreadCount"}, + {"metric" : "net.connector[$0].currentThreadsBusy", "key" : "currentThreadsBusy"} + ], + "queryInfo" : { + "query": "*Catalina:type=ThreadPool,*", + "extend" : { + "aliases" : [ + { + "key": "name", + "index":0 + } + ] + } + }, + "mappingInfo" : { + "arrayColumns" : [ "ThreadPool" ] + } + }, + { + "keys" : [ + {"metric" : "net.connector[$0].bytesSent", "key" : "bytesSent"}, + {"metric" : "net.connector[$0].bytesReceived", "key" : "bytesReceived"}, + {"metric" : "net.connector[$0].errorCount", "key" : "errorCount"}, + {"metric" : "net.connector[$0].requestCount", "key" : "requestCount"}, + {"metric" : "net.connector[$0].maxTime", "key" : "maxTime"}, + {"metric" : "net.connector[$0].processingTime", "key" : "processingTime"} + ], + "queryInfo" : { + "query": "*Catalina:type=GlobalRequestProcessor,*", + "extend" : { + "aliases" : [ + { + "key": "WebModule", + "index":0 + } + ] + } + }, + "mappingInfo" : { + "arrayColumns" : [ "GlobalRequestProcessor" ] + } + }, + { + "keys" : [ + {"metric" : "net.connector[$0].processingTime", "key" : "processingTime"}, + {"metric" : "net.connector[$0].errorCount", "key" : "errorCount"}, + {"metric" : "net.connector[$0].requestCount", "key" : "requestCount"} + ], + "queryInfo" : { + "query": "*Catalina:j2eeType=Servlet,*", + "extend" : { + "aliases" : [ + { + "key": "WebModule", + "index":0 + } + ] + } + }, + "mappingInfo" : { + "arrayColumns" : [ "Servlet" ] + } + }, + { + "keys" : [ + {"metric" : "net.connector[$0].accessCount", "key" : "accessCount"}, + {"metric" : "net.connector[$0].hitCount", "key" : "hitCount"} + ], + "queryInfo" : { + "query": "*Catalina:type=StringCache,*", + "extend" : { + "aliases" : [ + { + "key": "StringCache", + "index":0 + } + ] + } + }, + "mappingInfo" : { + "arrayColumns" : [ "StringCache" ] + } + }, + { + "keys" : [ + {"metric" : "net.connector[$0].jspCount", "key" : "jspCount"}, + {"metric" : "net.connector[$0].jspReloadCount", "key" : "jspReloadCount"} + ], + "queryInfo" : { + "query": "*Catalina:type=JspMonitor,*", + "extend" : { + "aliases" : [ + { + "key": "WebModule", + "index":0 + } + ] + } + }, + "mappingInfo" : { + "arrayColumns" : [ "JspMonitor" ] + } + } + ] +} diff --git a/src/test/resources/config/tomcat/example2.json b/src/test/resources/config/tomcat/example2.json new file mode 100644 index 0000000..bf439a6 --- /dev/null +++ b/src/test/resources/config/tomcat/example2.json @@ -0,0 +1,47 @@ +{ + "id" : "SOEJWEOJWOEJOSDJFOASDJFOSDFO2903870928734", + "target" : { + "connection" : { + "ip" : "192.168.1.103", + "port" : "9840", + "ssl" : false, + "portType" : "tcp" + }, + "auth" : { + + } + }, + "schedule" : { + "interval" : "10" + }, + "crawler" : { + "name":"jmx", + "container":"java_proxy" + }, + "items" : [ + { + "keys" : [ + {"metric" : "net.connector[$1].bytesSent", "key" : "bytesSent"}, + {"metric" : "net.connector[$1].bytesReceived", "key" : "bytesReceived"}, + {"metric" : "net.connector[$1].errorCount", "key" : "errorCount"}, + {"metric" : "net.connector[$1].requestCount", "key" : "requestCount"}, + {"metric" : "net.connector[$1].maxTime", "key" : "maxTime"}, + {"metric" : "net.connector[$1].processingTime", "key" : "processingTime"} + ], + "queryInfo" : { + "query": "*Catalina:j2eeType=GlobalRequestProcessor,*", + "extend" : { + "aliases" : [ + { + "key": "Catalina:type", + "index":1 + } + ] + } + }, + "mappingInfo" : { + "arrayColumns" : [ "GlobalRequestProcessor" ] + } + } + ] +} diff --git a/src/test/resources/config/tomcat/generate1.json b/src/test/resources/config/tomcat/generate1.json new file mode 100644 index 0000000..dc4e9d1 --- /dev/null +++ b/src/test/resources/config/tomcat/generate1.json @@ -0,0 +1,106 @@ +{ + "id":"5", + "target":{ + "auth":{ + "pw":"tomcat", + "id":"jmxxuser" + }, + "connection":{ + "ip":"192.168.1.204", + "port":"9840", + "portType":"TCP", + "ssl":false + } + }, + "schedule":{ + "interval":"5" + }, + "crawler":{ + "name":"JMX_CRAWLER", + "container":"java_proxy" + }, + "items":[ + { + "keys":[ + { + "metric":"global.request.processing_time[$0]", + "key":"processingTime" + }, + { + "metric":"global.request.max_time[$0]", + "key":"maxTime" + }, + { + "metric":"global.request.request_count[$0]", + "key":"requestCount" + }, + { + "metric":"global.request.error_count[$0]", + "key":"errorCount" + }, + { + "metric":"global.request.bytes_rcvd[$0]", + "key":"bytesReceived" + }, + { + "metric":"global.request.bytes_sent[$0]", + "key":"bytesSent" + } + ], + "queryInfo":{ + "query":"*Catalina:type=GlobalRequestProcessor,*", + "extend":{ + "aliases":[ + { + "key":"Catalina:type", + "index":0 + } + ] + } + }, + "mappingInfo":{ + "parseDirection":null, + "arrayColumns":[ + "GlobalRequestProcessor" + ], + "keyColumns":null, + "valueColumn":null + } + }, + { + "keys":[ + { + "metric":"thread.busy[$0]", + "key":"currentThreadsBusy" + }, + { + "metric":"thread.count[$0]", + "key":"currentThreadCount" + }, + { + "metric":"thread.max[$0]", + "key":"maxThreads" + } + ], + "queryInfo":{ + "query":"*Catalina:type=ThreadPool,*", + "extend":{ + "aliases":[ + { + "key":"Catalina:type", + "index":0 + } + ] + } + }, + "mappingInfo":{ + "parseDirection":null, + "arrayColumns":[ + "ThreadPool" + ], + "keyColumns":null, + "valueColumn":null + } + } + ] +} diff --git a/src/test/resources/config/wmi/example.json b/src/test/resources/config/wmi/example.json new file mode 100644 index 0000000..60351e6 --- /dev/null +++ b/src/test/resources/config/wmi/example.json @@ -0,0 +1,63 @@ +{ + "id" : "SOEJWEOJWOEJOSDJFOASDJFOSDFO2903870928734", + "target" : { + "connection" : { + "ip" : "192.168.1.1", + "port" : "135", + "ssl" : false, + "portType" : "tcp" + }, + "auth" : { + "id":"administrator", + "pw":"!@#$qwer1234" + } + }, + "schedule" : { + "interval" : "10" + }, + "crawler" : { + "name":"wmi_crawler", + "container":"java_proxy" + }, + "items" : [ + { + "keys" : [ + {"metric" : "cpu[$0].usage.system", "key":"PercentProcessorTime"}, + {"metric" : "cpu[$0].usage.idle", "key":"PercentIdleTime"}, + {"metric" : "cpu[$0].usage.user", "key":"PercentUserTime"} + ], + "queryInfo" : { + "query": "select PercentProcessorTime, PercentIdleTime, PercentUserTime,Name from Win32_PerfFormattedData_PerfOS_Processor", + "extend" : { + "nameSpace":"root/cimv2", + "wmicPath": "/home/snoop/temp/wmic" + } + }, + "mappingInfo" : { + "parseDirection" : "col", + "arrayColumns" : [ "Name"] + } + } + , + { + "keys" : [ + {"metric" : "cpu.usage.system", "key":"PercentProcessorTime"}, + {"metric" : "cpu.usage.idle", "key":"PercentIdleTime"}, + {"metric" : "cpu.usage.user", "key":"PercentUserTime"} + ], + "queryInfo" : { + "query": "select PercentProcessorTime, PercentIdleTime, PercentUserTime,Name from Win32_PerfFormattedData_PerfOS_Processor where Name='_Total'", + "extend" : { + "nameSpace":"root/cimv2", + "wmicPath": "/home/snoop/temp/wmic" + } + }, + "mappingInfo" : { + "parseDirection" : "col", + "arrayColumns" : [ "Name"] + } + } + + ] + +} diff --git a/src/test/resources/config/wmi/meta/meta_cpu.json b/src/test/resources/config/wmi/meta/meta_cpu.json new file mode 100644 index 0000000..74288c6 --- /dev/null +++ b/src/test/resources/config/wmi/meta/meta_cpu.json @@ -0,0 +1,49 @@ +{ + "id": "4", + "schedule": { + "interval": "5" + }, + "items": [{ + "keys": [{ + "metric": "cpu.caption", + "key": "Caption" + }, + { + "metric": "cpu.Manufacturer", + "key": "Manufacturer" + }, + { + "metric": "cpu.MaxClockSpeed", + "key": "MaxClockSpeed" + }, + { + "metric": "cpu.CurrentClockSpeed", + "key": "CurrentClockSpeed" + }, + { + "metric": "cpu.AddressWidth", + "key": "AddressWidth" + }, + { + "metric": "cpu.DataWidth", + "key": "DataWidth" + }, + { + "metric": "cpu.Architecture", + "key": "Architecture" + }], + "queryInfo": { + "query": "SELECT Caption, Manufacturer, MaxClockSpeed, CurrentClockSpeed, AddressWidth, DataWidth, Architecture from Win32_Processor ", + "extend": { + "nameSpace": "root/cimv2", + "wmicPath": "/home/snoop/temp/wmic" + } + }, + "mappingInfo": { + "parseDirection": "col", + "arrayColumns": null, + "keyColumns": null, + "valueColumn": null + } + }] +} diff --git a/src/test/resources/config/wmi/meta/meta_filesystem.json b/src/test/resources/config/wmi/meta/meta_filesystem.json new file mode 100644 index 0000000..11dbf76 --- /dev/null +++ b/src/test/resources/config/wmi/meta/meta_filesystem.json @@ -0,0 +1,61 @@ +{ + "id": "4", + "target": { + "auth": { + "pw": "dbseogns18", + "id": "administrator" + }, + "connection": { + "ip": "192.168.1.106", + "port": "135", + "portType": "tcp", + "ssl": false + } + }, + "schedule": { + "interval": "5" + }, + "crawler": { + "name": "WMI_CRAWLER", + "container": "java_proxy" + }, + "items": [{ + "keys": [{ + "metric": "filesystem[$0].InterfaceType", + "key": "InterfaceType" + }, + { + "metric": "filesystem[$0].Status", + "key": "Status" + }, + { + "metric": "filesystem[$0].Manufacturer", + "key": "Manufacturer" + }, + { + "metric": "filesystem[$0].Model", + "key": "Model" + }, + { + "metric": "filesystem[$0].MediaType", + "key": "MediaType" + }, + { + "metric": "filesystem[$0].Size", + "key": "Size" + }], + "queryInfo": { + "query": "SELECT InterfaceType, Status, Manufacturer, Model, MediaType, Size from Win32_DiskDrive ", + "extend": { + "nameSpace": "root/cimv2", + "wmicPath": "/home/snoop/temp/wmic" + } + }, + "mappingInfo": { + "parseDirection": "col", + "arrayColumns": ["Model"], + "keyColumns": null, + "valueColumn": null + } + }] +} diff --git a/src/test/resources/config/wmi/meta/meta_memory.json b/src/test/resources/config/wmi/meta/meta_memory.json new file mode 100644 index 0000000..a3f111a --- /dev/null +++ b/src/test/resources/config/wmi/meta/meta_memory.json @@ -0,0 +1,53 @@ +{ + "id": "4", + "target": { + "auth": { + "pw": "dbseogns18", + "id": "administrator" + }, + "connection": { + "ip": "192.168.1.106", + "port": "135", + "portType": "tcp", + "ssl": false + } + }, + "schedule": { + "interval": "5" + }, + "crawler": { + "name": "WMI_CRAWLER", + "container": "java_proxy" + }, + "items": [{ + "keys": [{ + "metric": "memory.BankLabel", + "key": "BankLabel" + }, + { + "metric": "memory.Capacity", + "key": "Capacity" + }, + { + "metric": "memory.MemoryType", + "key": "MemoryType" + }, + { + "metric": "memory.DataWidth", + "key": "DataWidth" + }], + "queryInfo": { + "query": "SELECT BankLabel, Capacity, MemoryType, DataWidth from Win32_PhysicalMemory ", + "extend": { + "nameSpace": "root/cimv2", + "wmicPath": "/home/snoop/temp/wmic" + } + }, + "mappingInfo": { + "parseDirection": "col", + "arrayColumns": null, + "keyColumns": null, + "valueColumn": null + } + }] +} diff --git a/src/test/resources/config/wmi/meta/meta_network.json b/src/test/resources/config/wmi/meta/meta_network.json new file mode 100644 index 0000000..1c08a00 --- /dev/null +++ b/src/test/resources/config/wmi/meta/meta_network.json @@ -0,0 +1,53 @@ +{ + "id": "4", + "target": { + "auth": { + "pw": "dbseogns18", + "id": "administrator" + }, + "connection": { + "ip": "192.168.1.106", + "port": "135", + "portType": "tcp", + "ssl": false + } + }, + "schedule": { + "interval": "5" + }, + "crawler": { + "name": "WMI_CRAWLER", + "container": "java_proxy" + }, + "items": [{ + "keys": [{ + "metric": "network[$0].MACAddress", + "key": "MACAddress" + }, + { + "metric": "network[$0].AdapterType", + "key": "AdapterType" + }, + { + "metric": "network[$0].Manufacturer", + "key": "Manufacturer" + }, + { + "metric": "network[$0].Description", + "key": "Description" + }], + "queryInfo": { + "query": "SELECT MACAddress, AdapterType, Manufacturer, Description, NetConnectionID from Win32_NetworkAdapter WHERE PhysicalAdapter='TRUE'", + "extend": { + "nameSpace": "root/cimv2", + "wmicPath": "/home/snoop/temp/wmic" + } + }, + "mappingInfo": { + "parseDirection": "col", + "arrayColumns": ["NetConnectionID"], + "keyColumns": null, + "valueColumn": null + } + }] +} diff --git a/src/test/resources/config/wmi/test.json b/src/test/resources/config/wmi/test.json new file mode 100644 index 0000000..00c66ef --- /dev/null +++ b/src/test/resources/config/wmi/test.json @@ -0,0 +1,130 @@ +{ + "id": "4", + "target": { + "auth": { + "pw": "dbseogns18", + "id": "administrator" + }, + "connection": { + "ip": "192.168.1.106", + "port": "135", + "portType": "tcp", + "ssl": false + } + }, + "schedule": { + "interval": "5" + }, + "crawler": { + "name": "WMI_CRAWLER", + "container": "java_proxy" + }, + "items": [{ + "keys": [{ + "metric": "cpu.usage.total.privilege", + "key": "PercentPrivilegedTime" + }, + { + "metric": "cpu.usage.total.user", + "key": "PercentUserTime" + }, + { + "metric": "cpu.usage.total.processor", + "key": "PercentProcessorTime" + }, + { + "metric": "cpu.usage.total.idle", + "key": "PercentIdleTime" + }], + "queryInfo": { + "query": "SELECT PercentPrivilegedTime, PercentUserTime, PercentProcessorTime, PercentIdleTime FROM Win32_PerfFormattedData_PerfOS_Processor WHERE Name='_Total'", + "extend": { + "nameSpace": "root/cimv2", + "wmicPath": "/home/snoop/temp/wmic" + } + }, + "mappingInfo": { + "parseDirection": "col", + "arrayColumns": null, + "keyColumns": null, + "valueColumn": null + } + }, + { + "keys": [{ + "metric": "disk.usage.free[$0]", + "key": "FreeSpace" + }, + { + "metric": "disk.usage.total[$0]", + "key": "Size" + }], + "queryInfo": { + "query": "SELECT FreeSpace, Size, Caption FROM Win32_LogicalDisk", + "extend": { + "nameSpace": "root/cimv2", + "wmicPath": "/home/snoop/temp/wmic" + } + }, + "mappingInfo": { + "parseDirection": "col", + "arrayColumns": ["Caption"], + "keyColumns": null, + "valueColumn": null + } + }, + { + "keys": [{ + "metric": "mem.usage.free.paging", + "key": "FreeSpaceInPagingFiles" + }], + "queryInfo": { + "query": "SELECT FreeSpaceInPagingFiles FROM Win32_OperatingSystem ", + "extend": { + "nameSpace": "root/cimv2", + "wmicPath": "/home/snoop/temp/wmic" + } + }, + "mappingInfo": { + "parseDirection": "col", + "arrayColumns": null, + "keyColumns": null, + "valueColumn": null + } + }, + { + "keys": [{ + "metric": "mem.usage.free.physical", + "key": "FreePhysicalMemory" + }, + { + "metric": "mem.usage.free.virtual", + "key": "FreeVirtualMemory" + }, + { + "metric": "mem.usage.total.paging", + "key": "SizeStoredInPagingFiles" + }, + { + "metric": "mem.usage.total.physical", + "key": "TotalVisibleMemorySize" + }, + { + "metric": "mem.usage.total.virtual", + "key": "TotalVirtualMemorySize" + }], + "queryInfo": { + "query": "SELECT FreePhysicalMemory, FreeVirtualMemory, SizeStoredInPagingFiles, TotalVisibleMemorySize, TotalVirtualMemorySize FROM Win32_OperatingSystem", + "extend": { + "nameSpace": "root/cimv2", + "wmicPath": "/home/snoop/temp/wmic" + } + }, + "mappingInfo": { + "parseDirection": "col", + "arrayColumns": null, + "keyColumns": null, + "valueColumn": null + } + }] +}