From 33ea77a120ba3bd7af5b673bd35dcd1451d255e4 Mon Sep 17 00:00:00 2001 From: Trevor Date: Wed, 24 Jun 2020 10:47:57 -0700 Subject: [PATCH 001/212] cloud test setup documentation (#495) --- cmd/build | 5 +- docs/add_test.md | 2 +- docs/cloud_tests.md | 133 ++++++++++++++++++++++++++++++++++++ docs/integration_testing.md | 83 ---------------------- docs/orchestration.md | 2 +- subset/cloud/test_udmi | 5 ++ 6 files changed, 143 insertions(+), 87 deletions(-) create mode 100644 docs/cloud_tests.md delete mode 100644 docs/integration_testing.md diff --git a/cmd/build b/cmd/build index dc428ba90d..f4f09dcf32 100755 --- a/cmd/build +++ b/cmd/build @@ -26,11 +26,12 @@ DOCKER_IMAGE_VER=docker_images.ver cd $ROOT source etc/config_base.sh -host_tests=$host_tests bin/docker_build_files +echo host_tests=$host_tests +test_targets=$host_tests bin/docker_build_files function pull_images { TAG=$1 declare -A test_set - for target in $(host_tests=$host_tests bin/docker_build_files); do + for target in $test_targets; do target=$(echo $target | sed 's|^.*/Dockerfile.||' | echo daqf/$(> local/system.conf` -- Set tests configuration. This, of course, only works for local development when using the `local_tests.conf` config. To -formalize a test and include it in the overal system build it should be included in +formalize a test and include it in the overall system build it should be included in `config/modules/all.conf`. ## Component Build diff --git a/docs/cloud_tests.md b/docs/cloud_tests.md new file mode 100644 index 0000000000..6ed8a9efed --- /dev/null +++ b/docs/cloud_tests.md @@ -0,0 +1,133 @@ +# Cloud Connection Testing + +A number of additional setup steps are required for enabling testing against "smart devices" +that communicate with the cloud. The tests themselves are part of the `subset/cloud/test_udmi` +module included in the standard DAQ distro. The same basic device-to-cloud validation test +pipeline can be done manually and automatically (through DAQ); it's instructive to fully +understand the manual test pipeline before engaging with the automated setup. + +## Manual Test Pipeline + +The overall device-to-cloud pipeline looks something like the following: + +* Device sends data to the cloud. There's two kinds of devices: + * A faux _reference design_ device called [pubber](pubber.md), which is a completely contained + software device. + * An actual physical device. The setup and configuration of that device will be manufacturer + dependent and so is out of scope for this (DAQ) documentation. +* A configured GCP IoT Core project, registry, and device entry. The +[GCP docs for IoT Core](https://cloud.google.com/iot/docs/how-tos/devices) describe the basics. The +key part is the _authentication key_ (hahaha) that needs to be setup between the local device and +cloud device entry. +* The IoT Core registry is configured with a _PubSub topic_ (not to be confused with an _MQTT topic_), +that provides the bridge between incoming data and consumers of that data. See the GCP documentation +on PubSub for more details. +* (optional) The `gcloud` command line can be used to validate that data is being sent from the +device to the cloud. Something like +`gcloud pubsub subscriptions pull --auto-ack projects/{project}/subscriptions/{sub_id}`. +(Complete documentation for how to use `gcloud` commands is out of scope of this documentation.) +* The [validator tool](validator.md) is what programmatically validates a device data stream, and +is what is ultimately used by `test_udmi` to validate device-cloud communication. + +## Base Local Test Setup + +* The `udmi` module needs to be enabled in build. When running `cmd/build` there should be a line +like `subset/cloud/Dockerfile.test_udmi` in the startup logs. +This is enabled through the `host_tests` config parameter, +which can be set to `config/modules/all.conf` if necessary. On startup, there should be a log +message that includes `udmi`: +``` +Jun 22 08:32:52 runner INFO Configured with tests pass, fail, ping, bacnet, mudgee, nmap, discover, switch, macoui, bacext, tls, password, udmi, manual +``` +* A testing gcp service account `gcp_cred` needs to be setup as described in +[service account setup instructions](service.md). +* The system's default `module_config` needs to enable the `udmi` test, e.g. as per +`resources/setups/baseline/module_config.json`. This can be validated by (runtime) checking +`inst/run-port-01/nodes/udmi01/tmp/module_config.json` to see if it has something like the following: +``` + "udmi": { + "enabled": true + } +``` +* `site_path` config needs to point to a site definition directory, or defaults to `local/site`. +This contains all the site-specific information about devices needed for testing. +* `{site_path}/mac_addrs/{mac_addr}/module_config.json` needs to have a `device_id` defined, e.g. +as in `resources/test_site/mac_addrs/3c5ab41e8f0b/module_config.json`. +* The GCP IoT Core setup needs to have a proper registry and device configred. This can either +be done manually or using the [registrar tool](registrar.md) tool. + +## Integration Testing + +If developing cloud-tests, then the CI build system also needs to have a service account configured +pointing at a suitable GCP project. To run cloud-based tests, setup the Travis `GCP_BASE64_CRED` +env variable with a `base64` encoded service account key for your project. It's recommended to +use a dedicated key with a nice name like `daq-travis`, but not required. Encode the key value +as per below, and cut/paste the resulting string into a +[Travis environment variable](https://docs.travis-ci.com/user/environment-variables/#defining-variables-in-repository-settings) +for a `GCP_BASE64_CRED` variable. Note the `-w 0` option is required for proper parsing/formatting, +as there can't be any newlines in the copied string. + + +$ base64 -w 0 local/gcp_service_account.json +ewoICJ1eXBlIjogInNlcnZpY2VfYWNjb3VudCIsCiAgInByb2plY3RfaWQiOiAiYm9zLWRhcS10ZXN0aW5nIiwKICAicHJpd +… +iOiAiaHR0cHM6Ly93LWRhcS10ZXN0aW5nLmlhbS5nc2VydmljZWFjY291bnQuY29tIgp9Cg== + + +### Travis CI Testing + +* Run the [registrar tool](registrar.md) to properly configure the cloud project. +* `gcp_topic` config to `local/system.conf` as described in this doc. +* Configure test subsystem with proper cloud endpoint in `{test_site}/cloud_iot_config.json`. +* Configure the DUT with the proper cloud device credentials (device specific). For _faux_ devices, this means copying +the associated `rsa_private.pkcs8` file to something like `inst/faux/daq-faux-2/local/` (exact path depends on which faux). +* Test with `bin/registrar`, `pubber/bin/run`, and `bin/validate` manually, before integrated testing through DAQ. + +### Is my Travis set up correctly? + +If Travis is set up correctly, you should see messages at the beginning of the log file: +``` +Setting environment variables from repository settings +$ export DOCKER_USERNAME=[secure] +$ export DOCKER_PASSWORD=[secure] +$ export GCP_BASE64_CRED=[secure] +``` + +Further down there would be more details about the cred itself: +``` +Running test script testing/test_aux.sh +Writing test results to inst/test_aux.out and inst/test_aux.gcp +Decoding GCP_BASE64_CRED to inst/config/gcp_service_account.json +base64 wc: 1 1 3097 +GCP service account is "daq-travis@daq-testing.iam.gserviceaccount.com" +``` + +If the `3097` character count is wildly off, then likely something went wrong with the newlines. + +### Travis Build For "External" Pull Requests + +Travis will not use encrypted environment variables when testing against pull requests +from foreign github repositories, even if you've forked from another repository that you +have full control of via Github. Travis authorization != Github authorization, even if +you sign into Travis using Github! This is as it should be b/c security. see the following +for more info: + +- https://docs.travis-ci.com/user/environment-variables/#defining-variables-in-repository-settings +- https://docs.travis-ci.com/user/pull-requests/#pull-requests-and-security-restrictions + +If your test is failing from a PR, you'll see something like in a similar log location: + +``` +Encrypted environment variables have been removed for security reasons. +See https://docs.travis-ci.com/user/pull-requests/#pull-requests-and-security-restrictions +Setting environment variables from .travis.yml +$ export DOCKER_STARTUP_TIMEOUT_MS=60000 +$ export DAQ_TEST=aux +``` + +### Other Travis Caveats + +Take note the URL in your browser's address bar when running Travis. You might be on either +travis-ci.com or travis-ci.org. Any particular setup +may end up across both sites for undetermined reasons. Please consult with your browser's +exact URL for more clarity. diff --git a/docs/integration_testing.md b/docs/integration_testing.md deleted file mode 100644 index 1c6435a9b0..0000000000 --- a/docs/integration_testing.md +++ /dev/null @@ -1,83 +0,0 @@ -# Integration Testing - -DAQ currently uses Travis CI for integration testing: https://travis-ci.org/ - -## Configuration - -The `test_udmi` test module uses the Registrar and Validator to check that a device is -properly communicating through Cloud IoT, automated through DAQ. - -### GCP Credential - -To run cloud-based tests, setup the Travis `GCP_BASE64_CRED` env variable with a `base64` encoded -service account key for your project. It's recommended to use a dedicated key with a nice name -like `daq-travis`, but not required. Encode the key value as per below, and cut/paste the -resulting string into a -[Travis environment variable](https://docs.travis-ci.com/user/environment-variables/#defining-variables-in-repository-settings) -for a `GCP_BASE64_CRED` varaible. Note the `-w 0` option is required for proper parsing/formatting, -as there can't be any newlines in the copied string. - - -$ base64 -w 0 local/gcp_service_account.json -ewoICJ1eXBlIjogInNlcnZpY2VfYWNjb3VudCIsCiAgInByb2plY3RfaWQiOiAiYm9zLWRhcS10ZXN0aW5nIiwKICAicHJpd -… -iOiAiaHR0cHM6Ly93LWRhcS10ZXN0aW5nLmlhbS5nc2VydmljZWFjY291bnQuY29tIgp9Cg== - - -## Travis CI Testing - -* Run the [registrar tool](registrar.md) to properly configure the cloud project. -* `gcp_topic` config to `local/system.conf` as described in this doc. -* Configure test subsystem with proper cloud endpoint in `{test_site}/cloud_iot_config.json`. -* Configure the DUT with the proper cloud device credentials (device specific). For _faux_ devices, this means copying -the assocatied `rsa_private.pkcs8` file to someting like `inst/faux/daq-faux-2/local/` (exact path depends on which faux). -* Test with `bin/registrar`, `pubber/bin/run`, and `bin/validate` manually, before integrated testing through DAQ. - -### Is my Travis set up correctly? - -If Travis is set up correctly, you should see messages at the beginning of the log file: -``` -Setting environment variables from repository settings -$ export DOCKER_USERNAME=[secure] -$ export DOCKER_PASSWORD=[secure] -$ export GCP_BASE64_CRED=[secure] -``` - -Further down there would be more details about the cred itself: -``` -Running test script testing/test_aux.sh -Writing test results to inst/test_aux.out and inst/test_aux.gcp -Decoding GCP_BASE64_CRED to inst/config/gcp_service_account.json -base64 wc: 1 1 3097 -GCP service account is "daq-travis@daq-testing.iam.gserviceaccount.com" -``` - -If the `3097` character count is wildly off, then likely something went wrong with the newlines. - -### Travis Build For "External" Pull Requests - -Travis will not use encrypted environment variables when testing against pull requests -from foreign github repositories, even if you've forked from another repository that you -have full control of via Github. Travis authorization != Github authorization, even if -you sign into Travis using Github! This is as it should be b/c security. see the following -for more info: - -- https://docs.travis-ci.com/user/environment-variables/#defining-variables-in-repository-settings -- https://docs.travis-ci.com/user/pull-requests/#pull-requests-and-security-restrictions - -If your test is failing from a PR, you'll see something like in a similar log location: - -``` -Encrypted environment variables have been removed for security reasons. -See https://docs.travis-ci.com/user/pull-requests/#pull-requests-and-security-restrictions -Setting environment variables from .travis.yml -$ export DOCKER_STARTUP_TIMEOUT_MS=60000 -$ export DAQ_TEST=aux -``` - -### Other Travis Caveats - -Take note the URL in your browser's address bar when running Travis. You might be on either -travis-ci.com or travis-ci.org. Any particular setup -may end up across both sites for undertermined reasons. Please consult with your browser's -exact URL for more clarity. diff --git a/docs/orchestration.md b/docs/orchestration.md index 4804ec356f..703c5235a0 100644 --- a/docs/orchestration.md +++ b/docs/orchestration.md @@ -11,7 +11,7 @@ to change. ## Data Rouces -The overal orchestration capability relies on several simple data sources: +The overall orchestration capability relies on several simple data sources: 1. [Overall network topology](topologies.md), which indicates how the network hardware is configured. 2. [Device MUD files](../mud_files), which provide an [IETF Standard MUD descriptor](https://datatracker.ietf.org/doc/draft-ietf-opsawg-mud/) that describes diff --git a/subset/cloud/test_udmi b/subset/cloud/test_udmi index 4b0cfb2a32..fde175a26d 100755 --- a/subset/cloud/test_udmi +++ b/subset/cloud/test_udmi @@ -1,4 +1,5 @@ #!/bin/bash -e + source reporting.sh REPORT=/tmp/report.txt @@ -87,3 +88,7 @@ function message_report { for message_type in $message_types; do message_report $message_type done + +fgrep RESULT $REPORT + +echo Done with test_udmi From 048bf2059b27bb8fe6e4b8579d6ee44feee8bedf Mon Sep 17 00:00:00 2001 From: Haoli Du Date: Thu, 25 Jun 2020 00:09:30 +0000 Subject: [PATCH 002/212] 1.6.0 release --- docs/changelog.md | 6 ++++++ etc/docker_images.txt | 47 ++++++++++++++++++++++--------------------- etc/docker_images.ver | 2 +- 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index a67a7cfd32..98dbfa0745 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,4 +1,10 @@ # Changelog +* 1.6.0 + * cloud test setup documentation (#495) + * Baseline for NTP tests (#494) + * Baseline for DNS test (#492) + * Add manual test summary to test report (#481) + * UDMI logentry schema update (#391) * 1.5.1 * Fix for local-port-as-string issue (#477) * 1.5.0 diff --git a/etc/docker_images.txt b/etc/docker_images.txt index 193e733424..4fd1fc4f47 100644 --- a/etc/docker_images.txt +++ b/etc/docker_images.txt @@ -1,23 +1,24 @@ -daqf/aardvark 34718b2f3fd5 -daqf/default 3ac95db36ee4 -daqf/faucet 45c13344a8ed -daqf/faux1 ecff07f12534 -daqf/faux2 39914ae11741 -daqf/gauge 1431053cf25e -daqf/networking af56b0732100 -daqf/switch 67954aca8dce -daqf/test_bacext 363b6d476ac8 -daqf/test_bacnet 073a0eb5529f -daqf/test_brute 700d986d5e83 -daqf/test_discover ad34b17b41e6 -daqf/test_fail c9a7e6b43bd0 -daqf/test_hold cb120980c658 -daqf/test_macoui a828288c855b -daqf/test_mudgee d4ed15ef1dfc -daqf/test_nmap 78aa5def41e5 -daqf/test_pass 74167ef0df55 -daqf/test_password 471bd1290918 -daqf/test_ping 5618e0243643 -daqf/test_switch 47585fc0876e -daqf/test_tls 9c5f28b74fed -daqf/test_udmi fc13d4c80b0d +daqf/aardvark a16be44f9e25 +daqf/default 0c3cdaf1ea29 +daqf/faucet 6d604669ca66 +daqf/faux1 4db039df8e23 +daqf/faux2 25a7fafb7e45 +daqf/gauge 765578acddba +daqf/networking bfcc9246b0ab +daqf/switch ae42486d4cbd +daqf/test_bacext c7b8e3edf77a +daqf/test_bacnet a72e6e252ba9 +daqf/test_brute 2bf056e2a552 +daqf/test_discover aabd2d3d70f6 +daqf/test_fail 68c70b8e1067 +daqf/test_hold 1a488be2c5ad +daqf/test_macoui b86a88ebc6b5 +daqf/test_manual 6d8f9eb5b231 +daqf/test_mudgee c5feb2e63c82 +daqf/test_nmap 379f01b87c8b +daqf/test_pass 4f4098eeb114 +daqf/test_password 98c312e8415b +daqf/test_ping c86303a534d5 +daqf/test_switch fa40f5010865 +daqf/test_tls 748c578eb01d +daqf/test_udmi b0eb4d8d6cd8 diff --git a/etc/docker_images.ver b/etc/docker_images.ver index 26ca594609..dc1e644a10 100644 --- a/etc/docker_images.ver +++ b/etc/docker_images.ver @@ -1 +1 @@ -1.5.1 +1.6.0 From b2447092d207b4552c4f391bbb37eaa92284a66a Mon Sep 17 00:00:00 2001 From: henry54809 Date: Thu, 25 Jun 2020 08:32:12 -0700 Subject: [PATCH 003/212] fix image pull in cmd/build (#503) --- cmd/build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/build b/cmd/build index f4f09dcf32..834b1078a5 100755 --- a/cmd/build +++ b/cmd/build @@ -27,7 +27,7 @@ DOCKER_IMAGE_VER=docker_images.ver cd $ROOT source etc/config_base.sh echo host_tests=$host_tests -test_targets=$host_tests bin/docker_build_files +test_targets=$(host_tests=$host_tests bin/docker_build_files) function pull_images { TAG=$1 declare -A test_set From 588189c5a12c1d93fcc6b67a470071e4c4c087f4 Mon Sep 17 00:00:00 2001 From: Haoli Du Date: Thu, 25 Jun 2020 16:02:53 +0000 Subject: [PATCH 004/212] 1.6.1 release --- docs/changelog.md | 2 ++ etc/docker_images.txt | 48 +++++++++++++++++++++---------------------- etc/docker_images.ver | 2 +- 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index 98dbfa0745..c27652fa90 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,4 +1,6 @@ # Changelog +* 1.6.1 + * fix image pull in cmd/build (#503) * 1.6.0 * cloud test setup documentation (#495) * Baseline for NTP tests (#494) diff --git a/etc/docker_images.txt b/etc/docker_images.txt index 4fd1fc4f47..6260cbd020 100644 --- a/etc/docker_images.txt +++ b/etc/docker_images.txt @@ -1,24 +1,24 @@ -daqf/aardvark a16be44f9e25 -daqf/default 0c3cdaf1ea29 -daqf/faucet 6d604669ca66 -daqf/faux1 4db039df8e23 -daqf/faux2 25a7fafb7e45 -daqf/gauge 765578acddba -daqf/networking bfcc9246b0ab -daqf/switch ae42486d4cbd -daqf/test_bacext c7b8e3edf77a -daqf/test_bacnet a72e6e252ba9 -daqf/test_brute 2bf056e2a552 -daqf/test_discover aabd2d3d70f6 -daqf/test_fail 68c70b8e1067 -daqf/test_hold 1a488be2c5ad -daqf/test_macoui b86a88ebc6b5 -daqf/test_manual 6d8f9eb5b231 -daqf/test_mudgee c5feb2e63c82 -daqf/test_nmap 379f01b87c8b -daqf/test_pass 4f4098eeb114 -daqf/test_password 98c312e8415b -daqf/test_ping c86303a534d5 -daqf/test_switch fa40f5010865 -daqf/test_tls 748c578eb01d -daqf/test_udmi b0eb4d8d6cd8 +daqf/aardvark df091e4d5825 +daqf/default d2544deaa6e1 +daqf/faucet b5fef9b579ff +daqf/faux1 221259034e61 +daqf/faux2 e6beb911f3eb +daqf/gauge 9cd676c425de +daqf/networking 410cc21c55fa +daqf/switch 2229d5b7071c +daqf/test_bacext ddfb25affc3a +daqf/test_bacnet c8aa2fc90b87 +daqf/test_brute 09e833bf46f0 +daqf/test_discover 6126fe95e495 +daqf/test_fail 4c4df8d524fa +daqf/test_hold 4a8f5ab032be +daqf/test_macoui 5925b633d2f5 +daqf/test_manual 10ad9b86ec3e +daqf/test_mudgee 370369e124a8 +daqf/test_nmap 393fd39e9b0f +daqf/test_pass 0f8e341c292b +daqf/test_password 5be042269e32 +daqf/test_ping 486bb80e9dd6 +daqf/test_switch 082159ca2f27 +daqf/test_tls d2320f042174 +daqf/test_udmi 07efea3d4641 diff --git a/etc/docker_images.ver b/etc/docker_images.ver index dc1e644a10..9c6d6293b1 100644 --- a/etc/docker_images.ver +++ b/etc/docker_images.ver @@ -1 +1 @@ -1.6.0 +1.6.1 From ab7eed7537e7737dc07aa2ddac65c7a7870d8aea Mon Sep 17 00:00:00 2001 From: henry54809 Date: Fri, 26 Jun 2020 07:04:54 -0700 Subject: [PATCH 005/212] USI (#496) --- usi/.gitignore | 3 + usi/Dockerfile.usi | 12 + usi/pom.xml | 146 ++++++++ .../main/java/daq/usi/ResponseHandler.java | 5 + .../main/java/daq/usi/SwitchController.java | 201 +++++++++++ .../daq/usi/SwitchTelnetClientSocket.java | 329 ++++++++++++++++++ usi/src/main/java/daq/usi/UsiImpl.java | 92 +++++ usi/src/main/java/daq/usi/UsiServer.java | 59 ++++ .../daq/usi/allied/AlliedTelesisX230.java | 292 ++++++++++++++++ .../main/java/daq/usi/cisco/Cisco9300.java | 289 +++++++++++++++ usi/src/main/proto/usi.proto | 79 +++++ .../java/daq/usi/SwitchControllerTest.java | 47 +++ usi/start | 2 + 13 files changed, 1556 insertions(+) create mode 100644 usi/.gitignore create mode 100644 usi/Dockerfile.usi create mode 100644 usi/pom.xml create mode 100644 usi/src/main/java/daq/usi/ResponseHandler.java create mode 100644 usi/src/main/java/daq/usi/SwitchController.java create mode 100644 usi/src/main/java/daq/usi/SwitchTelnetClientSocket.java create mode 100644 usi/src/main/java/daq/usi/UsiImpl.java create mode 100644 usi/src/main/java/daq/usi/UsiServer.java create mode 100644 usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java create mode 100644 usi/src/main/java/daq/usi/cisco/Cisco9300.java create mode 100644 usi/src/main/proto/usi.proto create mode 100644 usi/src/test/java/daq/usi/SwitchControllerTest.java create mode 100755 usi/start diff --git a/usi/.gitignore b/usi/.gitignore new file mode 100644 index 0000000000..4b12f8ab84 --- /dev/null +++ b/usi/.gitignore @@ -0,0 +1,3 @@ +tmp/* +target/* +.idea/* diff --git a/usi/Dockerfile.usi b/usi/Dockerfile.usi new file mode 100644 index 0000000000..ba63658021 --- /dev/null +++ b/usi/Dockerfile.usi @@ -0,0 +1,12 @@ +FROM daqf/aardvark:latest + +# Do this alone first so it can be re-used by other build files. +RUN $AG update && $AG install openjdk-9-jre + +RUN $AG update && $AG install openjdk-9-jdk git + +COPY usi/ usi/ + +RUN cd usi && mvn clean compile assembly:single + +CMD ["./usi/start"] diff --git a/usi/pom.xml b/usi/pom.xml new file mode 100644 index 0000000000..7d87e5c53d --- /dev/null +++ b/usi/pom.xml @@ -0,0 +1,146 @@ + + 4.0.0 + com.redstone + usi + 0.0.1 +jar + usi + + UTF-8 + 1.8 + 1.8 + + + + + + io.grpc + grpc-bom + 1.30.0 + pom + import + + + + + + + junit + junit + 4.13 + test + + + commons-net + commons-net + 3.6 + + + io.grpc + grpc-netty-shaded + 1.30.0 + + + io.grpc + grpc-protobuf + 1.30.0 + + + io.grpc + grpc-stub + 1.30.0 + + + org.apache.tomcat + annotations-api + 6.0.53 + provided + + + org.junit.jupiter + junit-jupiter + RELEASE + compile + + + + + + kr.motd.maven + os-maven-plugin + 1.6.2 + + + + + + org.xolstice.maven.plugins + protobuf-maven-plugin + 0.6.1 + + com.google.protobuf:protoc:3.12.0:exe:${os.detected.classifier} + grpc-java + io.grpc:protoc-gen-grpc-java:1.30.0:exe:${os.detected.classifier} + + ${basedir}/src/main/proto + + + + + + compile + compile-custom + + + + + + maven-assembly-plugin + + + + daq.usi.UsiServer + + + + jar-with-dependencies + + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.1.0 + + + maven-surefire-plugin + 2.22.2 + + + maven-jar-plugin + 3.2.0 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 9 + 9 + + + + + \ No newline at end of file diff --git a/usi/src/main/java/daq/usi/ResponseHandler.java b/usi/src/main/java/daq/usi/ResponseHandler.java new file mode 100644 index 0000000000..4fd96af577 --- /dev/null +++ b/usi/src/main/java/daq/usi/ResponseHandler.java @@ -0,0 +1,5 @@ +package daq.usi; + +public interface ResponseHandler { + void receiveData(T data) throws Exception; +} diff --git a/usi/src/main/java/daq/usi/SwitchController.java b/usi/src/main/java/daq/usi/SwitchController.java new file mode 100644 index 0000000000..f9325c9ec0 --- /dev/null +++ b/usi/src/main/java/daq/usi/SwitchController.java @@ -0,0 +1,201 @@ +package daq.usi; + +/* + * Licensed to Google under one or more contributor license agreements. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import grpc.Interface; +import grpc.Power; +import grpc.SwitchActionResponse; +import java.util.HashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + +public abstract class SwitchController implements Runnable { + /** + * Terminal Prompt ends with '#' when enabled, '>' when not enabled. + */ + public static final String CONSOLE_PROMPT_ENDING_ENABLED = "#"; + public static final String CONSOLE_PROMPT_ENDING_LOGIN = ">"; + + // Define Common Variables Required for All Switch Interrogators + protected SwitchTelnetClientSocket telnetClientSocket; + protected Thread telnetClientSocketThread; + protected String remoteIpAddress; + protected int telnetPort; + protected boolean debug; + protected String username; + protected String password; + protected boolean userAuthorised = false; + protected boolean userEnabled = false; + protected String hostname = null; + protected boolean commandPending = false; + + public SwitchController(String remoteIpAddress, int telnetPort, String username, + String password) { + this(remoteIpAddress, telnetPort, username, password, false); + } + + /** + * Abstract Switch controller. Override this class for switch specific implementation + * + * @param remoteIpAddress switch ip address + * @param telnetPort switch telnet port + * @param username switch username + * @param password switch password + * @param debug for verbose logging + */ + public SwitchController( + String remoteIpAddress, int telnetPort, String username, String password, boolean debug) { + this.remoteIpAddress = remoteIpAddress; + this.telnetPort = telnetPort; + this.username = username; + this.password = password; + this.debug = debug; + telnetClientSocket = + new SwitchTelnetClientSocket(remoteIpAddress, telnetPort, this, debug); + } + + protected boolean containsPrompt(String consoleData) { + // Prompts usually hostname# or hostname(config)# + Pattern r = Pattern.compile(hostname + "\\s*(\\(.+\\))?" + CONSOLE_PROMPT_ENDING_ENABLED, 'g'); + Matcher m = r.matcher(consoleData); + return m.find(); + } + + protected boolean promptReady(String consoleData) { + // Prompts usually hostname# or hostname(config)# + Pattern r = Pattern.compile(hostname + "\\s*(\\(.+\\))?" + CONSOLE_PROMPT_ENDING_ENABLED + "$"); + Matcher m = r.matcher(consoleData); + return m.find(); + } + + /** + * Receive the raw data packet from the telnet connection and process accordingly. + * + * @param consoleData Most recent data read from the telnet socket buffer + */ + public void receiveData(String consoleData) { + if (debug) { + System.out.println( + java.time.LocalTime.now() + " receivedData:\t" + consoleData); + } + if (consoleData != null) { + try { + consoleData = consoleData.trim(); + if (!userAuthorised) { + handleLoginMessage(consoleData); + } else if (!userEnabled) { + handleEnableMessage(consoleData); + } else { + parseData(consoleData); + } + } catch (Exception e) { + telnetClientSocket.disposeConnection(); + e.printStackTrace(); + } + } + } + + /** + * Map a simple table containing a header and 1 row of data to a hashmap + * This method will also attempt to correct for mis-aligned tabular data as well as empty + * columns values. + * + * @param rawPacket Raw table response from a switch command + * @param colNames Array containing the names of the columns in the response + * @param mapNames Array containing names key names to map values to + * @return A HashMap containing the values mapped to the key names provided in the mapNames array + */ + protected static HashMap mapSimpleTable( + String rawPacket, String[] colNames, String[] mapNames) { + HashMap colMap = new HashMap<>(); + String[] lines = rawPacket.split("\n"); + if (lines.length > 0) { + String header = lines[0].trim(); + String values = lines[1].trim(); + int lastSectionEnd = 0; + for (int i = 0; i < colNames.length; ++i) { + int secStart = lastSectionEnd; + int secEnd; + if ((i + 1) >= colNames.length) { + // Resolving last column + secEnd = values.length(); + } else { + // Tabular data is not always reported in perfectly alignment, we need to calculate the + // correct values based off of the sections in between white spaces + int firstWhiteSpace = + getFirstWhiteSpace(values.substring(lastSectionEnd)) + lastSectionEnd; + int lastWhiteSpace = + getIndexOfNonWhitespaceAfterWhitespace(values.substring(firstWhiteSpace)) + + firstWhiteSpace; + int nextHeaderStart = header.indexOf(colNames[i + 1]); + secEnd = Math.min(lastWhiteSpace, nextHeaderStart); + } + lastSectionEnd = secEnd; + String sectionRaw = values.substring(secStart, secEnd).trim(); + colMap.put(mapNames[i], sectionRaw); + } + } + return colMap; + } + + + private static int getFirstWhiteSpace(String string) { + char[] characters = string.toCharArray(); + for (int i = 0; i < string.length(); i++) { + if (Character.isWhitespace(characters[i])) { + return i; + } + } + return -1; + } + + private static int getIndexOfNonWhitespaceAfterWhitespace(String string) { + char[] characters = string.toCharArray(); + boolean lastWhitespace = false; + for (int i = 0; i < string.length(); i++) { + if (Character.isWhitespace(characters[i])) { + lastWhitespace = true; + } else if (lastWhitespace) { + return i; + } + } + return -1; + } + + protected abstract void parseData(String consoleData) throws Exception; + + protected abstract void handleLoginMessage(String consoleData) throws Exception; + + protected abstract void handleEnableMessage(String consoleData) throws Exception; + + public abstract void getPower(int devicePort, ResponseHandler handler) throws Exception; + + public abstract void getInterface(int devicePort, ResponseHandler handler) + throws Exception; + + public abstract void connect(int devicePort, ResponseHandler handler) + throws Exception; + + public abstract void disconnect(int devicePort, ResponseHandler handler) + throws Exception; + + @Override + public void run() { + telnetClientSocketThread = new Thread(telnetClientSocket); + telnetClientSocketThread.start(); + } +} diff --git a/usi/src/main/java/daq/usi/SwitchTelnetClientSocket.java b/usi/src/main/java/daq/usi/SwitchTelnetClientSocket.java new file mode 100644 index 0000000000..7a73380612 --- /dev/null +++ b/usi/src/main/java/daq/usi/SwitchTelnetClientSocket.java @@ -0,0 +1,329 @@ +package daq.usi; + +/* + * Licensed to Google under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import org.apache.commons.net.telnet.EchoOptionHandler; +import org.apache.commons.net.telnet.InvalidTelnetOptionException; +import org.apache.commons.net.telnet.SuppressGAOptionHandler; +import org.apache.commons.net.telnet.TelnetClient; +import org.apache.commons.net.telnet.TelnetNotificationHandler; +import org.apache.commons.net.telnet.TerminalTypeOptionHandler; + +public class SwitchTelnetClientSocket implements TelnetNotificationHandler, Runnable { + public static String MORE_INDICATOR = "--More--"; + + protected static final int SLEEP_MS = 100; + // Rx empty space timeout before sending \n + protected static final int MAX_EMPTY_WAIT_COUNT = 70; + + protected TelnetClient telnetClient; + protected SwitchController interrogator; + + protected String remoteIpAddress = ""; + protected int remotePort = 23; + + protected InputStream inputStream; + protected OutputStream outputStream; + + protected Queue rxQueue = new LinkedList<>(); + + protected Thread readerThread; + protected Thread gatherThread; + + protected boolean debug; + + /** + * Telnet Client. + * @param remoteIpAddress switch ip address + * @param remotePort telent port + * @param interrogator switch specific switch controller + * @param debug For more verbose output. + */ + public SwitchTelnetClientSocket( + String remoteIpAddress, int remotePort, SwitchController interrogator, boolean debug) { + this.remoteIpAddress = remoteIpAddress; + this.remotePort = remotePort; + this.interrogator = interrogator; + this.debug = debug; + telnetClient = new TelnetClient(); + addOptionHandlers(); + } + + protected void connectTelnetSocket() { + int attempts = 0; + + while (!telnetClient.isConnected() && attempts < 10) { + try { + telnetClient.connect(remoteIpAddress, remotePort); + } catch (IOException e) { + System.err.println("Exception while connecting:" + e.getMessage()); + } + + attempts++; + + try { + Thread.sleep(SLEEP_MS); + } catch (InterruptedException e) { + System.err.println("Exception while connecting:" + e.getMessage()); + } + } + } + + @Override + public void run() { + connectTelnetSocket(); + + Runnable readDataRunnable = + () -> { + readData(); + }; + readerThread = new Thread(readDataRunnable); + + readerThread.start(); + + Runnable gatherDataRunnable = + () -> { + gatherData(); + }; + gatherThread = new Thread(gatherDataRunnable); + + gatherThread.start(); + + outputStream = telnetClient.getOutputStream(); + } + + protected void gatherData() { + StringBuilder rxData = new StringBuilder(); + + int rxQueueCount = 0; + + while (telnetClient.isConnected()) { + try { + if (rxQueue.isEmpty()) { + Thread.sleep(SLEEP_MS); + rxQueueCount++; + if (!interrogator.commandPending && rxQueueCount > MAX_EMPTY_WAIT_COUNT) { + if (debug) { + System.out.println("rxQueue Empty. Sending new line."); + } + rxQueueCount = 0; + writeData("\n"); + } + continue; + } + rxQueueCount = 0; + while (rxQueue.peek().trim() == "") { + rxQueue.poll(); + } + String rxTemp = rxQueue.poll(); + if (rxTemp.indexOf(MORE_INDICATOR) > 0) { + writeData("\n"); + if (debug) { + System.out.println("more position:" + rxTemp.indexOf(MORE_INDICATOR)); + System.out.println("Data: " + rxTemp); + } + rxTemp = rxTemp.replace(MORE_INDICATOR, ""); + rxData.append(rxTemp); + } else if (interrogator.userAuthorised + && !interrogator.promptReady((rxData.toString() + rxTemp).trim())) { + rxData.append(rxTemp); + if (debug) { + System.out.println("Waiting for more data till prompt ready: "); + System.out.println(rxData.toString().trim()); + } + } else { + rxQueueCount = 0; + rxData.append(rxTemp); + String rxGathered = rxData.toString().trim(); + rxData = new StringBuilder(); + interrogator.receiveData(rxGathered); + } + } catch (InterruptedException e) { + System.err.println("InterruptedException gatherData:" + e.getMessage()); + } + } + } + + /** + * * Callback method called when TelnetClient receives an option negotiation command. + * + * @param negotiationCode - type of negotiation command received (RECEIVED_DO, RECEIVED_DONT, + * RECEIVED_WILL, RECEIVED_WONT, RECEIVED_COMMAND) + * @param optionCode - code of the option negotiated * + */ + public void receivedNegotiation(int negotiationCode, int optionCode) { + String command = null; + switch (negotiationCode) { + case TelnetNotificationHandler.RECEIVED_DO: + command = "DO"; + break; + case TelnetNotificationHandler.RECEIVED_DONT: + command = "DONT"; + break; + case TelnetNotificationHandler.RECEIVED_WILL: + command = "WILL"; + break; + case TelnetNotificationHandler.RECEIVED_WONT: + command = "WONT"; + break; + case TelnetNotificationHandler.RECEIVED_COMMAND: + command = "COMMAND"; + break; + default: + command = Integer.toString(negotiationCode); // Should not happen + break; + } + System.out.println("Received " + command + " for option code " + optionCode); + } + + private void addOptionHandlers() { + TerminalTypeOptionHandler terminalTypeOptionHandler = + new TerminalTypeOptionHandler("VT100", false, false, true, false); + + EchoOptionHandler echoOptionHandler = new EchoOptionHandler(false, false, false, false); + + SuppressGAOptionHandler suppressGaOptionHandler = + new SuppressGAOptionHandler(true, true, true, true); + + try { + telnetClient.addOptionHandler(terminalTypeOptionHandler); + telnetClient.addOptionHandler(echoOptionHandler); + telnetClient.addOptionHandler(suppressGaOptionHandler); + } catch (InvalidTelnetOptionException e) { + System.err.println( + "Error registering option handlers InvalidTelnetOptionException: " + e.getMessage()); + } catch (IOException e) { + System.err.println("Error registering option handlers IOException: " + e.getMessage()); + } + } + + private String normalizeLineEnding(byte[] bytes, char endChar) { + List bytesBuffer = new ArrayList(); + + int countBreak = 0; + int countEsc = 0; + + for (int i = 0; i < bytes.length; i++) { + if (bytes[i] != 0) { + switch (bytes[i]) { + case 8: + // backspace \x08 + break; + case 10: + // newLineFeed \x0A + countBreak++; + bytesBuffer.add((byte) endChar); + break; + case 13: + // carriageReturn \x0D + countBreak++; + bytesBuffer.add((byte) endChar); + break; + case 27: + // escape \x1B + countEsc = 2; + break; + case 33: + // character:! + break; + default: + if (countEsc == 0) { + if (countBreak > 1) { + int size = bytesBuffer.size(); + for (int x = 0; x < countBreak - 1; x++) { + bytesBuffer.remove(size - 1 - x); + } + countBreak = 0; + } + bytesBuffer.add(bytes[i]); + } else { + countEsc--; + } + break; + } + } + } + + String bytesString = ""; + + for (Byte byteBuffer : bytesBuffer) { + bytesString = bytesString + (char) (byte) byteBuffer; + } + + return bytesString; + } + + protected void readData() { + int bytesRead = 0; + + inputStream = telnetClient.getInputStream(); + + while (telnetClient.isConnected()) { + try { + byte[] buffer = new byte[1024]; + + bytesRead = inputStream.read(buffer); + if (bytesRead > 0) { + String rawData = normalizeLineEnding(buffer, '\n'); + rxQueue.add(rawData); + // Useful for debugging + // rxQueue.add(new String(buffer, 0, bytesRead, StandardCharsets.UTF_8)); + } else { + try { + Thread.sleep(SLEEP_MS); + } catch (InterruptedException e) { + System.err.println("InterruptedException readData:" + e.getMessage()); + } + } + } catch (IOException e) { + System.err.println("Exception while reading socket:" + e.getMessage()); + } + } + } + + public void writeData(String data) { + writeOutputStream(data); + } + + private void writeOutputStream(String data) { + try { + outputStream.write(data.getBytes()); + outputStream.flush(); + } catch (IOException e) { + System.err.println("Exception while writing socket:" + e.getMessage()); + } + } + + /** + * Closes telnet connection. + */ + public void disposeConnection() { + try { + telnetClient.disconnect(); + } catch (IOException e) { + System.err.println("Exception while disposeConnection:" + e.getMessage()); + } + } +} diff --git a/usi/src/main/java/daq/usi/UsiImpl.java b/usi/src/main/java/daq/usi/UsiImpl.java new file mode 100644 index 0000000000..41dfea419f --- /dev/null +++ b/usi/src/main/java/daq/usi/UsiImpl.java @@ -0,0 +1,92 @@ +package daq.usi; + +import daq.usi.allied.AlliedTelesisX230; +import daq.usi.cisco.Cisco9300; +import grpc.Interface; +import grpc.Power; +import grpc.SwitchActionResponse; +import grpc.SwitchInfo; +import grpc.USIServiceGrpc; +import io.grpc.stub.StreamObserver; +import java.util.HashMap; +import java.util.Map; + +public class UsiImpl extends USIServiceGrpc.USIServiceImplBase { + private Map switchControllers; + + public UsiImpl() { + super(); + switchControllers = new HashMap<>(); + } + + private SwitchController getSwitchController(SwitchInfo switchInfo) { + String repr = String.join(",", switchInfo.getModel().toString(), switchInfo.getIpAddr(), + String.valueOf(switchInfo.getTelnetPort()), switchInfo.getUsername(), + switchInfo.getPassword()); + SwitchController sc = switchControllers.get(repr); + if (sc == null) { + switch (switchInfo.getModel()) { + case ALLIED_TELESIS_X230: { + sc = new AlliedTelesisX230(switchInfo.getIpAddr(), switchInfo.getTelnetPort(), + switchInfo.getUsername(), switchInfo.getPassword()); + break; + } + case CISCO_9300: { + sc = new Cisco9300(switchInfo.getIpAddr(), switchInfo.getTelnetPort(), + switchInfo.getUsername(), switchInfo.getPassword()); + break; + } + default: + break; + } + new Thread(sc).start(); + switchControllers.put(repr, sc); + } + return sc; + } + + @Override + public void getPower(SwitchInfo request, StreamObserver responseObserver) { + SwitchController sc = getSwitchController(request); + try { + sc.getPower(request.getDevicePort(), responseObserver::onNext); + } catch (Exception e) { + e.printStackTrace(); + responseObserver.onError(e); + } + } + + @Override + public void getInterface(SwitchInfo request, StreamObserver responseObserver) { + SwitchController sc = getSwitchController(request); + try { + sc.getInterface(request.getDevicePort(), responseObserver::onNext); + } catch (Exception e) { + e.printStackTrace(); + responseObserver.onError(e); + } + } + + @Override + public void connect(SwitchInfo request, StreamObserver responseObserver) { + SwitchController sc = getSwitchController(request); + try { + sc.connect(request.getDevicePort(), responseObserver::onNext); + } catch (Exception e) { + e.printStackTrace(); + responseObserver.onError(e); + } + } + + @Override + public void disconnect(SwitchInfo request, + StreamObserver responseObserver) { + SwitchController sc = getSwitchController(request); + try { + sc.disconnect(request.getDevicePort(), responseObserver::onNext); + } catch (Exception e) { + e.printStackTrace(); + responseObserver.onError(e); + } + } +} \ No newline at end of file diff --git a/usi/src/main/java/daq/usi/UsiServer.java b/usi/src/main/java/daq/usi/UsiServer.java new file mode 100644 index 0000000000..b5ce26374a --- /dev/null +++ b/usi/src/main/java/daq/usi/UsiServer.java @@ -0,0 +1,59 @@ +package daq.usi; + +import io.grpc.Server; +import io.grpc.ServerBuilder; +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +public class UsiServer { + private Server server; + + private void start() throws IOException { + /* The port on which the server should run */ + int port = 5000; + server = ServerBuilder.forPort(port) + .addService(new UsiImpl()) + .build() + .start(); + System.out.println("Server started, listening on " + port); + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + // Use stderr here since the logger may have been reset by its JVM shutdown hook. + System.err.println("*** shutting down gRPC server since JVM is shutting down"); + try { + UsiServer.this.stop(); + } catch (InterruptedException e) { + e.printStackTrace(System.err); + } + System.err.println("*** server shut down"); + } + }); + } + + private void stop() throws InterruptedException { + if (server != null) { + server.shutdown().awaitTermination(30, TimeUnit.SECONDS); + } + } + + /** + * Await termination on the main thread since the grpc library uses daemon threads. + */ + private void blockUntilShutdown() throws InterruptedException { + if (server != null) { + server.awaitTermination(); + } + } + + /** + * Main method. + * @param args not used. + * @throws Exception Maybe a refactor is needed to throw more specific exceptions. + */ + public static void main(String[] args) throws Exception { + final UsiServer server = new UsiServer(); + server.start(); + server.blockUntilShutdown(); + } +} diff --git a/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java b/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java new file mode 100644 index 0000000000..f45b518542 --- /dev/null +++ b/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java @@ -0,0 +1,292 @@ +package daq.usi.allied; + +/* + * Licensed to the Google under one or more contributor license agreements. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import daq.usi.ResponseHandler; +import daq.usi.SwitchController; +import grpc.Interface; +import grpc.LinkStatus; +import grpc.POEStatus; +import grpc.POESupport; +import grpc.Power; +import grpc.SwitchActionResponse; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.Queue; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + + +public class AlliedTelesisX230 extends SwitchController { + private static final String[] powerExpected = + {"dev_interface", "admin", "pri", "oper", "power", "device", "dev_class", "max"}; + private static final String[] showPowerExpected = + {"Interface", "Admin", "Pri", "Oper", "Power", "Device", "Class", "Max"}; + private static final Map poeStatusMap = Map.of("Powered", POEStatus.ON, + "Off", POEStatus.OFF, "Fault", POEStatus.FAULT, "Deny", POEStatus.DENY); + // TODO Not certain about AT power "Deny" status string. Can't find a device to produce that state + private static final Map poeSupportMap = Map.of("Enabled", + POESupport.ENABLED, "Disabled", POESupport.DISABLED); + private static final Map interfaceProcessMap = + Map.of(Pattern.compile("Link is (\\w+)"), "link", + Pattern.compile("current duplex (\\w+)"), "duplex", + Pattern.compile("current speed (\\w+)"), "speed"); + + private static final int WAIT_MS = 100; + private ResponseHandler responseHandler; + + /** + * ATX230 Switch Controller. + * + * @param remoteIpAddress switch ip address + * @param telnetPort switch telnet port + * @param user switch username + * @param password switch password + */ + public AlliedTelesisX230( + String remoteIpAddress, + int telnetPort, + String user, + String password) { + this(remoteIpAddress, telnetPort, user, password, false); + } + + /** + * ATX230 Switch Controller. + * + * @param remoteIpAddress switch ip address + * @param telnetPort switch telnet port + * @param user switch username + * @param password switch password + * @param debug for verbose output + */ + public AlliedTelesisX230( + String remoteIpAddress, + int telnetPort, + String user, + String password, boolean debug) { + super(remoteIpAddress, telnetPort, user, password, debug); + this.username = user == null ? "manager" : user; + this.password = password == null ? "friend" : password; + } + + @Override + protected void parseData(String consoleData) throws Exception { + if (commandPending) { + responseHandler.receiveData(consoleData); + } + } + + /** + * Generic ATX230 Switch command to retrieve the Status of an interface. + */ + private String showIfaceStatusCommand(int interfacePort) { + return "show interface port1.0." + interfacePort; + } + + /** + * Generic ATX230 Switch command to retrieve the Power Status of an interface. Replace asterisk + * with actual port number for complete message. + */ + private String showIfacePowerStatusCommand(int interfacePort) { + return "show power-inline interface port1.0." + interfacePort; + } + + /** + * Port toggle commands. + * + * @param interfacePort port number + * @param enabled for bringing up/down interfacePort + * @return commands + */ + private String[] portManagementCommand(int interfacePort, boolean enabled) { + return new String[] { + "configure terminal", + "interface port1.0." + interfacePort, + (enabled ? "no " : "") + "shutdown", + "end" + }; + } + + + @Override + public void getPower(int devicePort, ResponseHandler handler) throws Exception { + while (commandPending) { + Thread.sleep(WAIT_MS); + } + String command = showIfacePowerStatusCommand(devicePort); + synchronized (this) { + commandPending = true; + responseHandler = data -> { + Map powerMap = processPowerStatusInline(data); + handler.receiveData(buildPowerResponse(powerMap)); + synchronized (this) { + commandPending = false; + } + }; + telnetClientSocket.writeData(command + "\n"); + } + } + + @Override + public void getInterface(int devicePort, ResponseHandler handler) throws Exception { + while (commandPending) { + Thread.sleep(WAIT_MS); + } + String command = showIfaceStatusCommand(devicePort); + synchronized (this) { + commandPending = true; + responseHandler = data -> { + Map interfaceMap = processInterfaceStatus(data); + handler.receiveData(buildInterfaceResponse(interfaceMap)); + synchronized (this) { + commandPending = false; + } + }; + telnetClientSocket.writeData(command + "\n"); + } + } + + private void managePort(int devicePort, ResponseHandler handler, + boolean enabled) throws Exception { + while (commandPending) { + Thread.sleep(WAIT_MS); + } + Queue commands = + new LinkedList<>(Arrays.asList(portManagementCommand(devicePort, enabled))); + SwitchActionResponse.Builder response = SwitchActionResponse.newBuilder(); + synchronized (this) { + commandPending = true; + responseHandler = data -> { + if (!commands.isEmpty()) { + telnetClientSocket.writeData(commands.poll() + "\n"); + return; + } + synchronized (this) { + commandPending = false; + handler.receiveData(response.setSuccess(true).build()); + } + }; + telnetClientSocket.writeData(commands.poll() + "\n"); + } + } + + @Override + public void connect(int devicePort, ResponseHandler handler) + throws Exception { + managePort(devicePort, handler, true); + } + + @Override + public void disconnect(int devicePort, ResponseHandler handler) + throws Exception { + managePort(devicePort, handler, false); + } + + private Interface buildInterfaceResponse(Map interfaceMap) { + Interface.Builder response = Interface.newBuilder(); + String duplex = interfaceMap.getOrDefault("duplex", ""); + int speed = 0; + try { + speed = Integer.parseInt(interfaceMap.get("speed")); + } catch (NumberFormatException e) { + System.out.println("Could not parse int: " + interfaceMap.get("speed")); + } + String linkStatus = interfaceMap.getOrDefault("link", ""); + return response.setLinkStatus(linkStatus.equals("UP") ? LinkStatus.UP : LinkStatus.DOWN) + .setDuplex(duplex) + .setLinkSpeed(speed) + .build(); + } + + private Power buildPowerResponse(Map powerMap) { + Power.Builder response = Power.newBuilder(); + float maxPower = 0; + float currentPower = 0; + try { + maxPower = Float.parseFloat(powerMap.get("max")); + currentPower = Float.parseFloat(powerMap.get("power")); + } catch (NumberFormatException e) { + System.out.println( + "Could not parse float: " + powerMap.get("max") + " or " + powerMap.get("power")); + } + String poeSupport = powerMap.getOrDefault("admin", null); + String poeStatus = powerMap.getOrDefault("oper", null); + return response.setPoeStatus(poeStatusMap.getOrDefault(poeStatus, POEStatus.OFF)) + .setPoeSupport(poeSupportMap.getOrDefault(poeSupport, POESupport.DISABLED)) + .setMaxPowerConsumption(maxPower) + .setCurrentPowerConsumption(currentPower).build(); + } + + private Map processInterfaceStatus(String response) { + Map interfaceMap = new HashMap<>(); + Arrays.stream(response.split("\n")).filter(s -> !containsPrompt(s)).forEach(s -> { + for (Pattern pattern : interfaceProcessMap.keySet()) { + Matcher m = pattern.matcher(s); + if (m.find()) { + interfaceMap.put(interfaceProcessMap.get(pattern), m.group(1)); + } + } + }); + return interfaceMap; + } + + private Map processPowerStatusInline(String response) { + String filtered = Arrays.stream(response.split("\n")) + .filter(s -> s.trim().length() > 0 + && !s.contains("show power-inline") + && !containsPrompt(s) + && !s.contains("(mW)")) // AT shows mW in second line + .collect(Collectors.joining("\n")); + return mapSimpleTable(filtered, showPowerExpected, powerExpected); + } + + /** + * Handles the process when using the enter command. Enable is a required step before commands can + * be sent to the switch. + * + * @param consoleData Raw console data received the the telnet connection. + */ + public void handleEnableMessage(String consoleData) throws Exception { + if (containsPrompt(consoleData)) { + userEnabled = true; + } + } + + /** + * Handles the process when logging into the switch. + * + * @param consoleData Raw console data received the the telnet connection. + */ + public void handleLoginMessage(String consoleData) throws Exception { + if (consoleData.endsWith("login:")) { + telnetClientSocket.writeData(username + "\n"); + } else if (consoleData.contains("Password:")) { + telnetClientSocket.writeData(password + "\n"); + } else if (consoleData.contains(CONSOLE_PROMPT_ENDING_LOGIN)) { + userAuthorised = true; + hostname = consoleData.split(CONSOLE_PROMPT_ENDING_LOGIN)[0]; + telnetClientSocket.writeData("enable\n"); + } else if (consoleData.contains("Login incorrect")) { + telnetClientSocket.disposeConnection(); + throw new Exception("Failed to Login, Bad Password"); + } + } + +} diff --git a/usi/src/main/java/daq/usi/cisco/Cisco9300.java b/usi/src/main/java/daq/usi/cisco/Cisco9300.java new file mode 100644 index 0000000000..83f1d19550 --- /dev/null +++ b/usi/src/main/java/daq/usi/cisco/Cisco9300.java @@ -0,0 +1,289 @@ +package daq.usi.cisco; + +/* + * Licensed to Google under one or more contributor license agreements. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import daq.usi.ResponseHandler; +import daq.usi.SwitchController; +import grpc.Interface; +import grpc.LinkStatus; +import grpc.POEStatus; +import grpc.POESupport; +import grpc.Power; +import grpc.SwitchActionResponse; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.Queue; +import java.util.stream.Collectors; + + +public class Cisco9300 extends SwitchController { + + private static final String[] interfaceExpected = + {"interface", "name", "status", "vlan", "duplex", "speed", "type"}; + private static final String[] showInterfaceExpected = + {"Port", "Name", "Status", "Vlan", "Duplex", "Speed", "Type"}; + private static final Map powerInlineMap = Map.of("Interface", "dev_interface", + "Inline Power Mode", "admin", + "Operational status", "oper", + "Measured at the port", "power", + "Device Type", "device", + "IEEE Class", "dev_class", + "Power available to the device", "max"); + private static final Map poeStatusMap = Map.of("on", POEStatus.ON, + "off", POEStatus.OFF, "fault", POEStatus.FAULT, "power-deny", POEStatus.DENY); + private static final Map poeSupportMap = Map.of("auto", POESupport.ENABLED, + "off", POESupport.DISABLED); + private static final int WAIT_MS = 100; + private ResponseHandler responseHandler; + + /** + * Cisco 9300 Switch Controller. + * + * @param remoteIpAddress switch ip + * @param telnetPort switch telnet port + * @param user switch username + * @param password switch password + */ + public Cisco9300( + String remoteIpAddress, + int telnetPort, + String user, + String password) { + super(remoteIpAddress, telnetPort, user, password); + this.username = user == null ? "admin" : user; + this.password = password == null ? "password" : password; + } + + /** + * Generic Cisco Switch command to retrieve the Status of an interface. + */ + private String showIfaceStatusCommand(int interfacePort) { + return "show interface gigabitethernet1/0/" + interfacePort + " status"; + } + + /** + * Generic Cisco Switch command to retrieve the Power Status of an interface. Replace asterisk + * with actual port number for complete message + */ + private String showIfacePowerStatusCommand(int interfacePort) { + return "show power inline gigabitethernet1/0/" + interfacePort + " detail"; + } + + /** + * Get port toggle commands. + * + * @param interfacePort port number + * @param enabled for bringing up/down interfacePort + * @return commands + */ + private String[] portManagementCommand(int interfacePort, boolean enabled) { + return new String[] { + "configure terminal", + "interface FastEthernet0/" + interfacePort, + (enabled ? "no " : "") + "shutdown", + "end" + }; + } + + /** + * Handles the process when using the enter command. Enable is a required step before commands can + * be sent to the switch. + * + * @param consoleData Raw console data received the the telnet connection. + */ + @Override + public void handleEnableMessage(String consoleData) throws Exception { + if (consoleData.contains("Password:")) { + telnetClientSocket.writeData(password + "\n"); + } else if (containsPrompt(consoleData)) { + userEnabled = true; + } else if (consoleData.contains("% Bad passwords")) { + telnetClientSocket.disposeConnection(); + throw new Exception("Could not Enable the User, Bad Password"); + } + } + + /** + * Handles the process when logging into the switch. + * + * @param consoleData Raw console data received the the telnet connection. + */ + @Override + public void handleLoginMessage(String consoleData) throws Exception { + if (consoleData.contains("Username:")) { + telnetClientSocket.writeData(username + "\n"); + } else if (consoleData.contains("Password:")) { + telnetClientSocket.writeData(password + "\n"); + } else if (consoleData.endsWith(CONSOLE_PROMPT_ENDING_LOGIN)) { + userAuthorised = true; + hostname = consoleData.split(CONSOLE_PROMPT_ENDING_LOGIN)[0]; + telnetClientSocket.writeData("enable\n"); + } else if (consoleData.contains("% Login invalid")) { + telnetClientSocket.disposeConnection(); + throw new Exception("Failed to Login, Login Invalid"); + } else if (consoleData.contains("% Bad passwords")) { + telnetClientSocket.disposeConnection(); + throw new Exception("Failed to Login, Bad Password"); + } + } + + /** + * Handles current data in the buffer read from the telnet console InputStream and sends it to the + * appropriate process. + * + * @param consoleData Current unhandled data in the buffered reader + */ + @Override + public void parseData(String consoleData) throws Exception { + if (commandPending) { + responseHandler.receiveData(consoleData); + } + } + + @Override + public void getPower(int devicePort, ResponseHandler powerResponseHandler) + throws Exception { + while (commandPending) { + Thread.sleep(WAIT_MS); + } + String command = showIfacePowerStatusCommand(devicePort); + synchronized (this) { + commandPending = true; + responseHandler = data -> { + Map powerMap = processPowerStatusInline(data); + powerResponseHandler.receiveData(buildPowerResponse(powerMap)); + synchronized (this) { + commandPending = false; + } + }; + telnetClientSocket.writeData(command + "\n"); + } + } + + @Override + public void getInterface(int devicePort, ResponseHandler handler) throws Exception { + while (commandPending) { + Thread.sleep(WAIT_MS); + } + String command = showIfaceStatusCommand(devicePort); + synchronized (this) { + commandPending = true; + responseHandler = data -> { + Map interfaceMap = processInterfaceStatus(data); + handler.receiveData(buildInterfaceResponse(interfaceMap)); + synchronized (this) { + commandPending = false; + } + }; + telnetClientSocket.writeData(command + "\n"); + } + } + + private void managePort(int devicePort, ResponseHandler handler, + boolean enabled) throws Exception { + while (commandPending) { + Thread.sleep(WAIT_MS); + } + Queue commands = + new LinkedList<>(Arrays.asList(portManagementCommand(devicePort, enabled))); + SwitchActionResponse.Builder response = SwitchActionResponse.newBuilder(); + synchronized (this) { + commandPending = true; + responseHandler = data -> { + if (!commands.isEmpty()) { + telnetClientSocket.writeData(commands.poll() + "\n"); + return; + } + synchronized (this) { + commandPending = false; + handler.receiveData(response.setSuccess(true).build()); + } + }; + telnetClientSocket.writeData(commands.poll() + "\n"); + } + } + + @Override + public void connect(int devicePort, ResponseHandler handler) + throws Exception { + managePort(devicePort, handler, true); + } + + @Override + public void disconnect(int devicePort, ResponseHandler handler) + throws Exception { + managePort(devicePort, handler, false); + } + + private Interface buildInterfaceResponse(Map interfaceMap) { + Interface.Builder response = Interface.newBuilder(); + String duplex = interfaceMap.getOrDefault("duplex", ""); + if (duplex.startsWith("a-")) { // Interface in Auto Duplex + duplex = duplex.replaceFirst("a-", ""); + } + + String speed = interfaceMap.getOrDefault("speed", ""); + if (speed.startsWith("a-")) { // Interface in Auto Speed + speed = speed.replaceFirst("a-", ""); + } + + String linkStatus = interfaceMap.getOrDefault("status", ""); + return response.setLinkStatus(linkStatus.equals("connected") ? LinkStatus.UP : LinkStatus.DOWN) + .setDuplex(duplex) + .setLinkSpeed(Integer.parseInt(speed)) + .build(); + } + + private Power buildPowerResponse(Map powerMap) { + Power.Builder response = Power.newBuilder(); + float maxPower = Float.parseFloat(powerMap.get("max")); + float currentPower = Float.parseFloat(powerMap.get("power")); + + String poeSupport = powerMap.getOrDefault("admin", null); + String poeStatus = powerMap.getOrDefault("oper", null); + return response.setPoeStatus(poeStatusMap.getOrDefault(poeStatus, null)) + .setPoeSupport(poeSupportMap.getOrDefault(poeSupport, null)) + .setMaxPowerConsumption(maxPower) + .setCurrentPowerConsumption(currentPower).build(); + } + + private Map processInterfaceStatus(String response) { + String filtered = Arrays.stream(response.split("\n")) + .filter(s -> !containsPrompt(s)) + .collect(Collectors.joining("\n")); + return mapSimpleTable(filtered, showInterfaceExpected, interfaceExpected); + } + + private Map processPowerStatusInline(String response) { + Map powerMap = new HashMap<>(); + Arrays.stream(response.split("\n")) + .forEach( + line -> { + String[] lineParts = line.trim().split(":"); + if (lineParts.length > 1) { + String powerMapKey = powerInlineMap.getOrDefault(lineParts[0], null); + if (powerMapKey != null) { + powerMap.put(powerMapKey, lineParts[1].trim()); + } + } + }); + return powerMap; + } + + +} diff --git a/usi/src/main/proto/usi.proto b/usi/src/main/proto/usi.proto new file mode 100644 index 0000000000..a85db75fbb --- /dev/null +++ b/usi/src/main/proto/usi.proto @@ -0,0 +1,79 @@ +/* + * Specification for Universal Switch Interface. + */ +syntax = "proto3"; +package usi; + +option java_multiple_files = true; +option java_outer_classname = "USIProto"; +option java_package = "grpc"; + +service USIService { + rpc GetPower(SwitchInfo) returns (Power) {} + rpc GetInterface(SwitchInfo) returns (Interface) {} + rpc disconnect(SwitchInfo) returns (SwitchActionResponse) {} + rpc connect(SwitchInfo) returns (SwitchActionResponse) {} +} + +message SwitchActionResponse { + bool success = 1; +} + +message Power { + float current_power_consumption = 1; + float max_power_consumption = 2; + POESupport poe_support = 3; + POEStatus poe_status = 4; +} + +message Interface { + LinkStatus link_status = 1; + int32 link_speed = 2; + string duplex = 3; +} + +enum SwitchModel { + ALLIED_TELESIS_X230 = 0; + CISCO_9300 = 1; +} + +enum LinkStatus { + UP = 0; + DOWN = 1; +} + +enum POESupport { + ENABLED = 0; + DISABLED = 1; +} + +enum POEStatus { + ON = 0; + OFF = 1; + FAULT = 2; + DENY = 3; +} + +/* + * System configuraiton of the access switch. This is used by the system + * to setup and configure the switch itself. + */ +message SwitchInfo { + // IP address of external switch. + string ip_addr = 1; + + // Telnet Port + int32 telnet_port = 2; + + // Device Port + int32 device_port = 3; + + // Switch model + SwitchModel model = 4; + + // Switch connect username + string username = 5; + + // Switch connect password + string password = 6; +} diff --git a/usi/src/test/java/daq/usi/SwitchControllerTest.java b/usi/src/test/java/daq/usi/SwitchControllerTest.java new file mode 100644 index 0000000000..656f7e0c5e --- /dev/null +++ b/usi/src/test/java/daq/usi/SwitchControllerTest.java @@ -0,0 +1,47 @@ +package daq.usi; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.util.Map; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class SwitchControllerTest { + + @BeforeEach + void setUp() { + } + + @AfterEach + void tearDown() { + } + + @Test + void mapSimpleTableEmptyInput() { + String raw = ""; + String[] colNames = {"a", "b"}; + String[] mapNames = {"a", "b"}; + Map response = SwitchController.mapSimpleTable(raw, colNames, mapNames); + for (String key : response.keySet()) { + assertNull(response.get(key)); + } + } + + @Test + void mapSimpleTableSampleInputAT() { + String raw = "Interface Admin Pri Oper Power Device Class Max \n" + + "port1.0.1 Enabled Low Powered 3337 n/a 0 15400 [C]"; + String[] colNames = {"Interface", "Admin", "Pri", "Oper", "Power", "Device", "Class", "Max"}; + String[] mapNames = {"interface", "admin", "pri", "oper", "power", "device", "class", "max"}; + Map expected = Map.of("interface", "port1.0.1", "admin", "Enabled", "pri", + "Low", "oper", "Powered", "power", "3337", "device", "n/a", + "class", "0", "max", "15400 [C]"); + Map response = SwitchController.mapSimpleTable(raw, colNames, mapNames); + for (String key : response.keySet()) { + assertEquals(response.get(key), expected.get(key)); + } + } + +} \ No newline at end of file diff --git a/usi/start b/usi/start new file mode 100755 index 0000000000..4c8350ff73 --- /dev/null +++ b/usi/start @@ -0,0 +1,2 @@ +#!/bin/bash -e +java -jar usi/target/usi-0.0.1-jar-with-dependencies.jar From f211531d639fc6ed6fe57e5917f9b98b394c74b5 Mon Sep 17 00:00:00 2001 From: Noureddine Date: Mon, 29 Jun 2020 13:48:42 +0100 Subject: [PATCH 006/212] Update Minimum Send Test (#498) * complete changes to min_send test --- subset/network/network_tests.py | 102 +++++++++++++++++++++++++++++--- 1 file changed, 93 insertions(+), 9 deletions(-) diff --git a/subset/network/network_tests.py b/subset/network/network_tests.py index 6dbaca3f85..d785debc67 100644 --- a/subset/network/network_tests.py +++ b/subset/network/network_tests.py @@ -1,5 +1,8 @@ import subprocess, time, sys, json +import re +import datetime + arguments = sys.argv test_request = str(arguments[1]) @@ -24,13 +27,18 @@ description_communication_type = 'Device sends unicast or broadcast packets.' description_ntp_support = 'Device sends NTP request packets.' -tcpdump_display_all_packets = 'tcpdump -n src host ' + device_address + ' -r ' + cap_pcap_file +tcpdump_display_all_packets = 'tcpdump -tttt -n src host ' + device_address + ' -r ' + cap_pcap_file tcpdump_display_udp_bacnet_packets = 'tcpdump -n udp dst portrange 47808-47809 -r ' + cap_pcap_file -tcpdump_display_arp_packets = 'tcpdump arp -r ' + cap_pcap_file +tcpdump_display_arp_packets = 'tcpdump arp -n src host ' + device_address + ' -r ' + cap_pcap_file tcpdump_display_ntp_packets = 'tcpdump dst port 123 -r ' + cap_pcap_file tcpdump_display_eapol_packets = 'tcpdump port 1812 or port 1813 or port 3799 -r ' + cap_pcap_file tcpdump_display_broadcast_packets = 'tcpdump broadcast and src host ' + device_address + ' -r ' + cap_pcap_file +system_conf_file = "/config/inst/system.conf" +tcpdump_date_format = "%Y-%m-%d %H:%M:%S.%f" +min_send_seconds = 300 +min_send_duration = "5 minutes" + def write_report(string_to_append): print(string_to_append.strip()) with open(report_filename, 'a+') as file_open: @@ -49,7 +57,7 @@ def add_packet_count_to_report(packet_type, packet_count): write_report("{i} {t} Packets recieved={p}\n".format(i=ignore, t=packet_type, p=packet_count)) def add_packet_info_to_report(packets_received): - packet_list = packets_received.rstrip().split("\n") + packet_list = packets_received.strip().split("\n") outnum = min(len(packet_list), max_packets_in_report) for x in range(0, outnum): write_report("{i} {p}\n".format(i=ignore, p=packet_list[x])) @@ -99,19 +107,95 @@ def decode_json_config(config_file, map_name, action): elif action == 'remove': remove_from_port_list(port_map) + +def get_scan_length(config_file): + """ Gets length of the monitor.pcap scan + + Reads the system.conf file to and returns the length of the monitor_scan + + Args: + config_file: Location of system.conf file within test container + + Returns: + Length of monitor scan in seconds + + If not defined, or system.conf could not be found + returns false + """ + + scan_length = False + try: + with open(config_file) as file: + for line in file: + match = re.search(r'^monitor_scan_sec=(\d+)', line) + if match: + matched_length = int(match.group(1)) + # If scan length = 0 or not found, then monitor scan does not exist + scan_length = matched_length if matched_length > 0 else False + return scan_length + except Exception as e: + write_report("Error encountered reading system.conf {}".format(e)) + return False + def test_connection_min_send(): + """ Runs the connection.min_send test + + Tests if the device sends data packets of any type (inc data, NTP, etc) + within a period of 5 minutes by looking through the monitor.pcap file + + The length of test can be configured using the min_send_seconds variable + at the start of the file + """ + + # Get scan length + scan_length = get_scan_length(system_conf_file) + min_send_delta = datetime.timedelta(seconds=min_send_seconds) + min_send_pass = False + + # The test scans the monitor.pcap, so if it's not found skip + if not scan_length: + add_summary("DAQ monitor scan not running, test skipped") + return 'skip' + arp_shell_result = shell_command_with_result(tcpdump_display_arp_packets, 0, False) arp_packets_received = packets_received_count(arp_shell_result) if arp_packets_received > 0: add_summary("ARP packets received.") + shell_result = shell_command_with_result(tcpdump_display_all_packets, 0, False) - all_packets_received = packets_received_count(shell_result) - app_packets_received = all_packets_received - arp_packets_received - if app_packets_received > 0: - add_summary("Other packets received.") - print('min_send_packets', arp_packets_received, all_packets_received) + all_packets = shell_result.splitlines() + + # Loop through tcpdump result and measure the time between succesive packets + for i, packet in enumerate(all_packets): + # datetime is the first 26 characters of the line + packet_time = datetime.datetime.strptime(packet[:26], tcpdump_date_format) + + if i == 0: + previous_packet_time = packet_time + continue + + delta = packet_time - previous_packet_time + if delta < min_send_delta: + min_send_pass = True + break + + previous_packet_time = packet_time + add_packet_info_to_report(shell_result) - return 'pass' if app_packets_received > 0 else 'fail' + + if not min_send_pass: + if scan_length > min_send_seconds: + add_summary('Data packets were not sent at a frequency less than ' + + min_send_duration) + return 'fail' + else: + add_summary('Please set DAQ monitor scan to be greater than ' + + min_send_duration) + return 'skip' + + add_summary('Data packets were sent at a frequency of less than ' + + min_send_duration) + return 'pass' def test_connection_dhcp_long(): shell_result = shell_command_with_result(tcpdump_display_arp_packets, 0, False) From 4e339824d263b8d5a698b0aef2d2f59c6480f25c Mon Sep 17 00:00:00 2001 From: Trevor Pering Date: Tue, 30 Jun 2020 08:06:05 -0700 Subject: [PATCH 007/212] Minor UDMI updates for pubber keygen --- pubber/bin/keygen | 33 ++++++++----------- .../main/java/daq/pubber/MqttPublisher.java | 4 ++- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/pubber/bin/keygen b/pubber/bin/keygen index 1b3cf60d67..5ee3166d16 100755 --- a/pubber/bin/keygen +++ b/pubber/bin/keygen @@ -1,26 +1,21 @@ #!/bin/bash -e -ROOT=$(realpath $(dirname $0)/../..) -cd $ROOT - -TARGET_PREFIX=local/rsa_ - -PUBLIC_CERT=${TARGET_PREFIX}cert.pem -PRIVATE_CERT=${TARGET_PREFIX}private.pem -PRIVATE_KEY=${TARGET_PREFIX}private.pkcs8 - -if [ -f $PUBLIC_CERT ]; then - echo $PUBLIC_CERT already exists, exiting. +if [ "$#" != 2 ]; then + echo $0 [type] [out_dir] false fi -if [ -f $PRIVATE_CERT ]; then - echo $PRIVATE_CERT already exists, exiting. - false -fi -if [ -f $PRIVATE_KEY ]; then - echo $PRIVATE_KEY already exists, exiting. + +type=$1 +cd $2 + +if [ $type == RS256 ]; then + openssl genrsa -out rsa_private.pem 2048 + openssl rsa -in rsa_private.pem -pubout -out rsa_public.pem +elif [ $type == RS256_X509 ]; then + openssl req -x509 -nodes -newkey rsa:2048 -keyout rsa_private.pem -days 1000000 -out rsa_cert.pem -subj "/CN=unused" +else + echo Unknown key type $type. Try one of { RS256, RS256_X509 } false fi -openssl req -x509 -nodes -newkey rsa:2048 -keyout $PRIVATE_CERT -days 1000000 -out $PUBLIC_CERT -subj "/CN=unused" -openssl pkcs8 -topk8 -inform PEM -outform DER -in $PRIVATE_CERT -nocrypt > $PRIVATE_KEY +openssl pkcs8 -topk8 -inform PEM -outform DER -in rsa_private.pem -nocrypt > rsa_private.pkcs8 diff --git a/pubber/src/main/java/daq/pubber/MqttPublisher.java b/pubber/src/main/java/daq/pubber/MqttPublisher.java index 9358ee3546..ea32788d30 100644 --- a/pubber/src/main/java/daq/pubber/MqttPublisher.java +++ b/pubber/src/main/java/daq/pubber/MqttPublisher.java @@ -155,7 +155,9 @@ private MqttClient newMqttClient(String deviceId) { try { Preconditions.checkNotNull(registryId, "registryId is null"); Preconditions.checkNotNull(deviceId, "deviceId is null"); - MqttClient mqttClient = new MqttClient(getBrokerUrl(), getClientId(deviceId), + String clientId = getClientId(deviceId); + LOG.info("Creating new mqtt client for " + clientId); + MqttClient mqttClient = new MqttClient(getBrokerUrl(), clientId, new MemoryPersistence()); return mqttClient; } catch (Exception e) { From 970c9d6b0b13a87de699d93ef66585202edb8b3b Mon Sep 17 00:00:00 2001 From: pbatta Date: Tue, 30 Jun 2020 13:44:07 -0700 Subject: [PATCH 008/212] add check for git version tag in Travis (#519) --- bin/test_daq | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/bin/test_daq b/bin/test_daq index 279e3bc53b..779cef8998 100755 --- a/bin/test_daq +++ b/bin/test_daq @@ -31,6 +31,16 @@ echo -n "DAQ version " git describe --dirty --always echo +TAGGED_VERSION=`cat etc/docker_images.ver` +if ! git show $TAGGED_VERSION > /dev/null; then + echo + echo Tagged version $TAGGED_VERSION not found. + echo Maybe you need to fetch tags: git fetch --tags. + echo If this is on Travis, ensure tags were pushed to your repo. + echo + false +fi + if [ -d faucet ]; then echo -n "Last FAUCET commit " (cd $FAUCET; git log -n 1 --pretty=format:"%h - %an, %ar : %s" || true) From 83f83757617c5bd64c498ea8d4fa46ee4ed19f9e Mon Sep 17 00:00:00 2001 From: Trevor Date: Mon, 6 Jul 2020 18:08:20 -0700 Subject: [PATCH 009/212] Add DAQ version to origin summary (#522) --- firebase/functions/index.js | 13 ++++++---- firebase/public/index.html | 14 +++++------ firebase/public/main.js | 48 ++++++++++++++++++++++--------------- 3 files changed, 45 insertions(+), 30 deletions(-) diff --git a/firebase/functions/index.js b/firebase/functions/index.js index f17a3d2c6c..12b6a11875 100644 --- a/firebase/functions/index.js +++ b/firebase/functions/index.js @@ -123,7 +123,7 @@ function handleTestResult(origin, siteName, message) { const deviceDoc = originDoc.collection('device').doc(message.device_id); const updates = [ - originDoc.set({ 'updated': timestamp }), + originDoc.set({ 'updated': timestamp }, { merge: true }), siteDoc.set({ 'updated': timestamp }), portDoc.set({ 'updated': timestamp }), deviceDoc.set({ 'updated': timestamp }) @@ -193,17 +193,22 @@ function handleTestResult(origin, siteName, message) { function handleHeartbeat(origin, message) { const timestamp = new Date().toJSON(); const originDoc = db.collection('origin').doc(origin); - console.log('heartbeat', timestamp, origin) + console.log('heartbeat', timestamp, origin, message) const heartbeatDoc = originDoc.collection('runner').doc('heartbeat'); return Promise.all([ - originDoc.set({ 'updated': timestamp }), + originDoc.set({ + 'updated': timestamp, + 'version': message.version + }), heartbeatDoc.get().then((result) => { const current = result.data(); - if (!current || !current.message || current.message.timestamp < message.timestamp) + const defined = current && current.message && current.message.timestamp; + if (!defined || current.message.timestamp < message.timestamp) { return heartbeatDoc.set({ 'updated': timestamp, message }); + } }) ]); } diff --git a/firebase/public/index.html b/firebase/public/index.html index d9ce546c59..c4928cd090 100644 --- a/firebase/public/index.html +++ b/firebase/public/index.html @@ -31,14 +31,14 @@

Filters:

-
- - -
+
+ + +
@@ -52,10 +52,10 @@

Filters:

-

Sites

-

Origins

+

Sites

+

Users

@@ -84,4 +84,4 @@

Users

if (typeof daq_deploy_version !== 'undefined') { document.getElementById('deploy-version').innerHTML = daq_deploy_version; } - \ No newline at end of file + diff --git a/firebase/public/main.js b/firebase/public/main.js index 09f4237a5e..a6eeee087f 100644 --- a/firebase/public/main.js +++ b/firebase/public/main.js @@ -8,11 +8,6 @@ const display_columns = []; const display_rows = []; const row_timestamps = {}; -const data_state = {}; - -let last_result_time_sec = 0; -let heartbeatTimestamp = 0; - const origin_id = getQueryParam('origin'); const site_name = getQueryParam('site'); const port_id = getQueryParam('port'); @@ -21,8 +16,13 @@ const device_id = getQueryParam('device'); const run_id = getQueryParam('runid'); const from = getQueryParam('from'); const to = getQueryParam('to'); + +const data_state = {}; +let last_result_time_sec = 0; +let heartbeatTimestamp = 0; var db; -var activePorts = []; +var activePorts = new Set(); + document.addEventListener('DOMContentLoaded', () => { db = firebase.firestore(); const settings = { @@ -289,7 +289,7 @@ function watcherAdd(ref, collection, limit, handler) { }, (e) => console.error(e)); } -function listSites(db) { +function listSites() { const linkGroup = document.querySelector('#listings .sites'); db.collection('site').get().then((snapshot) => { snapshot.forEach((site_doc) => { @@ -303,21 +303,31 @@ function listSites(db) { }).catch((e) => statusUpdate('registry list error', e)); } -function listOrigins(db) { - const linkGroup = document.querySelector('#listings .origins'); +function addOrigin(originId) { + db.collection('origin').doc(originId).get().then((result) => { + const linkGroup = document.querySelector('#listings .origins'); + const originLink = document.createElement('a'); + originLink.setAttribute('href', '/?origin=' + originId); + originLink.innerHTML = originId; + linkGroup.appendChild(originLink); + const originInfo = document.createElement('span'); + const version = result.data() && result.data().version; + const updated = result.data() && result.data().updated; + originInfo.innerHTML = ` ${version}, ${updated}`; + linkGroup.appendChild(originInfo); + linkGroup.appendChild(document.createElement('p')); + }); +} + +function listOrigins() { db.collection('origin').get().then((snapshot) => { snapshot.forEach((originDoc) => { - const origin = originDoc.id; - const originLink = document.createElement('a'); - originLink.setAttribute('href', '/?origin=' + origin); - originLink.innerHTML = origin; - linkGroup.appendChild(originLink); - linkGroup.appendChild(document.createElement('p')); + addOrigin(originDoc.id); }); }).catch((e) => statusUpdate('origin list error', e)); } -function listUsers(db) { +function listUsers() { const link_group = document.querySelector('#listings .users'); db.collection('users').get().then((snapshot) => { snapshot.forEach((user_doc) => { @@ -354,9 +364,9 @@ function dashboardSetup() { triggerOrigin(db, origin_id); } else { document.getElementById('listings').classList.add('active'); - listSites(db); - listOrigins(db); - listUsers(db); + listOrigins(); + listSites(); + listUsers(); } return origin_id; From 06e4660f16a1611b445cc95fa10838f82e73cfb3 Mon Sep 17 00:00:00 2001 From: Puneet Date: Mon, 6 Jul 2020 23:51:17 -0700 Subject: [PATCH 010/212] 1.7.0 release --- docs/changelog.md | 10 +++++++-- etc/docker_images.txt | 48 +++++++++++++++++++++---------------------- etc/docker_images.ver | 2 +- 3 files changed, 33 insertions(+), 27 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index c27652fa90..e3a796f4a1 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,11 +1,17 @@ # Changelog +* 1.7.0 + * Add DAQ version to origin summary (#522) + * Add check for git version tag in Travis (#519) + * Minor UDMI updates for pubber keygen + * Update Minimum Send Test (#498) + * Universal Switch Interface (USI) (#496) * 1.6.1 - * fix image pull in cmd/build (#503) + * fix image pull in cmd/build (#503) * 1.6.0 * cloud test setup documentation (#495) * Baseline for NTP tests (#494) * Baseline for DNS test (#492) - * Add manual test summary to test report (#481) + * Add manual test summary to test report (#481) * UDMI logentry schema update (#391) * 1.5.1 * Fix for local-port-as-string issue (#477) diff --git a/etc/docker_images.txt b/etc/docker_images.txt index 6260cbd020..78ef0f7a7d 100644 --- a/etc/docker_images.txt +++ b/etc/docker_images.txt @@ -1,24 +1,24 @@ -daqf/aardvark df091e4d5825 -daqf/default d2544deaa6e1 -daqf/faucet b5fef9b579ff -daqf/faux1 221259034e61 -daqf/faux2 e6beb911f3eb -daqf/gauge 9cd676c425de -daqf/networking 410cc21c55fa -daqf/switch 2229d5b7071c -daqf/test_bacext ddfb25affc3a -daqf/test_bacnet c8aa2fc90b87 -daqf/test_brute 09e833bf46f0 -daqf/test_discover 6126fe95e495 -daqf/test_fail 4c4df8d524fa -daqf/test_hold 4a8f5ab032be -daqf/test_macoui 5925b633d2f5 -daqf/test_manual 10ad9b86ec3e -daqf/test_mudgee 370369e124a8 -daqf/test_nmap 393fd39e9b0f -daqf/test_pass 0f8e341c292b -daqf/test_password 5be042269e32 -daqf/test_ping 486bb80e9dd6 -daqf/test_switch 082159ca2f27 -daqf/test_tls d2320f042174 -daqf/test_udmi 07efea3d4641 +daqf/aardvark 13e07616906a +daqf/default 8547decf4b0c +daqf/faucet 0bd65761a824 +daqf/faux1 500fc556e362 +daqf/faux2 65be2e8aaff5 +daqf/gauge 399cf3f0cf26 +daqf/networking e7d0b7cea324 +daqf/switch 0a7b905f10fa +daqf/test_bacext 765b3fd4f471 +daqf/test_bacnet 1cdac0876850 +daqf/test_brute 9d046780449f +daqf/test_discover 6bb39aebc6d9 +daqf/test_fail 21b8d383d676 +daqf/test_hold 2c2dbda2fb23 +daqf/test_macoui 890bc044e327 +daqf/test_manual 156a1947c7f4 +daqf/test_mudgee 44a4ad7a9615 +daqf/test_nmap 6e97b5498219 +daqf/test_pass 95e9680cef60 +daqf/test_password 1bc14db7767e +daqf/test_ping 45e3f58e30a2 +daqf/test_switch 57cf3951b2e3 +daqf/test_tls f93b7fec95a4 +daqf/test_udmi 771e5969564d diff --git a/etc/docker_images.ver b/etc/docker_images.ver index 9c6d6293b1..bd8bf882d0 100644 --- a/etc/docker_images.ver +++ b/etc/docker_images.ver @@ -1 +1 @@ -1.6.1 +1.7.0 From 499bff98914abe5a5c407b7f21502e57efc75b33 Mon Sep 17 00:00:00 2001 From: henry54809 Date: Tue, 7 Jul 2020 13:09:06 -0700 Subject: [PATCH 011/212] Feature/usi OVS switch (#521) --- usi/pom.xml | 2 +- .../java/daq/usi/BaseSwitchController.java | 169 +++++++++++++++ .../main/java/daq/usi/SwitchController.java | 196 +----------------- .../daq/usi/SwitchTelnetClientSocket.java | 21 +- usi/src/main/java/daq/usi/UsiImpl.java | 63 +++--- .../daq/usi/allied/AlliedTelesisX230.java | 46 ++-- .../main/java/daq/usi/cisco/Cisco9300.java | 40 ++-- .../main/java/daq/usi/ovs/OpenVSwitch.java | 85 ++++++++ usi/src/main/proto/usi.proto | 14 +- ...est.java => BaseSwitchControllerTest.java} | 6 +- .../java/daq/usi/ovs/OpenVSwitchTest.java | 29 +++ usi/src/test/resources/ovs_output.txt | 24 +++ 12 files changed, 389 insertions(+), 306 deletions(-) create mode 100644 usi/src/main/java/daq/usi/BaseSwitchController.java create mode 100644 usi/src/main/java/daq/usi/ovs/OpenVSwitch.java rename usi/src/test/java/daq/usi/{SwitchControllerTest.java => BaseSwitchControllerTest.java} (85%) create mode 100644 usi/src/test/java/daq/usi/ovs/OpenVSwitchTest.java create mode 100644 usi/src/test/resources/ovs_output.txt diff --git a/usi/pom.xml b/usi/pom.xml index 7d87e5c53d..623acc4d95 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -59,7 +59,7 @@ org.junit.jupiter junit-jupiter - RELEASE + 5.6.2 compile diff --git a/usi/src/main/java/daq/usi/BaseSwitchController.java b/usi/src/main/java/daq/usi/BaseSwitchController.java new file mode 100644 index 0000000000..247930b298 --- /dev/null +++ b/usi/src/main/java/daq/usi/BaseSwitchController.java @@ -0,0 +1,169 @@ +package daq.usi; + +import java.util.HashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + +public abstract class BaseSwitchController implements SwitchController { + /** + * Terminal Prompt ends with '#' when enabled, '>' when not enabled. + */ + public static final String CONSOLE_PROMPT_ENDING_ENABLED = "#"; + public static final String CONSOLE_PROMPT_ENDING_LOGIN = ">"; + public static final int TELNET_PORT = 23; + + // Define Common Variables Required for All Switch Interrogators + protected SwitchTelnetClientSocket telnetClientSocket; + protected Thread telnetClientSocketThread; + protected String remoteIpAddress; + protected boolean debug; + protected String username; + protected String password; + protected boolean userAuthorised = false; + protected boolean userEnabled = false; + protected String hostname = null; + protected boolean commandPending = false; + + public BaseSwitchController(String remoteIpAddress, String username, + String password) { + this(remoteIpAddress, username, password, false); + } + + /** + * Abstract Switch controller. Override this class for switch specific implementation + * + * @param remoteIpAddress switch ip address + * @param username switch username + * @param password switch password + * @param debug for verbose logging + */ + public BaseSwitchController( + String remoteIpAddress, String username, String password, boolean debug) { + this.remoteIpAddress = remoteIpAddress; + this.username = username; + this.password = password; + this.debug = debug; + telnetClientSocket = + new SwitchTelnetClientSocket(remoteIpAddress, TELNET_PORT, this, debug); + } + + /** + * Map a simple table containing a header and 1 row of data to a hashmap + * This method will also attempt to correct for mis-aligned tabular data as well as empty + * columns values. + * + * @param rawPacket Raw table response from a switch command + * @param colNames Array containing the names of the columns in the response + * @param mapNames Array containing names key names to map values to + * @return A HashMap containing the values mapped to the key names provided in the mapNames array + */ + protected static HashMap mapSimpleTable( + String rawPacket, String[] colNames, String[] mapNames) { + HashMap colMap = new HashMap<>(); + String[] lines = rawPacket.split("\n"); + if (lines.length > 0) { + String header = lines[0].trim(); + String values = lines[1].trim(); + int lastSectionEnd = 0; + for (int i = 0; i < colNames.length; ++i) { + int secStart = lastSectionEnd; + int secEnd; + if ((i + 1) >= colNames.length) { + // Resolving last column + secEnd = values.length(); + } else { + // Tabular data is not always reported in perfectly alignment, we need to calculate the + // correct values based off of the sections in between white spaces + int firstWhiteSpace = + getFirstWhiteSpace(values.substring(lastSectionEnd)) + lastSectionEnd; + int lastWhiteSpace = + getIndexOfNonWhitespaceAfterWhitespace(values.substring(firstWhiteSpace)) + + firstWhiteSpace; + int nextHeaderStart = header.indexOf(colNames[i + 1]); + secEnd = Math.min(lastWhiteSpace, nextHeaderStart); + } + lastSectionEnd = secEnd; + String sectionRaw = values.substring(secStart, secEnd).trim(); + colMap.put(mapNames[i], sectionRaw); + } + } + return colMap; + } + + private static int getFirstWhiteSpace(String string) { + char[] characters = string.toCharArray(); + for (int i = 0; i < string.length(); i++) { + if (Character.isWhitespace(characters[i])) { + return i; + } + } + return -1; + } + + private static int getIndexOfNonWhitespaceAfterWhitespace(String string) { + char[] characters = string.toCharArray(); + boolean lastWhitespace = false; + for (int i = 0; i < string.length(); i++) { + if (Character.isWhitespace(characters[i])) { + lastWhitespace = true; + } else if (lastWhitespace) { + return i; + } + } + return -1; + } + + protected boolean containsPrompt(String consoleData) { + // Prompts usually hostname# or hostname(config)# + Pattern r = Pattern.compile(hostname + "\\s*(\\(.+\\))?" + CONSOLE_PROMPT_ENDING_ENABLED, 'g'); + Matcher m = r.matcher(consoleData); + return m.find(); + } + + protected boolean promptReady(String consoleData) { + // Prompts usually hostname# or hostname(config)# + Pattern r = Pattern.compile(hostname + "\\s*(\\(.+\\))?" + CONSOLE_PROMPT_ENDING_ENABLED + "$"); + Matcher m = r.matcher(consoleData); + return m.find(); + } + + /** + * Receive the raw data packet from the telnet connection and process accordingly. + * + * @param consoleData Most recent data read from the telnet socket buffer + */ + public void receiveData(String consoleData) { + if (debug) { + System.out.println( + java.time.LocalTime.now() + " receivedData:\t" + consoleData); + } + if (consoleData != null) { + try { + consoleData = consoleData.trim(); + if (!userAuthorised) { + handleLoginMessage(consoleData); + } else if (!userEnabled) { + handleEnableMessage(consoleData); + } else { + parseData(consoleData); + } + } catch (Exception e) { + telnetClientSocket.disposeConnection(); + e.printStackTrace(); + } + } + } + + protected abstract void parseData(String consoleData) throws Exception; + + protected abstract void handleLoginMessage(String consoleData) throws Exception; + + protected abstract void handleEnableMessage(String consoleData) throws Exception; + + @Override + public void start() { + telnetClientSocketThread = new Thread(telnetClientSocket); + telnetClientSocketThread.start(); + } +} diff --git a/usi/src/main/java/daq/usi/SwitchController.java b/usi/src/main/java/daq/usi/SwitchController.java index f9325c9ec0..82ae4ce663 100644 --- a/usi/src/main/java/daq/usi/SwitchController.java +++ b/usi/src/main/java/daq/usi/SwitchController.java @@ -1,201 +1,21 @@ package daq.usi; -/* - * Licensed to Google under one or more contributor license agreements. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import grpc.Interface; -import grpc.Power; +import grpc.InterfaceResponse; +import grpc.PowerResponse; import grpc.SwitchActionResponse; -import java.util.HashMap; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - - -public abstract class SwitchController implements Runnable { - /** - * Terminal Prompt ends with '#' when enabled, '>' when not enabled. - */ - public static final String CONSOLE_PROMPT_ENDING_ENABLED = "#"; - public static final String CONSOLE_PROMPT_ENDING_LOGIN = ">"; - - // Define Common Variables Required for All Switch Interrogators - protected SwitchTelnetClientSocket telnetClientSocket; - protected Thread telnetClientSocketThread; - protected String remoteIpAddress; - protected int telnetPort; - protected boolean debug; - protected String username; - protected String password; - protected boolean userAuthorised = false; - protected boolean userEnabled = false; - protected String hostname = null; - protected boolean commandPending = false; - - public SwitchController(String remoteIpAddress, int telnetPort, String username, - String password) { - this(remoteIpAddress, telnetPort, username, password, false); - } - - /** - * Abstract Switch controller. Override this class for switch specific implementation - * - * @param remoteIpAddress switch ip address - * @param telnetPort switch telnet port - * @param username switch username - * @param password switch password - * @param debug for verbose logging - */ - public SwitchController( - String remoteIpAddress, int telnetPort, String username, String password, boolean debug) { - this.remoteIpAddress = remoteIpAddress; - this.telnetPort = telnetPort; - this.username = username; - this.password = password; - this.debug = debug; - telnetClientSocket = - new SwitchTelnetClientSocket(remoteIpAddress, telnetPort, this, debug); - } - - protected boolean containsPrompt(String consoleData) { - // Prompts usually hostname# or hostname(config)# - Pattern r = Pattern.compile(hostname + "\\s*(\\(.+\\))?" + CONSOLE_PROMPT_ENDING_ENABLED, 'g'); - Matcher m = r.matcher(consoleData); - return m.find(); - } - - protected boolean promptReady(String consoleData) { - // Prompts usually hostname# or hostname(config)# - Pattern r = Pattern.compile(hostname + "\\s*(\\(.+\\))?" + CONSOLE_PROMPT_ENDING_ENABLED + "$"); - Matcher m = r.matcher(consoleData); - return m.find(); - } - - /** - * Receive the raw data packet from the telnet connection and process accordingly. - * - * @param consoleData Most recent data read from the telnet socket buffer - */ - public void receiveData(String consoleData) { - if (debug) { - System.out.println( - java.time.LocalTime.now() + " receivedData:\t" + consoleData); - } - if (consoleData != null) { - try { - consoleData = consoleData.trim(); - if (!userAuthorised) { - handleLoginMessage(consoleData); - } else if (!userEnabled) { - handleEnableMessage(consoleData); - } else { - parseData(consoleData); - } - } catch (Exception e) { - telnetClientSocket.disposeConnection(); - e.printStackTrace(); - } - } - } - - /** - * Map a simple table containing a header and 1 row of data to a hashmap - * This method will also attempt to correct for mis-aligned tabular data as well as empty - * columns values. - * - * @param rawPacket Raw table response from a switch command - * @param colNames Array containing the names of the columns in the response - * @param mapNames Array containing names key names to map values to - * @return A HashMap containing the values mapped to the key names provided in the mapNames array - */ - protected static HashMap mapSimpleTable( - String rawPacket, String[] colNames, String[] mapNames) { - HashMap colMap = new HashMap<>(); - String[] lines = rawPacket.split("\n"); - if (lines.length > 0) { - String header = lines[0].trim(); - String values = lines[1].trim(); - int lastSectionEnd = 0; - for (int i = 0; i < colNames.length; ++i) { - int secStart = lastSectionEnd; - int secEnd; - if ((i + 1) >= colNames.length) { - // Resolving last column - secEnd = values.length(); - } else { - // Tabular data is not always reported in perfectly alignment, we need to calculate the - // correct values based off of the sections in between white spaces - int firstWhiteSpace = - getFirstWhiteSpace(values.substring(lastSectionEnd)) + lastSectionEnd; - int lastWhiteSpace = - getIndexOfNonWhitespaceAfterWhitespace(values.substring(firstWhiteSpace)) - + firstWhiteSpace; - int nextHeaderStart = header.indexOf(colNames[i + 1]); - secEnd = Math.min(lastWhiteSpace, nextHeaderStart); - } - lastSectionEnd = secEnd; - String sectionRaw = values.substring(secStart, secEnd).trim(); - colMap.put(mapNames[i], sectionRaw); - } - } - return colMap; - } - - - private static int getFirstWhiteSpace(String string) { - char[] characters = string.toCharArray(); - for (int i = 0; i < string.length(); i++) { - if (Character.isWhitespace(characters[i])) { - return i; - } - } - return -1; - } - - private static int getIndexOfNonWhitespaceAfterWhitespace(String string) { - char[] characters = string.toCharArray(); - boolean lastWhitespace = false; - for (int i = 0; i < string.length(); i++) { - if (Character.isWhitespace(characters[i])) { - lastWhitespace = true; - } else if (lastWhitespace) { - return i; - } - } - return -1; - } - - protected abstract void parseData(String consoleData) throws Exception; - - protected abstract void handleLoginMessage(String consoleData) throws Exception; - protected abstract void handleEnableMessage(String consoleData) throws Exception; +public interface SwitchController { - public abstract void getPower(int devicePort, ResponseHandler handler) throws Exception; + void getPower(int devicePort, ResponseHandler handler) throws Exception; - public abstract void getInterface(int devicePort, ResponseHandler handler) + void getInterface(int devicePort, ResponseHandler handler) throws Exception; - public abstract void connect(int devicePort, ResponseHandler handler) + void connect(int devicePort, ResponseHandler handler) throws Exception; - public abstract void disconnect(int devicePort, ResponseHandler handler) + void disconnect(int devicePort, ResponseHandler handler) throws Exception; - @Override - public void run() { - telnetClientSocketThread = new Thread(telnetClientSocket); - telnetClientSocketThread.start(); - } + void start(); } diff --git a/usi/src/main/java/daq/usi/SwitchTelnetClientSocket.java b/usi/src/main/java/daq/usi/SwitchTelnetClientSocket.java index 7a73380612..a8349ff8a1 100644 --- a/usi/src/main/java/daq/usi/SwitchTelnetClientSocket.java +++ b/usi/src/main/java/daq/usi/SwitchTelnetClientSocket.java @@ -1,22 +1,5 @@ package daq.usi; -/* - * Licensed to Google under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -39,7 +22,7 @@ public class SwitchTelnetClientSocket implements TelnetNotificationHandler, Runn protected static final int MAX_EMPTY_WAIT_COUNT = 70; protected TelnetClient telnetClient; - protected SwitchController interrogator; + protected BaseSwitchController interrogator; protected String remoteIpAddress = ""; protected int remotePort = 23; @@ -62,7 +45,7 @@ public class SwitchTelnetClientSocket implements TelnetNotificationHandler, Runn * @param debug For more verbose output. */ public SwitchTelnetClientSocket( - String remoteIpAddress, int remotePort, SwitchController interrogator, boolean debug) { + String remoteIpAddress, int remotePort, BaseSwitchController interrogator, boolean debug) { this.remoteIpAddress = remoteIpAddress; this.remotePort = remotePort; this.interrogator = interrogator; diff --git a/usi/src/main/java/daq/usi/UsiImpl.java b/usi/src/main/java/daq/usi/UsiImpl.java index 41dfea419f..6cda498025 100644 --- a/usi/src/main/java/daq/usi/UsiImpl.java +++ b/usi/src/main/java/daq/usi/UsiImpl.java @@ -2,8 +2,9 @@ import daq.usi.allied.AlliedTelesisX230; import daq.usi.cisco.Cisco9300; -import grpc.Interface; -import grpc.Power; +import daq.usi.ovs.OpenVSwitch; +import grpc.InterfaceResponse; +import grpc.PowerResponse; import grpc.SwitchActionResponse; import grpc.SwitchInfo; import grpc.USIServiceGrpc; @@ -12,41 +13,48 @@ import java.util.Map; public class UsiImpl extends USIServiceGrpc.USIServiceImplBase { - private Map switchControllers; + private final Map switchControllers; public UsiImpl() { super(); switchControllers = new HashMap<>(); } - private SwitchController getSwitchController(SwitchInfo switchInfo) { - String repr = String.join(",", switchInfo.getModel().toString(), switchInfo.getIpAddr(), - String.valueOf(switchInfo.getTelnetPort()), switchInfo.getUsername(), - switchInfo.getPassword()); - SwitchController sc = switchControllers.get(repr); - if (sc == null) { - switch (switchInfo.getModel()) { - case ALLIED_TELESIS_X230: { - sc = new AlliedTelesisX230(switchInfo.getIpAddr(), switchInfo.getTelnetPort(), - switchInfo.getUsername(), switchInfo.getPassword()); - break; - } - case CISCO_9300: { - sc = new Cisco9300(switchInfo.getIpAddr(), switchInfo.getTelnetPort(), - switchInfo.getUsername(), switchInfo.getPassword()); - break; - } - default: - break; + private SwitchController createController(SwitchInfo switchInfo) { + SwitchController newController; + switch (switchInfo.getModel()) { + case ALLIED_TELESIS_X230: { + newController = + new AlliedTelesisX230(switchInfo.getIpAddr(), switchInfo.getUsername(), + switchInfo.getPassword()); + break; + } + case CISCO_9300: { + newController = new Cisco9300(switchInfo.getIpAddr(), switchInfo.getUsername(), + switchInfo.getPassword()); + break; + } + case OVS_SWITCH: { + newController = new OpenVSwitch(); + break; } - new Thread(sc).start(); - switchControllers.put(repr, sc); + default: + throw new IllegalArgumentException("Unrecognized switch model " + + switchInfo.getModel()); } - return sc; + newController.start(); + return newController; + } + + private SwitchController getSwitchController(SwitchInfo switchInfo) { + String repr = String.join(",", switchInfo.getModel().toString(), + switchInfo.getIpAddr(), switchInfo.getUsername(), + switchInfo.getPassword()); + return switchControllers.computeIfAbsent(repr, key -> createController(switchInfo)); } @Override - public void getPower(SwitchInfo request, StreamObserver responseObserver) { + public void getPower(SwitchInfo request, StreamObserver responseObserver) { SwitchController sc = getSwitchController(request); try { sc.getPower(request.getDevicePort(), responseObserver::onNext); @@ -57,7 +65,8 @@ public void getPower(SwitchInfo request, StreamObserver responseObserver) } @Override - public void getInterface(SwitchInfo request, StreamObserver responseObserver) { + public void getInterface(SwitchInfo request, + StreamObserver responseObserver) { SwitchController sc = getSwitchController(request); try { sc.getInterface(request.getDevicePort(), responseObserver::onNext); diff --git a/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java b/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java index f45b518542..50007a2086 100644 --- a/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java +++ b/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java @@ -1,27 +1,12 @@ package daq.usi.allied; -/* - * Licensed to the Google under one or more contributor license agreements. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - +import daq.usi.BaseSwitchController; import daq.usi.ResponseHandler; -import daq.usi.SwitchController; -import grpc.Interface; +import grpc.InterfaceResponse; import grpc.LinkStatus; import grpc.POEStatus; import grpc.POESupport; -import grpc.Power; +import grpc.PowerResponse; import grpc.SwitchActionResponse; import java.util.Arrays; import java.util.HashMap; @@ -33,7 +18,7 @@ import java.util.stream.Collectors; -public class AlliedTelesisX230 extends SwitchController { +public class AlliedTelesisX230 extends BaseSwitchController { private static final String[] powerExpected = {"dev_interface", "admin", "pri", "oper", "power", "device", "dev_class", "max"}; private static final String[] showPowerExpected = @@ -55,33 +40,29 @@ public class AlliedTelesisX230 extends SwitchController { * ATX230 Switch Controller. * * @param remoteIpAddress switch ip address - * @param telnetPort switch telnet port * @param user switch username * @param password switch password */ public AlliedTelesisX230( String remoteIpAddress, - int telnetPort, String user, String password) { - this(remoteIpAddress, telnetPort, user, password, false); + this(remoteIpAddress, user, password, false); } /** * ATX230 Switch Controller. * * @param remoteIpAddress switch ip address - * @param telnetPort switch telnet port * @param user switch username * @param password switch password - * @param debug for verbose output + * @param debug for verbose output */ public AlliedTelesisX230( String remoteIpAddress, - int telnetPort, String user, String password, boolean debug) { - super(remoteIpAddress, telnetPort, user, password, debug); + super(remoteIpAddress, user, password, debug); this.username = user == null ? "manager" : user; this.password = password == null ? "friend" : password; } @@ -126,7 +107,7 @@ private String[] portManagementCommand(int interfacePort, boolean enabled) { @Override - public void getPower(int devicePort, ResponseHandler handler) throws Exception { + public void getPower(int devicePort, ResponseHandler handler) throws Exception { while (commandPending) { Thread.sleep(WAIT_MS); } @@ -145,7 +126,8 @@ public void getPower(int devicePort, ResponseHandler handler) throws Exce } @Override - public void getInterface(int devicePort, ResponseHandler handler) throws Exception { + public void getInterface(int devicePort, ResponseHandler handler) + throws Exception { while (commandPending) { Thread.sleep(WAIT_MS); } @@ -199,8 +181,8 @@ public void disconnect(int devicePort, ResponseHandler han managePort(devicePort, handler, false); } - private Interface buildInterfaceResponse(Map interfaceMap) { - Interface.Builder response = Interface.newBuilder(); + private InterfaceResponse buildInterfaceResponse(Map interfaceMap) { + InterfaceResponse.Builder response = InterfaceResponse.newBuilder(); String duplex = interfaceMap.getOrDefault("duplex", ""); int speed = 0; try { @@ -215,8 +197,8 @@ private Interface buildInterfaceResponse(Map interfaceMap) { .build(); } - private Power buildPowerResponse(Map powerMap) { - Power.Builder response = Power.newBuilder(); + private PowerResponse buildPowerResponse(Map powerMap) { + PowerResponse.Builder response = PowerResponse.newBuilder(); float maxPower = 0; float currentPower = 0; try { diff --git a/usi/src/main/java/daq/usi/cisco/Cisco9300.java b/usi/src/main/java/daq/usi/cisco/Cisco9300.java index 83f1d19550..1dd3683e6c 100644 --- a/usi/src/main/java/daq/usi/cisco/Cisco9300.java +++ b/usi/src/main/java/daq/usi/cisco/Cisco9300.java @@ -1,27 +1,12 @@ package daq.usi.cisco; -/* - * Licensed to Google under one or more contributor license agreements. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - +import daq.usi.BaseSwitchController; import daq.usi.ResponseHandler; -import daq.usi.SwitchController; -import grpc.Interface; +import grpc.InterfaceResponse; import grpc.LinkStatus; import grpc.POEStatus; import grpc.POESupport; -import grpc.Power; +import grpc.PowerResponse; import grpc.SwitchActionResponse; import java.util.Arrays; import java.util.HashMap; @@ -31,7 +16,7 @@ import java.util.stream.Collectors; -public class Cisco9300 extends SwitchController { +public class Cisco9300 extends BaseSwitchController { private static final String[] interfaceExpected = {"interface", "name", "status", "vlan", "duplex", "speed", "type"}; @@ -55,16 +40,14 @@ public class Cisco9300 extends SwitchController { * Cisco 9300 Switch Controller. * * @param remoteIpAddress switch ip - * @param telnetPort switch telnet port * @param user switch username * @param password switch password */ public Cisco9300( String remoteIpAddress, - int telnetPort, String user, String password) { - super(remoteIpAddress, telnetPort, user, password); + super(remoteIpAddress, user, password); this.username = user == null ? "admin" : user; this.password = password == null ? "password" : password; } @@ -156,7 +139,7 @@ public void parseData(String consoleData) throws Exception { } @Override - public void getPower(int devicePort, ResponseHandler powerResponseHandler) + public void getPower(int devicePort, ResponseHandler powerResponseHandler) throws Exception { while (commandPending) { Thread.sleep(WAIT_MS); @@ -176,7 +159,8 @@ public void getPower(int devicePort, ResponseHandler powerResponseHandler } @Override - public void getInterface(int devicePort, ResponseHandler handler) throws Exception { + public void getInterface(int devicePort, ResponseHandler handler) + throws Exception { while (commandPending) { Thread.sleep(WAIT_MS); } @@ -230,8 +214,8 @@ public void disconnect(int devicePort, ResponseHandler han managePort(devicePort, handler, false); } - private Interface buildInterfaceResponse(Map interfaceMap) { - Interface.Builder response = Interface.newBuilder(); + private InterfaceResponse buildInterfaceResponse(Map interfaceMap) { + InterfaceResponse.Builder response = InterfaceResponse.newBuilder(); String duplex = interfaceMap.getOrDefault("duplex", ""); if (duplex.startsWith("a-")) { // Interface in Auto Duplex duplex = duplex.replaceFirst("a-", ""); @@ -249,8 +233,8 @@ private Interface buildInterfaceResponse(Map interfaceMap) { .build(); } - private Power buildPowerResponse(Map powerMap) { - Power.Builder response = Power.newBuilder(); + private PowerResponse buildPowerResponse(Map powerMap) { + PowerResponse.Builder response = PowerResponse.newBuilder(); float maxPower = Float.parseFloat(powerMap.get("max")); float currentPower = Float.parseFloat(powerMap.get("power")); diff --git a/usi/src/main/java/daq/usi/ovs/OpenVSwitch.java b/usi/src/main/java/daq/usi/ovs/OpenVSwitch.java new file mode 100644 index 0000000000..691a04eeb5 --- /dev/null +++ b/usi/src/main/java/daq/usi/ovs/OpenVSwitch.java @@ -0,0 +1,85 @@ +package daq.usi.ovs; + +import daq.usi.ResponseHandler; +import daq.usi.SwitchController; +import grpc.InterfaceResponse; +import grpc.LinkStatus; +import grpc.POEStatus; +import grpc.POESupport; +import grpc.PowerResponse; +import grpc.SwitchActionResponse; +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.net.URL; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class OpenVSwitch implements SwitchController { + + private static final String OVS_OUTPUT_FILE = "ovs_output.txt"; + + protected String getInterfaceByPort(int devicePort) throws FileNotFoundException { + URL file = OpenVSwitch.class.getClassLoader().getResource(OVS_OUTPUT_FILE); + if (file == null) { + throw new FileNotFoundException(OVS_OUTPUT_FILE + " is not found!"); + } + FileReader reader = new FileReader(file.getFile()); + BufferedReader bufferedReader = new BufferedReader(reader); + Pattern pattern = Pattern.compile("(^\\s*" + devicePort + ")(\\((.+)\\))(:.*)", 'g'); + String interfaceLine = bufferedReader.lines().filter(line -> { + Matcher m = pattern.matcher(line); + return m.find(); + }).findFirst().get(); + + Matcher m = pattern.matcher(interfaceLine); + m.matches(); + return m.group(3); + } + + @Override + public void getPower(int devicePort, ResponseHandler handler) throws Exception { + PowerResponse.Builder response = PowerResponse.newBuilder(); + PowerResponse power = response.setPoeStatus(POEStatus.OFF) + .setPoeSupport(POESupport.DISABLED) + .setMaxPowerConsumption(0) + .setCurrentPowerConsumption(0).build(); + handler.receiveData(power); + } + + @Override + public void getInterface(int devicePort, ResponseHandler handler) + throws Exception { + InterfaceResponse.Builder response = InterfaceResponse.newBuilder(); + InterfaceResponse iface = response.setLinkStatus(LinkStatus.UP) + .setDuplex("") + .setLinkSpeed(0) + .build(); + handler.receiveData(iface); + } + + private void managePort(int devicePort, ResponseHandler handler, + boolean enabled) throws Exception { + String iface = getInterfaceByPort(devicePort); + ProcessBuilder processBuilder = new ProcessBuilder(); + processBuilder.command("bash", "-c", "ifconfig " + iface + (enabled ? " up" : " down")); + Process process = processBuilder.start(); + int exitCode = process.waitFor(); + handler.receiveData(SwitchActionResponse.newBuilder().setSuccess(exitCode == 0).build()); + } + + @Override + public void connect(int devicePort, ResponseHandler handler) + throws Exception { + managePort(devicePort, handler, true); + } + + @Override + public void disconnect(int devicePort, ResponseHandler handler) + throws Exception { + managePort(devicePort, handler, false); + } + + public void start() { + } +} diff --git a/usi/src/main/proto/usi.proto b/usi/src/main/proto/usi.proto index a85db75fbb..6107b0afc7 100644 --- a/usi/src/main/proto/usi.proto +++ b/usi/src/main/proto/usi.proto @@ -9,8 +9,8 @@ option java_outer_classname = "USIProto"; option java_package = "grpc"; service USIService { - rpc GetPower(SwitchInfo) returns (Power) {} - rpc GetInterface(SwitchInfo) returns (Interface) {} + rpc GetPower(SwitchInfo) returns (PowerResponse) {} + rpc GetInterface(SwitchInfo) returns (InterfaceResponse) {} rpc disconnect(SwitchInfo) returns (SwitchActionResponse) {} rpc connect(SwitchInfo) returns (SwitchActionResponse) {} } @@ -19,14 +19,14 @@ message SwitchActionResponse { bool success = 1; } -message Power { +message PowerResponse { float current_power_consumption = 1; float max_power_consumption = 2; POESupport poe_support = 3; POEStatus poe_status = 4; } -message Interface { +message InterfaceResponse { LinkStatus link_status = 1; int32 link_speed = 2; string duplex = 3; @@ -35,6 +35,7 @@ message Interface { enum SwitchModel { ALLIED_TELESIS_X230 = 0; CISCO_9300 = 1; + OVS_SWITCH = 2; } enum LinkStatus { @@ -62,9 +63,6 @@ message SwitchInfo { // IP address of external switch. string ip_addr = 1; - // Telnet Port - int32 telnet_port = 2; - // Device Port int32 device_port = 3; @@ -76,4 +74,4 @@ message SwitchInfo { // Switch connect password string password = 6; -} +} \ No newline at end of file diff --git a/usi/src/test/java/daq/usi/SwitchControllerTest.java b/usi/src/test/java/daq/usi/BaseSwitchControllerTest.java similarity index 85% rename from usi/src/test/java/daq/usi/SwitchControllerTest.java rename to usi/src/test/java/daq/usi/BaseSwitchControllerTest.java index 656f7e0c5e..f2867c1b65 100644 --- a/usi/src/test/java/daq/usi/SwitchControllerTest.java +++ b/usi/src/test/java/daq/usi/BaseSwitchControllerTest.java @@ -8,7 +8,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -class SwitchControllerTest { +class BaseSwitchControllerTest { @BeforeEach void setUp() { @@ -23,7 +23,7 @@ void mapSimpleTableEmptyInput() { String raw = ""; String[] colNames = {"a", "b"}; String[] mapNames = {"a", "b"}; - Map response = SwitchController.mapSimpleTable(raw, colNames, mapNames); + Map response = BaseSwitchController.mapSimpleTable(raw, colNames, mapNames); for (String key : response.keySet()) { assertNull(response.get(key)); } @@ -38,7 +38,7 @@ void mapSimpleTableSampleInputAT() { Map expected = Map.of("interface", "port1.0.1", "admin", "Enabled", "pri", "Low", "oper", "Powered", "power", "3337", "device", "n/a", "class", "0", "max", "15400 [C]"); - Map response = SwitchController.mapSimpleTable(raw, colNames, mapNames); + Map response = BaseSwitchController.mapSimpleTable(raw, colNames, mapNames); for (String key : response.keySet()) { assertEquals(response.get(key), expected.get(key)); } diff --git a/usi/src/test/java/daq/usi/ovs/OpenVSwitchTest.java b/usi/src/test/java/daq/usi/ovs/OpenVSwitchTest.java new file mode 100644 index 0000000000..fb951cf29f --- /dev/null +++ b/usi/src/test/java/daq/usi/ovs/OpenVSwitchTest.java @@ -0,0 +1,29 @@ +package daq.usi.ovs; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.FileNotFoundException; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class OpenVSwitchTest { + OpenVSwitch ovs; + + @BeforeEach + void setUp() { + ovs = new OpenVSwitch(); + } + + @AfterEach + void tearDown() { + } + + @Test + void getInterfaceByPort() throws FileNotFoundException { + assertEquals(ovs.getInterfaceByPort(1), "faux"); + assertEquals(ovs.getInterfaceByPort(2), "faux-2"); + assertEquals(ovs.getInterfaceByPort(7), "sec-eth7"); + } + +} \ No newline at end of file diff --git a/usi/src/test/resources/ovs_output.txt b/usi/src/test/resources/ovs_output.txt new file mode 100644 index 0000000000..9621772035 --- /dev/null +++ b/usi/src/test/resources/ovs_output.txt @@ -0,0 +1,24 @@ +OFPT_FEATURES_REPLY (xid=0x2): dpid:0000000000000002 +n_tables:254, n_buffers:0 +capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP +actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst + 1(faux): addr:de:06:c6:06:73:bb + config: 0 + state: 0 + current: 10GB-FD COPPER + speed: 10000 Mbps now, 0 Mbps max + 2(faux-2): addr:de:06:c6:06:73:bc + config: 0 + state: 0 + current: 10GB-FD COPPER + speed: 10000 Mbps now, 0 Mbps max + 7(sec-eth7): addr:a2:f2:6f:01:84:d4 + config: 0 + state: 0 + current: 10GB-FD COPPER + speed: 10000 Mbps now, 0 Mbps max + LOCAL(sec): addr:72:87:94:b5:9c:48 + config: PORT_DOWN + state: LINK_DOWN + speed: 0 Mbps now, 0 Mbps max +OFPT_GET_CONFIG_REPLY (xid=0x4): frags=normal miss_send_len=0 From 79768e490d42939f1629cef72545f10516b3e83e Mon Sep 17 00:00:00 2001 From: frgitdaq <62390501+frgitdaq@users.noreply.github.com> Date: Wed, 8 Jul 2020 18:05:03 +0100 Subject: [PATCH 012/212] NTPv4 support (#487) * Added NTPv4 test 25 --- config/modules/all.conf | 3 +- docker/include/bin/start_faux | 12 ++- docs/device_report.md | 23 +++++- .../module_config.json | 3 + .../distech_ecy-s1000/module_config.json | 3 + resources/setups/baseline/module_config.json | 3 + .../qualification/device_module_config.json | 3 + .../device_type_module_config.json | 3 + .../qualification/system_module_config.json | 3 + .../remediation/device_module_config.json | 3 + .../remediation/system_module_config.json | 3 + resources/test_site/module_config.json | 3 + subset/ntp/Dockerfile.test_ntp | 10 +++ subset/ntp/README.md | 17 +++++ subset/ntp/build.conf | 2 + subset/ntp/ntp_tests.py | 74 +++++++++++++++++++ subset/ntp/test_ntp | 9 +++ testing/test_aux.out | 9 +++ testing/test_aux.sh | 5 +- 19 files changed, 184 insertions(+), 7 deletions(-) create mode 100644 subset/ntp/Dockerfile.test_ntp create mode 100644 subset/ntp/README.md create mode 100644 subset/ntp/build.conf create mode 100644 subset/ntp/ntp_tests.py create mode 100755 subset/ntp/test_ntp diff --git a/config/modules/all.conf b/config/modules/all.conf index 4d897ae7c5..59b4b74367 100644 --- a/config/modules/all.conf +++ b/config/modules/all.conf @@ -7,4 +7,5 @@ include subset/connection/build.conf include subset/bacnet/build.conf include subset/security/build.conf include subset/cloud/build.conf -include subset/manual/build.conf \ No newline at end of file +include subset/manual/build.conf +include subset/ntp/build.conf diff --git a/docker/include/bin/start_faux b/docker/include/bin/start_faux index 94c9711ab3..15c85bbf4e 100755 --- a/docker/include/bin/start_faux +++ b/docker/include/bin/start_faux @@ -136,9 +136,15 @@ elif [ -n "${options[bacnetfail]}" ]; then FauxDeviceEngine.EntryPoint $local_ip $broadcast_ip "Faux-Device-Fail.json" & fi -if [ -n "${options[ntp_client]}" ]; then - echo Starting ntp client. - java -jar NTPClient/build/libs/NTPClient-1.0-SNAPSHOT.jar "time.google.com" "123" "3" & +# Queries the NTP server learnt from DHCP. +if [ -n "${options[ntpv4]}" ]; then + dhcp_ntp=$(fgrep NTPSERVERS= /run/ntpdate.dhcp) + ntp_server=`echo $dhcp_ntp | cut -d "'" -f 2` + echo Transmitting NTP query to $ntp_server using NTPv4 + ntpdate -q -o 4 $ntp_server & +elif [ -n "${options[ntpv3]}" ]; then + echo Transmitting NTP query to time.google.com using NTPv3 + ntpdate -q -o 3 time.google.com & fi # ntp_pass queries the NTP server learnt from DHCP. ntp_fail sends to time.google.com diff --git a/docs/device_report.md b/docs/device_report.md index 2ab3ab3320..b22465300b 100644 --- a/docs/device_report.md +++ b/docs/device_report.md @@ -56,7 +56,7 @@ Overall device result FAIL |---|---|---|---|---| |Required|1|0|0|0| |Recommended|2|0|0|0| -|Other|1|2|22|2| +|Other|2|2|22|2| |Result|Test|Category|Expectation|Notes| |---|---|---|---|---| @@ -67,6 +67,7 @@ Overall device result FAIL |skip|cloud.udmi.state|Other|Other|No device id| |skip|cloud.udmi.system|Other|Other|No device id| |fail|connection.mac_oui|Other|Other|Manufacturer prefix not found!| +|pass|connection.network.ntp_support|Other|Other|Using NTPv4.| |skip|connection.port_duplex|Other|Other|No local IP has been set, check system config| |skip|connection.port_link|Other|Other|No local IP has been set, check system config| |skip|connection.port_speed|Other|Other|No local IP has been set, check system config| @@ -567,5 +568,25 @@ RESULT pass manual.test.travis Manual test - for testing |---|---| |enabled|True| +## Module ntp + + +#### Report + +``` +-------------------- +connection.network.ntp_support +-------------------- +Device supports NTP version 4. +-------------------- +RESULT pass connection.network.ntp_support Using NTPv4. +``` + +#### Module Config + +|Attribute|Value| +|---|---| +|enabled|True| + ## Report complete diff --git a/resources/device_types/deltacontrols_o3-din-cpu/module_config.json b/resources/device_types/deltacontrols_o3-din-cpu/module_config.json index 066bf35abb..a17a5a6997 100644 --- a/resources/device_types/deltacontrols_o3-din-cpu/module_config.json +++ b/resources/device_types/deltacontrols_o3-din-cpu/module_config.json @@ -24,6 +24,9 @@ "nmap": { "enabled": true }, + "ntp": { + "enabled": true + }, "switch": { "enabled": true, "poe": { diff --git a/resources/device_types/distech_ecy-s1000/module_config.json b/resources/device_types/distech_ecy-s1000/module_config.json index d790899c5c..b9a1847754 100644 --- a/resources/device_types/distech_ecy-s1000/module_config.json +++ b/resources/device_types/distech_ecy-s1000/module_config.json @@ -24,6 +24,9 @@ "nmap": { "enabled": true }, + "ntp": { + "enabled": true + }, "switch": { "enabled": true, "poe": { diff --git a/resources/setups/baseline/module_config.json b/resources/setups/baseline/module_config.json index 8ebd56cc57..ea0f335568 100644 --- a/resources/setups/baseline/module_config.json +++ b/resources/setups/baseline/module_config.json @@ -32,6 +32,9 @@ }, "network": { "enabled": true + }, + "ntp": { + "enabled": true } } } diff --git a/resources/setups/qualification/device_module_config.json b/resources/setups/qualification/device_module_config.json index 6019735d2b..9713c5723b 100644 --- a/resources/setups/qualification/device_module_config.json +++ b/resources/setups/qualification/device_module_config.json @@ -39,6 +39,9 @@ "nmap": { "enabled": true }, + "ntp": { + "enabled": true + }, "switch": { "enabled": true, "poe": { diff --git a/resources/setups/qualification/device_type_module_config.json b/resources/setups/qualification/device_type_module_config.json index f183d5527c..9d3181460b 100644 --- a/resources/setups/qualification/device_type_module_config.json +++ b/resources/setups/qualification/device_type_module_config.json @@ -33,6 +33,9 @@ "nmap": { "enabled": true }, + "ntp": { + "enabled": true + }, "switch": { "enabled": true, "poe": { diff --git a/resources/setups/qualification/system_module_config.json b/resources/setups/qualification/system_module_config.json index de3cc56461..8b1926a3f1 100644 --- a/resources/setups/qualification/system_module_config.json +++ b/resources/setups/qualification/system_module_config.json @@ -24,6 +24,9 @@ "nmap": { "enabled": true }, + "ntp": { + "enabled": true + }, "switch": { "enabled": true, "poe": { diff --git a/resources/setups/remediation/device_module_config.json b/resources/setups/remediation/device_module_config.json index 976761c762..65223dac27 100644 --- a/resources/setups/remediation/device_module_config.json +++ b/resources/setups/remediation/device_module_config.json @@ -35,6 +35,9 @@ "nmap": { "enabled": true }, + "ntp": { + "enabled": true + }, "switch": { "enabled": true, "poe": { diff --git a/resources/setups/remediation/system_module_config.json b/resources/setups/remediation/system_module_config.json index 17e7793758..754145aa9e 100644 --- a/resources/setups/remediation/system_module_config.json +++ b/resources/setups/remediation/system_module_config.json @@ -24,6 +24,9 @@ "nmap": { "enabled": true }, + "ntp": { + "enabled": true + }, "switch": { "enabled": true, "poe": { diff --git a/resources/test_site/module_config.json b/resources/test_site/module_config.json index 4d672b67aa..3ff4030a4c 100644 --- a/resources/test_site/module_config.json +++ b/resources/test_site/module_config.json @@ -17,6 +17,9 @@ }, "manual": { "enabled": true + }, + "ntp": { + "enabled": true } }, "process": { diff --git a/subset/ntp/Dockerfile.test_ntp b/subset/ntp/Dockerfile.test_ntp new file mode 100644 index 0000000000..2bfedf5a18 --- /dev/null +++ b/subset/ntp/Dockerfile.test_ntp @@ -0,0 +1,10 @@ +FROM daqf/aardvark:latest + +RUN $AG update && $AG install python python-setuptools python-pip netcat + +RUN pip install scapy + +COPY subset/ntp/ntp_tests.py . +COPY subset/ntp/test_ntp . + +CMD ["./test_ntp"] diff --git a/subset/ntp/README.md b/subset/ntp/README.md new file mode 100644 index 0000000000..b6b4bc3a8e --- /dev/null +++ b/subset/ntp/README.md @@ -0,0 +1,17 @@ +# NTP testing + +## test_ntp +The NTP test inspects client NTP support and version. + +### Note for test developers +The functional test code is included in the `ntp_tests.py` file. + +The test reads packets from startup.pcap. + +If the python code needs debugging, the pip module `scapy` is required (`pip install scapy`). + +### NTP Test conditions +| Test ID | Info | Pass | Fail | Skip | +|---|---|---|---|---| +| connection.network.ntp_support | Are the received NTP packets using NTP v4? | NTP version is 4 | NTP version is not 4 | No NTP packets are received | + diff --git a/subset/ntp/build.conf b/subset/ntp/build.conf new file mode 100644 index 0000000000..febb370b8f --- /dev/null +++ b/subset/ntp/build.conf @@ -0,0 +1,2 @@ +build subset/ntp +add ntp diff --git a/subset/ntp/ntp_tests.py b/subset/ntp/ntp_tests.py new file mode 100644 index 0000000000..2a774f1124 --- /dev/null +++ b/subset/ntp/ntp_tests.py @@ -0,0 +1,74 @@ +from __future__ import absolute_import +import sys +from scapy.all import NTP, rdpcap + +arguments = sys.argv + +test_request = str(arguments[1]) +cap_pcap_file = str(arguments[2]) + +report_filename = 'report.txt' +ignore = '%%' +summary_text = '' +result = 'fail' +dash_break_line = '--------------------\n' +description_ntp_support = 'Device supports NTP version 4.' + + +def write_report(string_to_append): + with open(report_filename, 'a+') as file_open: + file_open.write(string_to_append) + + +# Extracts the NTP version from the first client NTP packet +def ntp_client_version(capture): + client_packets = ntp_packets(capture, 3) + if len(client_packets) == 0: + return None + return client_packets[0].version + + +# Filters the packets by type (NTP) +def ntp_packets(capture, mode=None): + packets = [] + for packet in capture: + if NTP in packet: + ip = packet.payload + udp = ip.payload + ntp = udp.payload + if mode is None or mode == ntp.mode: + packets.append(ntp) + return packets + + +def test_ntp_support(): + capture = rdpcap(cap_pcap_file) + if len(capture) > 0: + version = ntp_client_version(capture) + if version is None: + add_summary("No NTP packets received.") + return 'skip' + if version == 4: + add_summary("Using NTPv4.") + return 'pass' + else: + add_summary("Not using NTPv4.") + return 'fail' + else: + add_summary("No NTP packets received.") + return 'skip' + + +def add_summary(text): + global summary_text + summary_text = summary_text + " " + text if summary_text else text + + +write_report("{b}{t}\n{b}".format(b=dash_break_line, t=test_request)) + + +if test_request == 'connection.network.ntp_support': + write_report("{d}\n{b}".format(b=dash_break_line, d=description_ntp_support)) + result = test_ntp_support() + +write_report("RESULT {r} {t} {s}\n".format(r=result, t=test_request, s=summary_text.strip())) diff --git a/subset/ntp/test_ntp b/subset/ntp/test_ntp new file mode 100755 index 0000000000..7521f9d74d --- /dev/null +++ b/subset/ntp/test_ntp @@ -0,0 +1,9 @@ +#!/bin/bash -e + +REPORT=/tmp/report.txt + +STARTUP=/scans/startup.pcap + +python ntp_tests.py connection.network.ntp_support $STARTUP + +cat report.txt >> $REPORT diff --git a/testing/test_aux.out b/testing/test_aux.out index acf12f7aa7..bed2e7dec1 100644 --- a/testing/test_aux.out +++ b/testing/test_aux.out @@ -57,6 +57,9 @@ RESULT pass security.passwords.telnet Default passwords have been changed. RESULT pass security.passwords.ssh Default passwords have been changed. RESULT skip security.firmware Could not retrieve a firmware version with nmap. Check bacnet port. RESULT pass security.firmware version found: ?\xFF\xFF\x19,>u\x08\x00no +RESULT pass connection.network.ntp_support Using NTPv4. +RESULT fail connection.network.ntp_support Not using NTPv4. +RESULT skip connection.network.ntp_support No NTP packets received. dhcp requests 1 1 0 1 01: [] 02: ['02:macoui:TimeoutError', '02:ping:TimeoutError'] @@ -105,6 +108,9 @@ port-01 module_config modules "nmap": { "enabled": true }, + "ntp": { + "enabled": true + }, "pass": { "enabled": true }, @@ -154,6 +160,9 @@ port-02 module_config modules "nmap": { "enabled": true }, + "ntp": { + "enabled": true + }, "pass": { "enabled": false }, diff --git a/testing/test_aux.sh b/testing/test_aux.sh index ebf75ee79c..f78d30f506 100755 --- a/testing/test_aux.sh +++ b/testing/test_aux.sh @@ -62,9 +62,9 @@ site_path: inst/test_site schema_path: schemas/udmi interfaces: faux-1: - opts: brute broadcast_client ntp_pass + opts: brute broadcast_client ntpv4 faux-2: - opts: nobrute expiredtls bacnetfail pubber passwordfail ntp_fail opendns + opts: nobrute expiredtls bacnetfail pubber passwordfail ntpv3 opendns faux-3: opts: tls macoui passwordpass bacnet pubber broadcast_client long_dhcp_response_sec: 0 @@ -114,6 +114,7 @@ capture_test_results tls capture_test_results password capture_test_results discover capture_test_results network +capture_test_results ntp # Capture peripheral logs more inst/run-port-*/scans/ip_triggers.txt | cat From fde428980a4e15cf35bbac5a802ffec5eac012cd Mon Sep 17 00:00:00 2001 From: Trevor Date: Wed, 8 Jul 2020 17:15:13 -0700 Subject: [PATCH 013/212] UDMI registrar error handling updates (#508) --- .checkstyle.xml | 2 +- bin/registrar | 2 +- bin/validate | 12 ++- .../main/java/daq/pubber/Configuration.java | 1 + pubber/src/main/java/daq/pubber/Pubber.java | 15 ++-- subset/cloud/test_udmi | 2 +- .../.idea/codeStyles/codeStyleConfig.xml | 2 +- ...ckson_core_jackson_annotations_2_11_0.xml} | 6 +- ...rxml_jackson_core_jackson_core_2_11_0.xml} | 6 +- ..._jackson_core_jackson_databind_2_11_0.xml} | 6 +- ...format_jackson_dataformat_yaml_2_11_0.xml} | 6 +- ...ml => Gradle__org_yaml_snakeyaml_1_26.xml} | 6 +- .../.idea/modules/daq-validator.validator.iml | 10 +-- validator/bin/registrar | 4 + validator/bin/test_schema | 2 +- validator/bin/validate | 3 + .../daq/mqtt/registrar/LocalDevice.java | 47 +++++------ .../google/daq/mqtt/registrar/Registrar.java | 77 +++++++++++++------ .../google/daq/mqtt/util/CloudIotManager.java | 10 +-- .../daq/mqtt/util/FirestoreDataSink.java | 24 +----- .../google/daq/mqtt/validator/Validator.java | 10 +-- 21 files changed, 138 insertions(+), 115 deletions(-) rename validator/.idea/libraries/{Gradle__com_fasterxml_jackson_core_jackson_annotations_2_10_3.xml => Gradle__com_fasterxml_jackson_core_jackson_annotations_2_11_0.xml} (54%) rename validator/.idea/libraries/{Gradle__com_fasterxml_jackson_core_jackson_core_2_10_3.xml => Gradle__com_fasterxml_jackson_core_jackson_core_2_11_0.xml} (55%) rename validator/.idea/libraries/{Gradle__com_fasterxml_jackson_core_jackson_databind_2_10_3.xml => Gradle__com_fasterxml_jackson_core_jackson_databind_2_11_0.xml} (55%) rename validator/.idea/libraries/{Gradle__com_fasterxml_jackson_dataformat_jackson_dataformat_yaml_2_10_3.xml => Gradle__com_fasterxml_jackson_dataformat_jackson_dataformat_yaml_2_11_0.xml} (68%) rename validator/.idea/libraries/{Gradle__org_yaml_snakeyaml_1_24.xml => Gradle__org_yaml_snakeyaml_1_26.xml} (50%) diff --git a/.checkstyle.xml b/.checkstyle.xml index a214cc83f6..469a132853 100644 --- a/.checkstyle.xml +++ b/.checkstyle.xml @@ -42,7 +42,7 @@ - + diff --git a/bin/registrar b/bin/registrar index e2278951e4..3f941ba188 100755 --- a/bin/registrar +++ b/bin/registrar @@ -27,4 +27,4 @@ validator/bin/build > /dev/null echo Running tools version `git describe` -validator/bin/registrar $project_id $site_path $schema_path $* +validator/bin/registrar $project_id $site_path $schema_path $* 2>&1 diff --git a/bin/validate b/bin/validate index bd13b42612..9789659c11 100755 --- a/bin/validate +++ b/bin/validate @@ -20,16 +20,14 @@ if [ -z "$schema_path" ]; then false fi -validator/bin/build +echo Building validator... +validator/bin/build > /dev/null -unset GOOGLE_CLOUD_PROJECT -export GOOGLE_APPLICATION_CREDENTIALS=$PWD/$gcp_cred -echo Using credentials from $GOOGLE_APPLICATION_CREDENTIALS echo Configured topic is $gcp_topic echo Configured schema is $schema_path -if [ -n "$site_path" ]; then - echo Configured site path is $site_path -fi +echo Configured site path is $site_path echo +echo Running tools version `git describe` + validator/bin/validate $schema_path pubsub:$gcp_topic dev $site_path diff --git a/pubber/src/main/java/daq/pubber/Configuration.java b/pubber/src/main/java/daq/pubber/Configuration.java index 7c362781ef..e72d6919d2 100644 --- a/pubber/src/main/java/daq/pubber/Configuration.java +++ b/pubber/src/main/java/daq/pubber/Configuration.java @@ -10,6 +10,7 @@ public class Configuration { public String registryId; public String gatewayId; public String deviceId; + public String sitePath; public String keyFile = "local/rsa_private.pkcs8"; public byte[] keyBytes; public String algorithm = "RS256"; diff --git a/pubber/src/main/java/daq/pubber/Pubber.java b/pubber/src/main/java/daq/pubber/Pubber.java index 5f28a08efa..1265b65e53 100644 --- a/pubber/src/main/java/daq/pubber/Pubber.java +++ b/pubber/src/main/java/daq/pubber/Pubber.java @@ -8,9 +8,6 @@ import daq.udmi.Message.Pointset; import daq.udmi.Message.PointsetState; import daq.udmi.Message.State; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.File; import java.nio.file.Files; import java.nio.file.Path; @@ -24,6 +21,8 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class Pubber { @@ -40,9 +39,10 @@ public class Pubber { private static final int MIN_REPORT_MS = 200; private static final int DEFAULT_REPORT_MS = 5000; private static final int CONFIG_WAIT_TIME_MS = 10000; - private static final int STATE_THROTTLE_MS = 1500; + private static final int STATE_THROTTLE_MS = 2000; private static final String CONFIG_ERROR_STATUS_KEY = "config_error"; private static final int LOGGING_MOD_COUNT = 10; + public static final String KEY_SITE_PATH_FORMAT = "%s/devices/%s/rsa_private.pkcs8"; private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); @@ -163,6 +163,11 @@ private void addPoint(AbstractPoint point) { } private void initialize() { + Preconditions.checkNotNull(configuration.deviceId, "configuration deviceId not defined"); + if (configuration.sitePath != null) { + configuration.keyFile = String.format(KEY_SITE_PATH_FORMAT, configuration.sitePath, + configuration.deviceId); + } Preconditions.checkState(mqttPublisher == null, "mqttPublisher already defined"); Preconditions.checkNotNull(configuration.keyFile, "configuration keyFile not defined"); System.err.println("Loading device key file from " + configuration.keyFile); @@ -262,8 +267,8 @@ private void publishLogMessage(String deviceId, String logMessage) { private void publishStateMessage(String deviceId) { lastStateTimeMs = sleepUntil(lastStateTimeMs + STATE_THROTTLE_MS); - info("Sending state message for device " + deviceId); deviceState.timestamp = new Date(); + info("Sending state message for device " + deviceId + " at " + deviceState.timestamp); mqttPublisher.publish(deviceId, STATE_TOPIC, deviceState); } diff --git a/subset/cloud/test_udmi b/subset/cloud/test_udmi index fde175a26d..aa484f5434 100755 --- a/subset/cloud/test_udmi +++ b/subset/cloud/test_udmi @@ -60,7 +60,7 @@ echo Configured schema is $schema_path echo Target device is $device_id echo -timeout 60 validator/bin/validate $PWD/$schema_path pubsub:$gcp_topic $service_id-$HOSTNAME || true +timeout 60 validator/bin/validate $PWD/$schema_path pubsub:$gcp_topic $service_id-$HOSTNAME -- || true function message_report { message_type=$1 diff --git a/validator/.idea/codeStyles/codeStyleConfig.xml b/validator/.idea/codeStyles/codeStyleConfig.xml index a55e7a179b..b9d18bf599 100644 --- a/validator/.idea/codeStyles/codeStyleConfig.xml +++ b/validator/.idea/codeStyles/codeStyleConfig.xml @@ -1,5 +1,5 @@ - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_annotations_2_10_3.xml b/validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_annotations_2_11_0.xml similarity index 54% rename from validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_annotations_2_10_3.xml rename to validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_annotations_2_11_0.xml index 940abc9cd6..fef9a9403a 100644 --- a/validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_annotations_2_10_3.xml +++ b/validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_annotations_2_11_0.xml @@ -1,11 +1,11 @@ - + - + - + \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_core_2_10_3.xml b/validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_core_2_11_0.xml similarity index 55% rename from validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_core_2_10_3.xml rename to validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_core_2_11_0.xml index c39a1aad89..93709bc78c 100644 --- a/validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_core_2_10_3.xml +++ b/validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_core_2_11_0.xml @@ -1,11 +1,11 @@ - + - + - + \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_databind_2_10_3.xml b/validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_databind_2_11_0.xml similarity index 55% rename from validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_databind_2_10_3.xml rename to validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_databind_2_11_0.xml index 401e4470cc..326959d4e0 100644 --- a/validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_databind_2_10_3.xml +++ b/validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_databind_2_11_0.xml @@ -1,11 +1,11 @@ - + - + - + \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_fasterxml_jackson_dataformat_jackson_dataformat_yaml_2_10_3.xml b/validator/.idea/libraries/Gradle__com_fasterxml_jackson_dataformat_jackson_dataformat_yaml_2_11_0.xml similarity index 68% rename from validator/.idea/libraries/Gradle__com_fasterxml_jackson_dataformat_jackson_dataformat_yaml_2_10_3.xml rename to validator/.idea/libraries/Gradle__com_fasterxml_jackson_dataformat_jackson_dataformat_yaml_2_11_0.xml index eeaf4be6fe..8b4a7f585e 100644 --- a/validator/.idea/libraries/Gradle__com_fasterxml_jackson_dataformat_jackson_dataformat_yaml_2_10_3.xml +++ b/validator/.idea/libraries/Gradle__com_fasterxml_jackson_dataformat_jackson_dataformat_yaml_2_11_0.xml @@ -1,11 +1,11 @@ - + - + - + \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__org_yaml_snakeyaml_1_24.xml b/validator/.idea/libraries/Gradle__org_yaml_snakeyaml_1_26.xml similarity index 50% rename from validator/.idea/libraries/Gradle__org_yaml_snakeyaml_1_24.xml rename to validator/.idea/libraries/Gradle__org_yaml_snakeyaml_1_26.xml index 6d98003d93..734cd9dad1 100644 --- a/validator/.idea/libraries/Gradle__org_yaml_snakeyaml_1_24.xml +++ b/validator/.idea/libraries/Gradle__org_yaml_snakeyaml_1_26.xml @@ -1,11 +1,11 @@ - + - + - + \ No newline at end of file diff --git a/validator/.idea/modules/daq-validator.validator.iml b/validator/.idea/modules/daq-validator.validator.iml index c07f3da9ef..f12ef8c574 100644 --- a/validator/.idea/modules/daq-validator.validator.iml +++ b/validator/.idea/modules/daq-validator.validator.iml @@ -12,8 +12,8 @@ - - + + @@ -46,9 +46,9 @@ - - - + + + diff --git a/validator/bin/registrar b/validator/bin/registrar index c302518d21..49dc18d1e3 100755 --- a/validator/bin/registrar +++ b/validator/bin/registrar @@ -16,6 +16,9 @@ devices_dir=$2 schema_dir=$3 device_filter=$4 +echo Using gcloud auth: +gcloud config get-value account || true + echo Using cloud project $project_id echo Using site config dir $devices_dir echo Using schema root dir $schema_dir @@ -24,6 +27,7 @@ echo Using device filter $device_filter JAVA=/usr/lib/jvm/java-11-openjdk-amd64/bin/java error=0 +echo java args $project_id $devices_dir $schema_dir $device_filter $JAVA -cp $jarfile $mainclass $project_id $devices_dir $schema_dir $device_filter || error=$? echo Registrar complete, exit $error diff --git a/validator/bin/test_schema b/validator/bin/test_schema index c73505aa2e..f3adbf1657 100755 --- a/validator/bin/test_schema +++ b/validator/bin/test_schema @@ -59,7 +59,7 @@ for schema in $schemas; do error=0 reltest=${testpath#$rootdir/} - (cd $rootdir; java -jar $jarfile $schemaname $reltest $ignoreset) 2> $output || error=$? + (cd $rootdir; java -jar $jarfile $schemaname $reltest $ignoreset --) 2> $output || error=$? if [ $force == y ]; then diff $expected $output || echo Updating $expected && cp $output $expected else diff --git a/validator/bin/validate b/validator/bin/validate index 910021f982..e79c158756 100755 --- a/validator/bin/validate +++ b/validator/bin/validate @@ -20,6 +20,9 @@ if [ ! -f $jarfile ]; then validator/bin/build fi +echo Using gcloud auth: +gcloud config get-value account || true + echo Executing validator $schema $target... echo Validating against schema $schemafile into validations/ diff --git a/validator/src/main/java/com/google/daq/mqtt/registrar/LocalDevice.java b/validator/src/main/java/com/google/daq/mqtt/registrar/LocalDevice.java index f36e338b85..e32dc8b2b0 100644 --- a/validator/src/main/java/com/google/daq/mqtt/registrar/LocalDevice.java +++ b/validator/src/main/java/com/google/daq/mqtt/registrar/LocalDevice.java @@ -51,7 +51,6 @@ class LocalDevice { private static final String RSA_CERT_PEM = "rsa_cert.pem"; private static final String RSA_PRIVATE_PEM = "rsa_private.pem"; private static final String RSA_PRIVATE_PKCS8 = "rsa_private.pkcs8"; - private static final String PHYSICAL_TAG_ERROR = "Physical tag %s %s does not match expected %s"; private static final Set DEVICE_FILES = ImmutableSet.of(METADATA_JSON); private static final Set KEY_FILES = ImmutableSet.of(RSA_PUBLIC_PEM, RSA_PRIVATE_PEM, RSA_PRIVATE_PKCS8); @@ -68,18 +67,17 @@ class LocalDevice { private final Map schemas; private final File deviceDir; private final UdmiSchema.Metadata metadata; - private final File devicesDir; private final ExceptionMap exceptionMap; private String deviceNumId; private CloudDeviceSettings settings; + private DeviceCredential deviceCredential; LocalDevice(File devicesDir, String deviceId, Map schemas) { try { this.deviceId = deviceId; this.schemas = schemas; - this.devicesDir = devicesDir; exceptionMap = new ExceptionMap("Exceptions for " + deviceId); deviceDir = new File(devicesDir, deviceId); metadata = readMetadata(); @@ -162,16 +160,21 @@ private String getAuthFileType() { return RSA_CERT_TYPE.equals(getAuthType()) ? RSA_CERT_FILE : RSA_KEY_FILE; } - private DeviceCredential loadCredential() { + public DeviceCredential loadCredential() { + deviceCredential = readCredential(); + return deviceCredential; + } + + public DeviceCredential readCredential() { try { if (hasGateway() && getAuthType() != null) { - throw new RuntimeException("Proxied devices should not have auth_type defined"); + throw new RuntimeException("Proxied devices should not have cloud.auth_type defined"); } if (!isDirectConnect()) { return null; } if (getAuthType() == null) { - throw new RuntimeException("Credential auth_type definition missing"); + throw new RuntimeException("Credential cloud.auth_type definition missing"); } File deviceKeyFile = new File(deviceDir, publicKeyFile()); if (!deviceKeyFile.exists()) { @@ -223,10 +226,6 @@ boolean isDirectConnect() { return isGateway() || !hasGateway(); } - String getGatewayId() { - return hasGateway() ? metadata.gateway.gateway_id : null; - } - CloudDeviceSettings getSettings() { try { if (settings != null) { @@ -236,7 +235,7 @@ CloudDeviceSettings getSettings() { if (metadata == null) { return settings; } - settings.credential = loadCredential(); + settings.credential = deviceCredential; settings.metadata = metadataString(); settings.config = deviceConfigString(); settings.proxyDevices = getProxyDevicesList(); @@ -297,6 +296,7 @@ private String metadataString() { } public void validateEnvelope(String registryId, String siteName) { + checkConsistency(siteName); try { UdmiSchema.Envelope envelope = new UdmiSchema.Envelope(); envelope.deviceId = deviceId; @@ -309,7 +309,6 @@ public void validateEnvelope(String registryId, String siteName) { } catch (Exception e) { throw new IllegalStateException("Validating envelope " + deviceId, e); } - checkConsistency(siteName); } private String fakeProjectId() { @@ -317,15 +316,17 @@ private String fakeProjectId() { } private void checkConsistency(String expectedSite) { - String siteName = metadata.system.location.site; - String assetSite = metadata.system.physical_tag.asset.site; String assetName = metadata.system.physical_tag.asset.name; - Preconditions.checkState(expectedSite.equals(siteName), - String.format(PHYSICAL_TAG_ERROR, "location", siteName, expectedSite)); - Preconditions.checkState(expectedSite.equals(assetSite), - String.format(PHYSICAL_TAG_ERROR, "site", assetSite, expectedSite)); Preconditions.checkState(deviceId.equals(assetName), - String.format(PHYSICAL_TAG_ERROR, "name", assetName, deviceId)); + String.format("system.physical_tag.asset.name %s does not match expected %s", assetName, deviceId)); + + String assetSite = metadata.system.physical_tag.asset.site; + Preconditions.checkState(expectedSite.equals(assetSite), + String.format("system.physical_tag.asset.site %s does not match expected %s", assetSite, expectedSite)); + + String siteName = metadata.system.location.site; + Preconditions.checkState(expectedSite.equals(siteName), + String.format("system.location.site %s does not match expected %s", siteName, expectedSite)); } private String makeNumId(UdmiSchema.Envelope envelope) { @@ -335,11 +336,12 @@ private String makeNumId(UdmiSchema.Envelope envelope) { public void writeErrors() { File errorsFile = new File(deviceDir, DEVICE_ERRORS_JSON); - System.err.println("Updating " + errorsFile); if (exceptionMap.isEmpty()) { + System.err.println("Removing " + errorsFile); errorsFile.delete(); return; } + System.err.println("Updating " + errorsFile); try (PrintStream printStream = new PrintStream(new FileOutputStream(errorsFile))) { ExceptionMap.ErrorTree errorTree = ExceptionMap.format(exceptionMap, ERROR_FORMAT_INDENT); errorTree.write(printStream); @@ -377,8 +379,9 @@ void writeNormalized() { public void writeConfigFile() { File configFile = new File(deviceDir, GENERATED_CONFIG_JSON); try (OutputStream outputStream = new FileOutputStream(configFile)) { - outputStream.write(settings.config.getBytes()); + outputStream.write(getSettings().config.getBytes()); } catch (Exception e) { + e.printStackTrace(); throw new RuntimeException("While writing "+ configFile.getAbsolutePath(), e); } } @@ -399,7 +402,7 @@ public ExceptionMap getErrors() { return exceptionMap; } - public boolean hasValidMetadata() { + public boolean isValid() { return metadata != null; } diff --git a/validator/src/main/java/com/google/daq/mqtt/registrar/Registrar.java b/validator/src/main/java/com/google/daq/mqtt/registrar/Registrar.java index 6b991bca48..e665d9ed16 100644 --- a/validator/src/main/java/com/google/daq/mqtt/registrar/Registrar.java +++ b/validator/src/main/java/com/google/daq/mqtt/registrar/Registrar.java @@ -1,5 +1,7 @@ package com.google.daq.mqtt.registrar; +import static java.util.stream.Collectors.toSet; + import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; @@ -7,24 +9,30 @@ import com.google.api.services.cloudiot.v1.model.Device; import com.google.api.services.cloudiot.v1.model.DeviceCredential; import com.google.common.base.Preconditions; -import com.google.daq.mqtt.util.*; +import com.google.common.collect.ImmutableList; +import com.google.daq.mqtt.util.CloudDeviceSettings; +import com.google.daq.mqtt.util.CloudIotManager; +import com.google.daq.mqtt.util.ConfigUtil; +import com.google.daq.mqtt.util.ExceptionMap; import com.google.daq.mqtt.util.ExceptionMap.ErrorTree; -import org.everit.json.schema.Schema; -import org.everit.json.schema.loader.SchemaClient; -import org.everit.json.schema.loader.SchemaLoader; -import org.json.JSONObject; -import org.json.JSONTokener; - +import com.google.daq.mqtt.util.PubSubPusher; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.math.BigInteger; -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; - -import static java.util.stream.Collectors.toSet; +import org.everit.json.schema.Schema; +import org.everit.json.schema.loader.SchemaClient; +import org.everit.json.schema.loader.SchemaLoader; +import org.json.JSONObject; +import org.json.JSONTokener; public class Registrar { @@ -43,6 +51,7 @@ public class Registrar { .setDateFormat(new ISO8601DateFormat()) .setSerializationInclusion(Include.NON_NULL); public static final String ALL_MATCH = ""; + private static final String LOCAL_ONLY_PROJECT_ID = "--"; private CloudIotManager cloudIotManager; private File siteConfig; @@ -90,7 +99,7 @@ private void writeErrors() throws Exception { .put(device.getDeviceId(), "True"); } }); - if (!blockErrors.isEmpty()) { + if (blockErrors != null && !blockErrors.isEmpty()) { errorSummary.put("Block", blockErrors.stream().collect(Collectors.toMap( Map.Entry::getKey, entry -> entry.getValue().toString()))); } @@ -121,27 +130,31 @@ private void processDevices(String deviceRegex) { Set extraDevices = cloudDevices.stream().map(Device::getId).collect(toSet()); for (String localName : localDevices.keySet()) { LocalDevice localDevice = localDevices.get(localName); - if (!localDevice.hasValidMetadata()) { + if (!localDevice.isValid()) { System.err.println("Skipping (invalid) " + localName); continue; } extraDevices.remove(localName); try { - updateCloudIoT(localDevice); localDevice.writeConfigFile(); - Device device = Preconditions.checkNotNull(fetchDevice(localName), - "missing device " + localName); - BigInteger numId = Preconditions.checkNotNull(device.getNumId(), - "missing deviceNumId for " + localName); - localDevice.setDeviceNumId(numId.toString()); - sendMetadataMessage(localDevice); + if (!localOnly()) { + updateCloudIoT(localDevice); + Device device = Preconditions.checkNotNull(fetchDevice(localName), + "missing device " + localName); + BigInteger numId = Preconditions.checkNotNull(device.getNumId(), + "missing deviceNumId for " + localName); + localDevice.setDeviceNumId(numId.toString()); + sendMetadataMessage(localDevice); + } } catch (Exception e) { System.err.println("Deferring exception: " + e.toString()); localDevice.getErrors().put("Registering", e); } } - bindGatewayDevices(localDevices); - blockErrors = blockExtraDevices(extraDevices); + if (!localOnly()) { + bindGatewayDevices(localDevices); + blockErrors = blockExtraDevices(extraDevices); + } System.err.println(String.format("Processed %d devices", localDevices.size())); } catch (Exception e) { throw new RuntimeException("While processing devices", e); @@ -209,8 +222,17 @@ private void shutdown() { } private List fetchDeviceList(Pattern devicePattern) { - System.err.println("Fetching remote registry " + cloudIotManager.getRegistryId()); - return cloudIotManager.fetchDeviceList(devicePattern); + if (localOnly()) { + System.err.println("Skipping remote registry fetch"); + return ImmutableList.of(); + } else { + System.err.println("Fetching remote registry " + cloudIotManager.getRegistryPath()); + return cloudIotManager.fetchDeviceList(devicePattern); + } + } + + private boolean localOnly() { + return LOCAL_ONLY_PROJECT_ID.equals(projectId); } private Map loadLocalDevices(Pattern devicePattern) { @@ -267,8 +289,13 @@ private Map loadDevices(File devicesDir, String[] devices, Matcher deviceMatch = devicePattern.matcher(deviceName); if (deviceMatch.find() && LocalDevice.deviceExists(devicesDir, deviceName)) { System.err.println("Loading local device " + deviceName); - LocalDevice localDevice = new LocalDevice(devicesDir, deviceName, schemas); - localDevices.put(deviceName, localDevice); + LocalDevice localDevice = localDevices.computeIfAbsent(deviceName, + keyName -> new LocalDevice(devicesDir, deviceName, schemas)); + try { + localDevice.loadCredential(); + } catch (Exception e) { + localDevice.getErrors().put("Credential", e); + } try { localDevice.validateEnvelope(cloudIotManager.getRegistryId(), cloudIotManager.getSiteName()); } catch (Exception e) { diff --git a/validator/src/main/java/com/google/daq/mqtt/util/CloudIotManager.java b/validator/src/main/java/com/google/daq/mqtt/util/CloudIotManager.java index f69c3bb0ae..1fec58ed0a 100644 --- a/validator/src/main/java/com/google/daq/mqtt/util/CloudIotManager.java +++ b/validator/src/main/java/com/google/daq/mqtt/util/CloudIotManager.java @@ -68,12 +68,12 @@ private static CloudIotConfig validate(CloudIotConfig cloudIotConfig) { return cloudIotConfig; } - private String getRegistryPath(String registryId) { + public String getRegistryPath() { return projectPath + "/registries/" + registryId; } private String getDevicePath(String registryId, String deviceId) { - return getRegistryPath(registryId) + "/devices/" + deviceId; + return getRegistryPath() + "/devices/" + deviceId; } private void initializeCloudIoT() { @@ -168,7 +168,7 @@ private GatewayConfig getGatewayConfig(CloudDeviceSettings settings) { private void createDevice(String deviceId, CloudDeviceSettings settings) throws IOException { try { - cloudIotRegistries.devices().create(getRegistryPath(registryId), + cloudIotRegistries.devices().create(getRegistryPath(), makeDevice(deviceId, settings, null)).execute(); } catch (GoogleJsonResponseException e) { throw new RuntimeException("Remote error creating device " + deviceId, e); @@ -205,7 +205,7 @@ public List fetchDeviceList(Pattern devicePattern) { try { List devices = cloudIotRegistries .devices() - .list(getRegistryPath(registryId)) + .list(getRegistryPath()) .setPageSize(LIST_PAGE_SIZE) .execute() .getDevices(); @@ -254,7 +254,7 @@ public Object getCloudRegion() { } public void bindDevice(String proxyDeviceId, String gatewayDeviceId) throws IOException { - cloudIotRegistries.bindDeviceToGateway(getRegistryPath(registryId), + cloudIotRegistries.bindDeviceToGateway(getRegistryPath(), getBindRequest(proxyDeviceId, gatewayDeviceId)).execute(); } diff --git a/validator/src/main/java/com/google/daq/mqtt/util/FirestoreDataSink.java b/validator/src/main/java/com/google/daq/mqtt/util/FirestoreDataSink.java index 9a09a0cc9d..ac0d527f2a 100644 --- a/validator/src/main/java/com/google/daq/mqtt/util/FirestoreDataSink.java +++ b/validator/src/main/java/com/google/daq/mqtt/util/FirestoreDataSink.java @@ -1,6 +1,5 @@ package com.google.daq.mqtt.util; -import com.google.auth.Credentials; import com.google.auth.oauth2.GoogleCredentials; import com.google.cloud.ServiceOptions; import com.google.cloud.firestore.DocumentReference; @@ -8,9 +7,6 @@ import com.google.cloud.firestore.FirestoreOptions; import com.google.common.base.Preconditions; import com.google.daq.mqtt.util.ExceptionMap.ErrorTree; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; import java.time.Instant; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; @@ -19,8 +15,6 @@ public class FirestoreDataSink { - private static final String - CREDENTIAL_ERROR_FORMAT = "Credential file %s defined by %s not found."; private static final String VIEW_URL_FORMAT = "https://console.cloud.google.com/firestore/data/registries/?project=%s"; @@ -34,10 +28,10 @@ public class FirestoreDataSink { public FirestoreDataSink() { try { - Credentials projectCredentials = getProjectCredentials(); + GoogleCredentials credential = GoogleCredentials.getApplicationDefault(); FirestoreOptions firestoreOptions = FirestoreOptions.getDefaultInstance().toBuilder() - .setCredentials(projectCredentials) + .setCredentials(credential) .setProjectId(projectId) .setTimestampsInSnapshotsEnabled(true) .build(); @@ -48,20 +42,8 @@ public FirestoreDataSink() { } } - private Credentials getProjectCredentials() throws IOException { - File credentialFile = new File(System.getenv(ServiceOptions.CREDENTIAL_ENV_NAME)); - if (!credentialFile.exists()) { - throw new RuntimeException(String.format(CREDENTIAL_ERROR_FORMAT, - credentialFile.getAbsolutePath(), ServiceOptions.CREDENTIAL_ENV_NAME)); - } - try (FileInputStream serviceAccount = new FileInputStream(credentialFile)) { - return GoogleCredentials.fromStream(serviceAccount); - } - } - public void validationResult(String deviceId, String schemaId, Map attributes, - Object message, - ErrorTree errorTree) { + Object message, ErrorTree errorTree) { if (oldError.get() != null) { throw oldError.getAndSet(null); } diff --git a/validator/src/main/java/com/google/daq/mqtt/validator/Validator.java b/validator/src/main/java/com/google/daq/mqtt/validator/Validator.java index 5fc94ed99c..ca133f2769 100644 --- a/validator/src/main/java/com/google/daq/mqtt/validator/Validator.java +++ b/validator/src/main/java/com/google/daq/mqtt/validator/Validator.java @@ -56,6 +56,7 @@ public class Validator { private static final String DEVICE_REGISTRY_ID_KEY = "deviceRegistryId"; private static final String UNKNOWN_SCHEMA_DEFAULT = "unknown"; private static final String POINTSET_TYPE = "pointset"; + private static final String NO_SITE = "--"; private FirestoreDataSink dataSink; private File schemaRoot; private String schemaSpec; @@ -69,15 +70,14 @@ public class Validator { public static void main(String[] args) { Validator validator = new Validator(); try { - System.out.println(ServiceOptions.CREDENTIAL_ENV_NAME + "=" + - System.getenv(ServiceOptions.CREDENTIAL_ENV_NAME)); - if (args.length < 3 || args.length > 4) { - throw new IllegalArgumentException("Args: schema target inst_name [site]"); + if (args.length != 4) { + throw new IllegalArgumentException("Args: [schema] [target] [inst_name] [site]"); } validator.setSchemaSpec(args[0]); String targetSpec = args[1]; String instName = args[2]; - if (args.length >= 4) { + String siteDir = args[3]; + if (!NO_SITE.equals(siteDir)) { validator.setSiteDir(args[3]); } if (targetSpec.startsWith(PUBSUB_PREFIX)) { From 7478825759236645d3329939b3350dde4c678f1a Mon Sep 17 00:00:00 2001 From: Trevor Date: Thu, 9 Jul 2020 16:55:58 -0700 Subject: [PATCH 014/212] Use trunk rather than stack between switches (#526) --- daq/network.py | 2 +- daq/topology.py | 27 +++++++++++++++------------ 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/daq/network.py b/daq/network.py index b622205926..255a6bd259 100644 --- a/daq/network.py +++ b/daq/network.py @@ -136,7 +136,7 @@ def _attach_sec_device_links(self): def is_system_port(self, dpid, port): """Check if the dpid/port combo is the system trunk port""" - return dpid == self.topology.PRI_DPID and port == self.topology.PRI_STACK_PORT + return dpid == self.topology.PRI_DPID and port == self.topology.PRI_TRUNK_PORT def is_device_port(self, dpid, port): """Check if the dpid/port combo is for a valid device""" diff --git a/daq/topology.py b/daq/topology.py index 2438b49012..8d0cb62390 100644 --- a/daq/topology.py +++ b/daq/topology.py @@ -31,13 +31,14 @@ class FaucetTopology: INCOMING_ACL_FORMAT = "dp_%s_incoming_acl" PORTSET_ACL_FORMAT = "dp_%s_portset_%d_acl" LOCAL_ACL_FORMAT = "dp_%s_local_acl" - _DEFAULT_STACK_PORT_NAME = "stack_sec" + _DEFAULT_SEC_TRUNK_NAME = "trunk_sec" _MIRROR_IFACE_FORMAT = "mirror-%d" _MIRROR_PORT_BASE = 1000 _SWITCH_LOCAL_PORT = _MIRROR_PORT_BASE _VLAN_BASE = 1000 PRI_DPID = 1 - PRI_STACK_PORT = 1 + PRI_TRUNK_PORT = 1 + PRI_TRUNK_NAME = 'trunk_pri' _NO_VLAN = "0x0000/0x1000" def __init__(self, config): @@ -92,7 +93,7 @@ def get_sec_dpid(self): return self.sec_dpid def get_sec_port(self): - """Return the secondary stacking port""" + """Return the secondary trunk port""" return self.sec_port def get_device_intfs(self): @@ -173,20 +174,23 @@ def _update_port_vlan(self, port_no, port_set): def _port_set_vlan(self, port_set=None): return self._VLAN_BASE + (port_set if port_set else 0) - def _make_pri_stack_interface(self): + def _make_pri_trunk_interface(self): interface = {} interface['acl_in'] = self.INCOMING_ACL_FORMAT % self.pri_name - interface['stack'] = {'dp': self.sec_name, 'port': self.sec_port} - interface['name'] = 'stack_pri' + interface['tagged_vlans'] = self._vlan_tags() + interface['name'] = self.PRI_TRUNK_NAME return interface - def _make_sec_stack_interface(self): + def _make_sec_trunk_interface(self): interface = {} interface['acl_in'] = self.INCOMING_ACL_FORMAT % self.sec_name - interface['stack'] = {'dp': self.pri_name, 'port': self.PRI_STACK_PORT} - interface['name'] = self.get_ext_intf() or self._DEFAULT_STACK_PORT_NAME + interface['tagged_vlans'] = self._vlan_tags() + interface['name'] = self.get_ext_intf() or self._DEFAULT_SEC_TRUNK_NAME return interface + def _vlan_tags(self): + return list(range(self._VLAN_BASE, self._VLAN_BASE + self.sec_port)) + def _make_default_acl_rules(self): rules = [] if not self._append_acl_template(rules, 'raw'): @@ -201,7 +205,7 @@ def _make_sec_port_interface(self, port_no): def _make_pri_interfaces(self): interfaces = {} - interfaces[self.PRI_STACK_PORT] = self._make_pri_stack_interface() + interfaces[self.PRI_TRUNK_PORT] = self._make_pri_trunk_interface() for port_set in range(1, self.sec_port): for port in self._get_gw_ports(port_set): interfaces[port] = self._make_gw_interface(port_set) @@ -212,7 +216,7 @@ def _make_pri_interfaces(self): def _make_sec_interfaces(self): interfaces = {} - interfaces[self.sec_port] = self._make_sec_stack_interface() + interfaces[self.sec_port] = self._make_sec_trunk_interface() for port in range(1, self.sec_port): interfaces[port] = self._make_sec_port_interface(port) return interfaces @@ -228,7 +232,6 @@ def _make_pri_topology(self): pri_dp = {} pri_dp['dp_id'] = self.PRI_DPID pri_dp['name'] = self.pri_name - pri_dp['stack'] = {'priority':1} pri_dp['interfaces'] = self._make_pri_interfaces() return pri_dp From a0bc2b725c948cc37cd85d4ead699cc95f96cdbd Mon Sep 17 00:00:00 2001 From: henry54809 Date: Fri, 10 Jul 2020 09:10:13 -0700 Subject: [PATCH 015/212] using usi in daq (#520) --- bin/build_proto | 2 + bin/setup_dev | 5 +- cmd/exrun | 9 +- cmd/usi | 18 + config/modules/host.conf | 1 + config/modules/topo.conf | 1 + config/system/default.yaml | 4 + daq/gateway.py | 19 +- daq/host.py | 38 +- daq/runner.py | 2 +- firebase/public/protos.hash | 2 +- firebase/public/protos.html | 35 ++ libs/proto/system_config_pb2.py | 178 ++++--- libs/proto/usi_pb2.py | 449 ++++++++++++++++++ libs/proto/usi_pb2_grpc.py | 161 +++++++ proto/system_config.proto | 9 + testing/run_unit_tests.sh | 2 +- usi/Dockerfile.usi | 3 +- usi/build.conf | 2 + usi/src/main/java/daq/usi/UsiImpl.java | 37 +- .../main/java/daq/usi/ovs/OpenVSwitch.java | 48 +- usi/start | 2 +- 22 files changed, 909 insertions(+), 118 deletions(-) create mode 100755 cmd/usi create mode 100644 libs/proto/usi_pb2.py create mode 100644 libs/proto/usi_pb2_grpc.py create mode 100644 usi/build.conf diff --git a/bin/build_proto b/bin/build_proto index ad07980e9e..b0886e5d86 100755 --- a/bin/build_proto +++ b/bin/build_proto @@ -56,3 +56,5 @@ mkdir -p libs/proto/ touch libs/proto/__init__.py cp build/daq/proto/*.py libs/proto/ cp build/protos.html $WEB_ROOT/ + +python -m grpc_tools.protoc -I usi/src/main/proto/ --python_out=libs/proto/ --grpc_python_out=libs/proto/ usi/src/main/proto/usi.proto diff --git a/bin/setup_dev b/bin/setup_dev index 62223aa9c3..59eb0f6df3 100755 --- a/bin/setup_dev +++ b/bin/setup_dev @@ -137,8 +137,9 @@ $PIP install --upgrade --index-url=https://pypi.python.org/simple Jinja2 \ google-api-core==1.16.0 \ google-cloud-storage==1.16.1 \ google-cloud-firestore==1.6.0 \ - google-cloud-logging==1.14.0 - + google-cloud-logging==1.14.0 \ + grpcio-tools==1.30.0 + $PIP freeze echo Resetting .cache directory permissions... test -n "$USER" && sudo chown $USER -R $HOME/.cache diff --git a/cmd/exrun b/cmd/exrun index e0538e81a2..88a047994b 100755 --- a/cmd/exrun +++ b/cmd/exrun @@ -44,6 +44,7 @@ FAUCET=$(realpath $ROOT/faucet) FORCH=$(realpath $ROOT/forch) MININET=$(realpath $ROOT/mininet) LIBS=$(realpath $ROOT/libs) +PROTO=$(realpath $ROOT/libs/proto) if [ ! -d $FAUCET ]; then echo Faucet directory $FAUCET not found, try running bin/setup_dev. @@ -66,7 +67,7 @@ if [ "$1" == "-h" ]; then skip_autostart=y fi -export PYTHONPATH=$FORCH:$FAUCET:$MININET:$LIBS +export PYTHONPATH=$FORCH:$FAUCET:$MININET:$LIBS:$PROTO mkdir -p $INSTDIR rm -f $INSTDIR/faucet* $cleanup_file @@ -81,7 +82,8 @@ sudo rm -f $cleanup_file function autostart { tmp=`mktemp` echo DAQ autostart $@ - eval $@ | tee $tmp + eval $@ > $tmp # Don't use "eval $@ | tee $tmp" here; breaks cmd/usi. + cat $tmp grep -e '^\s*DAQ autoclean\s' $tmp >> $cleanup_file || true } @@ -105,6 +107,9 @@ else echo No external switch model specified. fi +docker rm -f daq-usi || true +autostart cmd/usi + # Kill any gateways so that they don't prematurely assign an IP address. gwids=$(docker ps --format '{{ .Image }} {{ .Names }}' | fgrep daqf/networking | awk '{print $2}') || true for gwid in $gwids; do diff --git a/cmd/usi b/cmd/usi new file mode 100755 index 0000000000..fe39673d89 --- /dev/null +++ b/cmd/usi @@ -0,0 +1,18 @@ +#!/bin/bash -e +TMP_DIR=/tmp/usi + +function dump_ovs_interfaces { + while true; do + sudo ovs-ofctl show sec > $TMP_DIR/ovs_output.txt || true + sleep 5 + done +} + +echo Starting USI +mkdir -p $TMP_DIR +dump_ovs_interfaces & +PID=$! +docker run -d -v /tmp/usi:/ovs --privileged --network=host --name daq-usi daqf/usi + +echo DAQ autoclean docker kill daq-usi +echo DAQ autoclean kill $PID diff --git a/config/modules/host.conf b/config/modules/host.conf index e6ec5e37ef..8ec24df938 100644 --- a/config/modules/host.conf +++ b/config/modules/host.conf @@ -12,6 +12,7 @@ add mudgee # Additional base modules include subset/pentests/build.conf +include usi/build.conf # Example of how to remove something. remove unused diff --git a/config/modules/topo.conf b/config/modules/topo.conf index 4d47ec6cf9..ba02ce2374 100644 --- a/config/modules/topo.conf +++ b/config/modules/topo.conf @@ -3,3 +3,4 @@ build docker/modules # Use ping with runtime configuration for topo testing. add ping +include usi/build.conf diff --git a/config/system/default.yaml b/config/system/default.yaml index 644993b96e..67daa36ba0 100644 --- a/config/system/default.yaml +++ b/config/system/default.yaml @@ -37,3 +37,7 @@ long_dhcp_response_sec: 105 # finish hook: executed at the end of every test finish_hook: bin/dump_network + +# usi url for DAQ to connect to +usi_setup: + url: localhost:5000 diff --git a/daq/gateway.py b/daq/gateway.py index c7c54182a5..9984dc7a6e 100644 --- a/daq/gateway.py +++ b/daq/gateway.py @@ -12,6 +12,7 @@ LOGGER = logger.get_logger('gateway') + class Gateway(): """Gateway collection class for managing testing services""" @@ -37,8 +38,8 @@ def __init__(self, runner, name, port_set, network): self.dummy = None self.tmpdir = None self.targets = {} - self.test_ports = {} - self.ready = {} + self.test_ports = set() + self.ready = set() self.activated = False self.result_linger = False self._scan_monitor = None @@ -125,6 +126,14 @@ def request_new_ip(self, mac): """Requests a new ip for the device""" self.execute_script('new_ip', mac) + def change_dhcp_response_time(self, mac, time): + """Change dhcp response time for device mac""" + self.execute_script('change_dhcp_response_time', mac, time) + + def stop_dhcp_response(self, mac): + """Stops DHCP respopnse for the device""" + self.change_dhcp_response_time(mac, -1) + def allocate_test_port(self): """Get the test port to use for this gateway setup""" test_port = self._switch_port(self.TEST_OFFSET_START) @@ -132,7 +141,7 @@ def allocate_test_port(self): test_port = test_port + 1 limit_port = self._switch_port(self.NUM_SET_PORTS) assert test_port < limit_port, 'no test ports available' - self.test_ports[test_port] = True + self.test_ports.add(test_port) return test_port def _startup_scan(self, host): @@ -160,7 +169,7 @@ def _scan_error(self, e): def release_test_port(self, test_port): """Release the given port from the gateway""" assert test_port in self.test_ports, 'test port not allocated' - del self.test_ports[test_port] + self.test_ports.remove(test_port) def _switch_port(self, offset): return self.port_set * self.SET_SPACING + offset @@ -207,7 +216,7 @@ def target_ready(self, target_mac): """Mark a target ready, and return set of ready targets""" if not target_mac in self.ready: LOGGER.info('Ready target %s from gateway group %s', target_mac, self.name) - self.ready[target_mac] = True + self.ready.add(target_mac) return self.ready def get_targets(self): diff --git a/daq/host.py b/daq/host.py index dc13f9b659..8dc3d5f8ac 100644 --- a/daq/host.py +++ b/daq/host.py @@ -5,9 +5,12 @@ import shutil import time from datetime import timedelta, datetime +import grpc from clib import tcpdump_helper from report import ResultType, ReportGenerator +from proto import usi_pb2 as usi +from proto import usi_pb2_grpc as usi_service import configurator import docker_test @@ -46,10 +49,12 @@ class MODE: LONG = 'long' MERR = 'merr' + def pre_states(): """Return pre-test states for basic operation""" return ['startup', 'sanity', 'ipaddr', 'base', 'monitor'] + def post_states(): """Return post-test states for recording finalization""" return ['finish', 'info', 'timer'] @@ -96,6 +101,7 @@ def __init__(self, runner, gateway, target, config): _default_timeout_sec = int(config.get('default_timeout_sec', 0)) self._default_timeout_sec = _default_timeout_sec if _default_timeout_sec else None self._finish_hook_script = config.get('finish_hook') + self._usi_url = config.get('usi_setup', {}).get('url') self._mirror_intf_name = None self._monitor_ref = None self._monitor_start = None @@ -271,6 +277,21 @@ def _state_transition(self, target, expected=None): LOGGER.debug('Target port %d state: %s -> %s', self.target_port, self.state, target) self.state = target + def _build_switch_info(self) -> usi.SwitchInfo: + switch_config = self._get_switch_config() + if switch_config["model"]: + switch_model = usi.SwitchModel.Value(switch_config["model"]) + else: + switch_model = usi.SwitchModel.OVS_SWITCH + params = { + "ip_addr": switch_config["ip"], + "device_port": self.target_port, + "model": switch_model, + "username": switch_config["username"], + "password": switch_config["password"] + } + return usi.SwitchInfo(**params) + def is_running(self): """Return True if this host is running active test.""" return self.state != _STATE.ERROR and self.state != _STATE.DONE @@ -285,6 +306,21 @@ def notify_activate(self): self._record_result('startup', state=MODE.HOLD) return self.state == _STATE.WAITING + def connect_port(self, connect): + """Connects/Disconnects port for this host""" + switch_info = self._build_switch_info() + try: + with grpc.insecure_channel(self._usi_url) as channel: + stub = usi_service.USIServiceStub(channel) + if connect: + res = stub.connect(switch_info) + else: + res = stub.disconnect(switch_info) + LOGGER.info('Target port %s %s successful? %s', self.target_port, "connect" + if connect else "disconnect", res.success) + except Exception as e: + LOGGER.error(e) + def _prepare(self): LOGGER.info('Target port %d waiting for ip as %s', self.target_port, self.target_mac) self._state_transition(_STATE.WAITING, _STATE.INIT) @@ -306,7 +342,7 @@ def _prepare(self): if dhcp_mode == 'long_response' else 0 LOGGER.info('Target port %d using %s DHCP mode, wait %s', self.target_port, dhcp_mode, wait_time) - self.gateway.execute_script('change_dhcp_response_time', self.target_mac, wait_time) + self.gateway.change_dhcp_response_time(self.target_mac, wait_time) _ = [listener(self) for listener in self._dhcp_listeners] def _aux_module_timeout_handler(self): diff --git a/daq/runner.py b/daq/runner.py index 631aa43526..5895045271 100644 --- a/daq/runner.py +++ b/daq/runner.py @@ -393,7 +393,7 @@ def _target_set_trigger(self, target_port): # Stops all DHCP response initially # Selectively enables dhcp response at ipaddr stage based on dhcp mode - gateway.execute_script('change_dhcp_response_time', target_mac, -1) + gateway.stop_dhcp_response(target_mac) gateway.attach_target(target_port, target) try: diff --git a/firebase/public/protos.hash b/firebase/public/protos.hash index bab39e76c2..3873f3c004 100644 --- a/firebase/public/protos.hash +++ b/firebase/public/protos.hash @@ -1 +1 @@ -b7a56a30dafe26576d6bdef00dfb57dc07a016ac proto/system_config.proto +96148b4135bc7326586f96fc38a18beeca8147c4 proto/system_config.proto diff --git a/firebase/public/protos.html b/firebase/public/protos.html index d24bed4958..cfcb14e33d 100644 --- a/firebase/public/protos.html +++ b/firebase/public/protos.html @@ -198,6 +198,10 @@

Table of Contents

MSwitchSetup +
  • + MUSISetup +
  • + @@ -478,6 +482,13 @@

    DaqConfig

    Set time between port disconnect and host tests shutdown

    + + usi_setup + USISetup + +

    USI url

    + + @@ -679,6 +690,30 @@

    SwitchSetup

    +

    USISetup

    +

    USI paramters

    + + + + + + + + + + + + + + + + +
    FieldTypeLabelDescription
    urlstring

    + + + + + diff --git a/libs/proto/system_config_pb2.py b/libs/proto/system_config_pb2.py index e4746e687f..e110d5eade 100644 --- a/libs/proto/system_config_pb2.py +++ b/libs/proto/system_config_pb2.py @@ -1,7 +1,8 @@ -# -*- coding: utf-8 -*- # Generated by the protocol buffer compiler. DO NOT EDIT! # source: daq/proto/system_config.proto +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection @@ -18,7 +19,7 @@ package='', syntax='proto3', serialized_options=None, - serialized_pb=b'\n\x1d\x64\x61q/proto/system_config.proto\"\xfb\x07\n\tDaqConfig\x12\x18\n\x10site_description\x18\x01 \x01(\t\x12\x18\n\x10monitor_scan_sec\x18\x02 \x01(\x05\x12\x1b\n\x13\x64\x65\x66\x61ult_timeout_sec\x18\x03 \x01(\x05\x12\x12\n\nsettle_sec\x18& \x01(\x05\x12\x11\n\tbase_conf\x18\x04 \x01(\t\x12\x11\n\tsite_path\x18\x05 \x01(\t\x12\x1f\n\x17initial_dhcp_lease_time\x18\x06 \x01(\t\x12\x17\n\x0f\x64hcp_lease_time\x18\x07 \x01(\t\x12\x19\n\x11\x64hcp_response_sec\x18\' \x01(\x05\x12\x1e\n\x16long_dhcp_response_sec\x18\x08 \x01(\x05\x12\"\n\x0cswitch_setup\x18\t \x01(\x0b\x32\x0c.SwitchSetup\x12\x12\n\nhost_tests\x18\x10 \x01(\t\x12\x13\n\x0b\x62uild_tests\x18$ \x01(\x08\x12\x11\n\trun_limit\x18\x11 \x01(\x05\x12\x11\n\tfail_mode\x18\x12 \x01(\x08\x12\x13\n\x0bsingle_shot\x18\" \x01(\x08\x12\x15\n\rresult_linger\x18\x13 \x01(\x08\x12\x0f\n\x07no_test\x18\x14 \x01(\x08\x12\x11\n\tkeep_hold\x18( \x01(\x08\x12\x14\n\x0c\x64\x61q_loglevel\x18\x15 \x01(\t\x12\x18\n\x10mininet_loglevel\x18\x16 \x01(\t\x12\x13\n\x0b\x66inish_hook\x18# \x01(\t\x12\x10\n\x08gcp_cred\x18\x17 \x01(\t\x12\x11\n\tgcp_topic\x18\x18 \x01(\t\x12\x13\n\x0bschema_path\x18\x19 \x01(\t\x12\x11\n\tmud_files\x18\x1a \x01(\t\x12\x14\n\x0c\x64\x65vice_specs\x18\x1b \x01(\t\x12\x13\n\x0btest_config\x18\x1c \x01(\t\x12\x19\n\x11port_debounce_sec\x18\x1d \x01(\x05\x12\x11\n\tfail_hook\x18\x1e \x01(\t\x12\x17\n\x0f\x64\x65vice_template\x18\x1f \x01(\t\x12\x14\n\x0csite_reports\x18 \x01(\t\x12\x1f\n\x17run_data_retention_days\x18! \x01(\x02\x12.\n\ninterfaces\x18% \x03(\x0b\x32\x1a.DaqConfig.InterfacesEntry\x12/\n\x0b\x66\x61il_module\x18/ \x03(\x0b\x32\x1a.DaqConfig.FailModuleEntry\x12\x1d\n\x15port_flap_timeout_sec\x18\x30 \x01(\x05\x1a=\n\x0fInterfacesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x19\n\x05value\x18\x02 \x01(\x0b\x32\n.Interface:\x02\x38\x01\x1a\x31\n\x0f\x46\x61ilModuleEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xe2\x01\n\x0bSwitchSetup\x12\x11\n\tctrl_intf\x18\t \x01(\t\x12\x0f\n\x07ip_addr\x18\x0b \x01(\t\x12\x13\n\x0buplink_port\x18\r \x01(\x05\x12\x0f\n\x07lo_port\x18\x0e \x01(\x05\x12\x0f\n\x07lo_addr\x18\x0f \x01(\t\x12\x11\n\tmods_addr\x18\x10 \x01(\t\x12\x0f\n\x07of_dpid\x18) \x01(\t\x12\x11\n\tdata_intf\x18* \x01(\t\x12\x0e\n\x06\x65xt_br\x18+ \x01(\t\x12\r\n\x05model\x18, \x01(\t\x12\x10\n\x08username\x18- \x01(\t\x12\x10\n\x08password\x18. \x01(\t\"\'\n\tInterface\x12\x0c\n\x04opts\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05\x62\x06proto3' + serialized_pb=_b('\n\x1d\x64\x61q/proto/system_config.proto\"\x99\x08\n\tDaqConfig\x12\x18\n\x10site_description\x18\x01 \x01(\t\x12\x18\n\x10monitor_scan_sec\x18\x02 \x01(\x05\x12\x1b\n\x13\x64\x65\x66\x61ult_timeout_sec\x18\x03 \x01(\x05\x12\x12\n\nsettle_sec\x18& \x01(\x05\x12\x11\n\tbase_conf\x18\x04 \x01(\t\x12\x11\n\tsite_path\x18\x05 \x01(\t\x12\x1f\n\x17initial_dhcp_lease_time\x18\x06 \x01(\t\x12\x17\n\x0f\x64hcp_lease_time\x18\x07 \x01(\t\x12\x19\n\x11\x64hcp_response_sec\x18\' \x01(\x05\x12\x1e\n\x16long_dhcp_response_sec\x18\x08 \x01(\x05\x12\"\n\x0cswitch_setup\x18\t \x01(\x0b\x32\x0c.SwitchSetup\x12\x12\n\nhost_tests\x18\x10 \x01(\t\x12\x13\n\x0b\x62uild_tests\x18$ \x01(\x08\x12\x11\n\trun_limit\x18\x11 \x01(\x05\x12\x11\n\tfail_mode\x18\x12 \x01(\x08\x12\x13\n\x0bsingle_shot\x18\" \x01(\x08\x12\x15\n\rresult_linger\x18\x13 \x01(\x08\x12\x0f\n\x07no_test\x18\x14 \x01(\x08\x12\x11\n\tkeep_hold\x18( \x01(\x08\x12\x14\n\x0c\x64\x61q_loglevel\x18\x15 \x01(\t\x12\x18\n\x10mininet_loglevel\x18\x16 \x01(\t\x12\x13\n\x0b\x66inish_hook\x18# \x01(\t\x12\x10\n\x08gcp_cred\x18\x17 \x01(\t\x12\x11\n\tgcp_topic\x18\x18 \x01(\t\x12\x13\n\x0bschema_path\x18\x19 \x01(\t\x12\x11\n\tmud_files\x18\x1a \x01(\t\x12\x14\n\x0c\x64\x65vice_specs\x18\x1b \x01(\t\x12\x13\n\x0btest_config\x18\x1c \x01(\t\x12\x19\n\x11port_debounce_sec\x18\x1d \x01(\x05\x12\x11\n\tfail_hook\x18\x1e \x01(\t\x12\x17\n\x0f\x64\x65vice_template\x18\x1f \x01(\t\x12\x14\n\x0csite_reports\x18 \x01(\t\x12\x1f\n\x17run_data_retention_days\x18! \x01(\x02\x12.\n\ninterfaces\x18% \x03(\x0b\x32\x1a.DaqConfig.InterfacesEntry\x12/\n\x0b\x66\x61il_module\x18/ \x03(\x0b\x32\x1a.DaqConfig.FailModuleEntry\x12\x1d\n\x15port_flap_timeout_sec\x18\x30 \x01(\x05\x12\x1c\n\tusi_setup\x18\x31 \x01(\x0b\x32\t.USISetup\x1a=\n\x0fInterfacesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x19\n\x05value\x18\x02 \x01(\x0b\x32\n.Interface:\x02\x38\x01\x1a\x31\n\x0f\x46\x61ilModuleEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x17\n\x08USISetup\x12\x0b\n\x03url\x18\x01 \x01(\t\"\xe2\x01\n\x0bSwitchSetup\x12\x11\n\tctrl_intf\x18\t \x01(\t\x12\x0f\n\x07ip_addr\x18\x0b \x01(\t\x12\x13\n\x0buplink_port\x18\r \x01(\x05\x12\x0f\n\x07lo_port\x18\x0e \x01(\x05\x12\x0f\n\x07lo_addr\x18\x0f \x01(\t\x12\x11\n\tmods_addr\x18\x10 \x01(\t\x12\x0f\n\x07of_dpid\x18) \x01(\t\x12\x11\n\tdata_intf\x18* \x01(\t\x12\x0e\n\x06\x65xt_br\x18+ \x01(\t\x12\r\n\x05model\x18, \x01(\t\x12\x10\n\x08username\x18- \x01(\t\x12\x10\n\x08password\x18. \x01(\t\"\'\n\tInterface\x12\x0c\n\x04opts\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05\x62\x06proto3') ) @@ -34,7 +35,7 @@ _descriptor.FieldDescriptor( name='key', full_name='DaqConfig.InterfacesEntry.key', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -51,14 +52,14 @@ nested_types=[], enum_types=[ ], - serialized_options=b'8\001', + serialized_options=_b('8\001'), is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=941, - serialized_end=1002, + serialized_start=971, + serialized_end=1032, ) _DAQCONFIG_FAILMODULEENTRY = _descriptor.Descriptor( @@ -71,14 +72,14 @@ _descriptor.FieldDescriptor( name='key', full_name='DaqConfig.FailModuleEntry.key', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='value', full_name='DaqConfig.FailModuleEntry.value', index=1, number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -88,14 +89,14 @@ nested_types=[], enum_types=[ ], - serialized_options=b'8\001', + serialized_options=_b('8\001'), is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=1004, - serialized_end=1053, + serialized_start=1034, + serialized_end=1083, ) _DAQCONFIG = _descriptor.Descriptor( @@ -108,7 +109,7 @@ _descriptor.FieldDescriptor( name='site_description', full_name='DaqConfig.site_description', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -136,28 +137,28 @@ _descriptor.FieldDescriptor( name='base_conf', full_name='DaqConfig.base_conf', index=4, number=4, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='site_path', full_name='DaqConfig.site_path', index=5, number=5, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='initial_dhcp_lease_time', full_name='DaqConfig.initial_dhcp_lease_time', index=6, number=6, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='dhcp_lease_time', full_name='DaqConfig.dhcp_lease_time', index=7, number=7, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -185,7 +186,7 @@ _descriptor.FieldDescriptor( name='host_tests', full_name='DaqConfig.host_tests', index=11, number=16, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -241,63 +242,63 @@ _descriptor.FieldDescriptor( name='daq_loglevel', full_name='DaqConfig.daq_loglevel', index=19, number=21, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='mininet_loglevel', full_name='DaqConfig.mininet_loglevel', index=20, number=22, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='finish_hook', full_name='DaqConfig.finish_hook', index=21, number=35, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='gcp_cred', full_name='DaqConfig.gcp_cred', index=22, number=23, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='gcp_topic', full_name='DaqConfig.gcp_topic', index=23, number=24, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='schema_path', full_name='DaqConfig.schema_path', index=24, number=25, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='mud_files', full_name='DaqConfig.mud_files', index=25, number=26, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='device_specs', full_name='DaqConfig.device_specs', index=26, number=27, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='test_config', full_name='DaqConfig.test_config', index=27, number=28, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -311,21 +312,21 @@ _descriptor.FieldDescriptor( name='fail_hook', full_name='DaqConfig.fail_hook', index=29, number=30, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='device_template', full_name='DaqConfig.device_template', index=30, number=31, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='site_reports', full_name='DaqConfig.site_reports', index=31, number=32, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -357,6 +358,13 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='usi_setup', full_name='DaqConfig.usi_setup', index=36, + number=49, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], @@ -370,7 +378,38 @@ oneofs=[ ], serialized_start=34, - serialized_end=1053, + serialized_end=1083, +) + + +_USISETUP = _descriptor.Descriptor( + name='USISetup', + full_name='USISetup', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='url', full_name='USISetup.url', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1085, + serialized_end=1108, ) @@ -384,14 +423,14 @@ _descriptor.FieldDescriptor( name='ctrl_intf', full_name='SwitchSetup.ctrl_intf', index=0, number=9, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='ip_addr', full_name='SwitchSetup.ip_addr', index=1, number=11, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -412,56 +451,56 @@ _descriptor.FieldDescriptor( name='lo_addr', full_name='SwitchSetup.lo_addr', index=4, number=15, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='mods_addr', full_name='SwitchSetup.mods_addr', index=5, number=16, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='of_dpid', full_name='SwitchSetup.of_dpid', index=6, number=41, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='data_intf', full_name='SwitchSetup.data_intf', index=7, number=42, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='ext_br', full_name='SwitchSetup.ext_br', index=8, number=43, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='model', full_name='SwitchSetup.model', index=9, number=44, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='username', full_name='SwitchSetup.username', index=10, number=45, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='password', full_name='SwitchSetup.password', index=11, number=46, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -477,8 +516,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1056, - serialized_end=1282, + serialized_start=1111, + serialized_end=1337, ) @@ -492,7 +531,7 @@ _descriptor.FieldDescriptor( name='opts', full_name='Interface.opts', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -515,8 +554,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1284, - serialized_end=1323, + serialized_start=1339, + serialized_end=1378, ) _DAQCONFIG_INTERFACESENTRY.fields_by_name['value'].message_type = _INTERFACE @@ -525,46 +564,55 @@ _DAQCONFIG.fields_by_name['switch_setup'].message_type = _SWITCHSETUP _DAQCONFIG.fields_by_name['interfaces'].message_type = _DAQCONFIG_INTERFACESENTRY _DAQCONFIG.fields_by_name['fail_module'].message_type = _DAQCONFIG_FAILMODULEENTRY +_DAQCONFIG.fields_by_name['usi_setup'].message_type = _USISETUP DESCRIPTOR.message_types_by_name['DaqConfig'] = _DAQCONFIG +DESCRIPTOR.message_types_by_name['USISetup'] = _USISETUP DESCRIPTOR.message_types_by_name['SwitchSetup'] = _SWITCHSETUP DESCRIPTOR.message_types_by_name['Interface'] = _INTERFACE _sym_db.RegisterFileDescriptor(DESCRIPTOR) -DaqConfig = _reflection.GeneratedProtocolMessageType('DaqConfig', (_message.Message,), { +DaqConfig = _reflection.GeneratedProtocolMessageType('DaqConfig', (_message.Message,), dict( - 'InterfacesEntry' : _reflection.GeneratedProtocolMessageType('InterfacesEntry', (_message.Message,), { - 'DESCRIPTOR' : _DAQCONFIG_INTERFACESENTRY, - '__module__' : 'daq.proto.system_config_pb2' + InterfacesEntry = _reflection.GeneratedProtocolMessageType('InterfacesEntry', (_message.Message,), dict( + DESCRIPTOR = _DAQCONFIG_INTERFACESENTRY, + __module__ = 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:DaqConfig.InterfacesEntry) - }) + )) , - 'FailModuleEntry' : _reflection.GeneratedProtocolMessageType('FailModuleEntry', (_message.Message,), { - 'DESCRIPTOR' : _DAQCONFIG_FAILMODULEENTRY, - '__module__' : 'daq.proto.system_config_pb2' + FailModuleEntry = _reflection.GeneratedProtocolMessageType('FailModuleEntry', (_message.Message,), dict( + DESCRIPTOR = _DAQCONFIG_FAILMODULEENTRY, + __module__ = 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:DaqConfig.FailModuleEntry) - }) + )) , - 'DESCRIPTOR' : _DAQCONFIG, - '__module__' : 'daq.proto.system_config_pb2' + DESCRIPTOR = _DAQCONFIG, + __module__ = 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:DaqConfig) - }) + )) _sym_db.RegisterMessage(DaqConfig) _sym_db.RegisterMessage(DaqConfig.InterfacesEntry) _sym_db.RegisterMessage(DaqConfig.FailModuleEntry) -SwitchSetup = _reflection.GeneratedProtocolMessageType('SwitchSetup', (_message.Message,), { - 'DESCRIPTOR' : _SWITCHSETUP, - '__module__' : 'daq.proto.system_config_pb2' +USISetup = _reflection.GeneratedProtocolMessageType('USISetup', (_message.Message,), dict( + DESCRIPTOR = _USISETUP, + __module__ = 'daq.proto.system_config_pb2' + # @@protoc_insertion_point(class_scope:USISetup) + )) +_sym_db.RegisterMessage(USISetup) + +SwitchSetup = _reflection.GeneratedProtocolMessageType('SwitchSetup', (_message.Message,), dict( + DESCRIPTOR = _SWITCHSETUP, + __module__ = 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:SwitchSetup) - }) + )) _sym_db.RegisterMessage(SwitchSetup) -Interface = _reflection.GeneratedProtocolMessageType('Interface', (_message.Message,), { - 'DESCRIPTOR' : _INTERFACE, - '__module__' : 'daq.proto.system_config_pb2' +Interface = _reflection.GeneratedProtocolMessageType('Interface', (_message.Message,), dict( + DESCRIPTOR = _INTERFACE, + __module__ = 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:Interface) - }) + )) _sym_db.RegisterMessage(Interface) diff --git a/libs/proto/usi_pb2.py b/libs/proto/usi_pb2.py new file mode 100644 index 0000000000..c9189dc119 --- /dev/null +++ b/libs/proto/usi_pb2.py @@ -0,0 +1,449 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: usi.proto + +from google.protobuf.internal import enum_type_wrapper +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='usi.proto', + package='usi', + syntax='proto3', + serialized_options=b'\n\004grpcB\010USIProtoP\001', + create_key=_descriptor._internal_create_key, + serialized_pb=b'\n\tusi.proto\x12\x03usi\"\'\n\x14SwitchActionResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\"\x9b\x01\n\rPowerResponse\x12!\n\x19\x63urrent_power_consumption\x18\x01 \x01(\x02\x12\x1d\n\x15max_power_consumption\x18\x02 \x01(\x02\x12$\n\x0bpoe_support\x18\x03 \x01(\x0e\x32\x0f.usi.POESupport\x12\"\n\npoe_status\x18\x04 \x01(\x0e\x32\x0e.usi.POEStatus\"]\n\x11InterfaceResponse\x12$\n\x0blink_status\x18\x01 \x01(\x0e\x32\x0f.usi.LinkStatus\x12\x12\n\nlink_speed\x18\x02 \x01(\x05\x12\x0e\n\x06\x64uplex\x18\x03 \x01(\t\"w\n\nSwitchInfo\x12\x0f\n\x07ip_addr\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65vice_port\x18\x03 \x01(\x05\x12\x1f\n\x05model\x18\x04 \x01(\x0e\x32\x10.usi.SwitchModel\x12\x10\n\x08username\x18\x05 \x01(\t\x12\x10\n\x08password\x18\x06 \x01(\t*F\n\x0bSwitchModel\x12\x17\n\x13\x41LLIED_TELESIS_X230\x10\x00\x12\x0e\n\nCISCO_9300\x10\x01\x12\x0e\n\nOVS_SWITCH\x10\x02*\x1e\n\nLinkStatus\x12\x06\n\x02UP\x10\x00\x12\x08\n\x04\x44OWN\x10\x01*\'\n\nPOESupport\x12\x0b\n\x07\x45NABLED\x10\x00\x12\x0c\n\x08\x44ISABLED\x10\x01*1\n\tPOEStatus\x12\x06\n\x02ON\x10\x00\x12\x07\n\x03OFF\x10\x01\x12\t\n\x05\x46\x41ULT\x10\x02\x12\x08\n\x04\x44\x45NY\x10\x03\x32\xef\x01\n\nUSIService\x12\x31\n\x08GetPower\x12\x0f.usi.SwitchInfo\x1a\x12.usi.PowerResponse\"\x00\x12\x39\n\x0cGetInterface\x12\x0f.usi.SwitchInfo\x1a\x16.usi.InterfaceResponse\"\x00\x12:\n\ndisconnect\x12\x0f.usi.SwitchInfo\x1a\x19.usi.SwitchActionResponse\"\x00\x12\x37\n\x07\x63onnect\x12\x0f.usi.SwitchInfo\x1a\x19.usi.SwitchActionResponse\"\x00\x42\x12\n\x04grpcB\x08USIProtoP\x01\x62\x06proto3' +) + +_SWITCHMODEL = _descriptor.EnumDescriptor( + name='SwitchModel', + full_name='usi.SwitchModel', + filename=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + values=[ + _descriptor.EnumValueDescriptor( + name='ALLIED_TELESIS_X230', index=0, number=0, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='CISCO_9300', index=1, number=1, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='OVS_SWITCH', index=2, number=2, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + ], + containing_type=None, + serialized_options=None, + serialized_start=433, + serialized_end=503, +) +_sym_db.RegisterEnumDescriptor(_SWITCHMODEL) + +SwitchModel = enum_type_wrapper.EnumTypeWrapper(_SWITCHMODEL) +_LINKSTATUS = _descriptor.EnumDescriptor( + name='LinkStatus', + full_name='usi.LinkStatus', + filename=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + values=[ + _descriptor.EnumValueDescriptor( + name='UP', index=0, number=0, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='DOWN', index=1, number=1, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + ], + containing_type=None, + serialized_options=None, + serialized_start=505, + serialized_end=535, +) +_sym_db.RegisterEnumDescriptor(_LINKSTATUS) + +LinkStatus = enum_type_wrapper.EnumTypeWrapper(_LINKSTATUS) +_POESUPPORT = _descriptor.EnumDescriptor( + name='POESupport', + full_name='usi.POESupport', + filename=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + values=[ + _descriptor.EnumValueDescriptor( + name='ENABLED', index=0, number=0, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='DISABLED', index=1, number=1, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + ], + containing_type=None, + serialized_options=None, + serialized_start=537, + serialized_end=576, +) +_sym_db.RegisterEnumDescriptor(_POESUPPORT) + +POESupport = enum_type_wrapper.EnumTypeWrapper(_POESUPPORT) +_POESTATUS = _descriptor.EnumDescriptor( + name='POEStatus', + full_name='usi.POEStatus', + filename=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + values=[ + _descriptor.EnumValueDescriptor( + name='ON', index=0, number=0, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='OFF', index=1, number=1, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='FAULT', index=2, number=2, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='DENY', index=3, number=3, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + ], + containing_type=None, + serialized_options=None, + serialized_start=578, + serialized_end=627, +) +_sym_db.RegisterEnumDescriptor(_POESTATUS) + +POEStatus = enum_type_wrapper.EnumTypeWrapper(_POESTATUS) +ALLIED_TELESIS_X230 = 0 +CISCO_9300 = 1 +OVS_SWITCH = 2 +UP = 0 +DOWN = 1 +ENABLED = 0 +DISABLED = 1 +ON = 0 +OFF = 1 +FAULT = 2 +DENY = 3 + + + +_SWITCHACTIONRESPONSE = _descriptor.Descriptor( + name='SwitchActionResponse', + full_name='usi.SwitchActionResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='success', full_name='usi.SwitchActionResponse.success', index=0, + number=1, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=18, + serialized_end=57, +) + + +_POWERRESPONSE = _descriptor.Descriptor( + name='PowerResponse', + full_name='usi.PowerResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='current_power_consumption', full_name='usi.PowerResponse.current_power_consumption', index=0, + number=1, type=2, cpp_type=6, label=1, + has_default_value=False, default_value=float(0), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='max_power_consumption', full_name='usi.PowerResponse.max_power_consumption', index=1, + number=2, type=2, cpp_type=6, label=1, + has_default_value=False, default_value=float(0), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='poe_support', full_name='usi.PowerResponse.poe_support', index=2, + number=3, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='poe_status', full_name='usi.PowerResponse.poe_status', index=3, + number=4, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=60, + serialized_end=215, +) + + +_INTERFACERESPONSE = _descriptor.Descriptor( + name='InterfaceResponse', + full_name='usi.InterfaceResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='link_status', full_name='usi.InterfaceResponse.link_status', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='link_speed', full_name='usi.InterfaceResponse.link_speed', index=1, + number=2, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='duplex', full_name='usi.InterfaceResponse.duplex', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=217, + serialized_end=310, +) + + +_SWITCHINFO = _descriptor.Descriptor( + name='SwitchInfo', + full_name='usi.SwitchInfo', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='ip_addr', full_name='usi.SwitchInfo.ip_addr', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='device_port', full_name='usi.SwitchInfo.device_port', index=1, + number=3, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='model', full_name='usi.SwitchInfo.model', index=2, + number=4, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='username', full_name='usi.SwitchInfo.username', index=3, + number=5, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='password', full_name='usi.SwitchInfo.password', index=4, + number=6, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=312, + serialized_end=431, +) + +_POWERRESPONSE.fields_by_name['poe_support'].enum_type = _POESUPPORT +_POWERRESPONSE.fields_by_name['poe_status'].enum_type = _POESTATUS +_INTERFACERESPONSE.fields_by_name['link_status'].enum_type = _LINKSTATUS +_SWITCHINFO.fields_by_name['model'].enum_type = _SWITCHMODEL +DESCRIPTOR.message_types_by_name['SwitchActionResponse'] = _SWITCHACTIONRESPONSE +DESCRIPTOR.message_types_by_name['PowerResponse'] = _POWERRESPONSE +DESCRIPTOR.message_types_by_name['InterfaceResponse'] = _INTERFACERESPONSE +DESCRIPTOR.message_types_by_name['SwitchInfo'] = _SWITCHINFO +DESCRIPTOR.enum_types_by_name['SwitchModel'] = _SWITCHMODEL +DESCRIPTOR.enum_types_by_name['LinkStatus'] = _LINKSTATUS +DESCRIPTOR.enum_types_by_name['POESupport'] = _POESUPPORT +DESCRIPTOR.enum_types_by_name['POEStatus'] = _POESTATUS +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +SwitchActionResponse = _reflection.GeneratedProtocolMessageType('SwitchActionResponse', (_message.Message,), { + 'DESCRIPTOR' : _SWITCHACTIONRESPONSE, + '__module__' : 'usi_pb2' + # @@protoc_insertion_point(class_scope:usi.SwitchActionResponse) + }) +_sym_db.RegisterMessage(SwitchActionResponse) + +PowerResponse = _reflection.GeneratedProtocolMessageType('PowerResponse', (_message.Message,), { + 'DESCRIPTOR' : _POWERRESPONSE, + '__module__' : 'usi_pb2' + # @@protoc_insertion_point(class_scope:usi.PowerResponse) + }) +_sym_db.RegisterMessage(PowerResponse) + +InterfaceResponse = _reflection.GeneratedProtocolMessageType('InterfaceResponse', (_message.Message,), { + 'DESCRIPTOR' : _INTERFACERESPONSE, + '__module__' : 'usi_pb2' + # @@protoc_insertion_point(class_scope:usi.InterfaceResponse) + }) +_sym_db.RegisterMessage(InterfaceResponse) + +SwitchInfo = _reflection.GeneratedProtocolMessageType('SwitchInfo', (_message.Message,), { + 'DESCRIPTOR' : _SWITCHINFO, + '__module__' : 'usi_pb2' + # @@protoc_insertion_point(class_scope:usi.SwitchInfo) + }) +_sym_db.RegisterMessage(SwitchInfo) + + +DESCRIPTOR._options = None + +_USISERVICE = _descriptor.ServiceDescriptor( + name='USIService', + full_name='usi.USIService', + file=DESCRIPTOR, + index=0, + serialized_options=None, + create_key=_descriptor._internal_create_key, + serialized_start=630, + serialized_end=869, + methods=[ + _descriptor.MethodDescriptor( + name='GetPower', + full_name='usi.USIService.GetPower', + index=0, + containing_service=None, + input_type=_SWITCHINFO, + output_type=_POWERRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name='GetInterface', + full_name='usi.USIService.GetInterface', + index=1, + containing_service=None, + input_type=_SWITCHINFO, + output_type=_INTERFACERESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name='disconnect', + full_name='usi.USIService.disconnect', + index=2, + containing_service=None, + input_type=_SWITCHINFO, + output_type=_SWITCHACTIONRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name='connect', + full_name='usi.USIService.connect', + index=3, + containing_service=None, + input_type=_SWITCHINFO, + output_type=_SWITCHACTIONRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), +]) +_sym_db.RegisterServiceDescriptor(_USISERVICE) + +DESCRIPTOR.services_by_name['USIService'] = _USISERVICE + +# @@protoc_insertion_point(module_scope) diff --git a/libs/proto/usi_pb2_grpc.py b/libs/proto/usi_pb2_grpc.py new file mode 100644 index 0000000000..c8e57501c9 --- /dev/null +++ b/libs/proto/usi_pb2_grpc.py @@ -0,0 +1,161 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc + +import usi_pb2 as usi__pb2 + + +class USIServiceStub(object): + """Missing associated documentation comment in .proto file.""" + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.GetPower = channel.unary_unary( + '/usi.USIService/GetPower', + request_serializer=usi__pb2.SwitchInfo.SerializeToString, + response_deserializer=usi__pb2.PowerResponse.FromString, + ) + self.GetInterface = channel.unary_unary( + '/usi.USIService/GetInterface', + request_serializer=usi__pb2.SwitchInfo.SerializeToString, + response_deserializer=usi__pb2.InterfaceResponse.FromString, + ) + self.disconnect = channel.unary_unary( + '/usi.USIService/disconnect', + request_serializer=usi__pb2.SwitchInfo.SerializeToString, + response_deserializer=usi__pb2.SwitchActionResponse.FromString, + ) + self.connect = channel.unary_unary( + '/usi.USIService/connect', + request_serializer=usi__pb2.SwitchInfo.SerializeToString, + response_deserializer=usi__pb2.SwitchActionResponse.FromString, + ) + + +class USIServiceServicer(object): + """Missing associated documentation comment in .proto file.""" + + def GetPower(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def GetInterface(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def disconnect(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def connect(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_USIServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'GetPower': grpc.unary_unary_rpc_method_handler( + servicer.GetPower, + request_deserializer=usi__pb2.SwitchInfo.FromString, + response_serializer=usi__pb2.PowerResponse.SerializeToString, + ), + 'GetInterface': grpc.unary_unary_rpc_method_handler( + servicer.GetInterface, + request_deserializer=usi__pb2.SwitchInfo.FromString, + response_serializer=usi__pb2.InterfaceResponse.SerializeToString, + ), + 'disconnect': grpc.unary_unary_rpc_method_handler( + servicer.disconnect, + request_deserializer=usi__pb2.SwitchInfo.FromString, + response_serializer=usi__pb2.SwitchActionResponse.SerializeToString, + ), + 'connect': grpc.unary_unary_rpc_method_handler( + servicer.connect, + request_deserializer=usi__pb2.SwitchInfo.FromString, + response_serializer=usi__pb2.SwitchActionResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'usi.USIService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + + + # This class is part of an EXPERIMENTAL API. +class USIService(object): + """Missing associated documentation comment in .proto file.""" + + @staticmethod + def GetPower(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/usi.USIService/GetPower', + usi__pb2.SwitchInfo.SerializeToString, + usi__pb2.PowerResponse.FromString, + options, channel_credentials, + call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def GetInterface(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/usi.USIService/GetInterface', + usi__pb2.SwitchInfo.SerializeToString, + usi__pb2.InterfaceResponse.FromString, + options, channel_credentials, + call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def disconnect(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/usi.USIService/disconnect', + usi__pb2.SwitchInfo.SerializeToString, + usi__pb2.SwitchActionResponse.FromString, + options, channel_credentials, + call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def connect(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/usi.USIService/connect', + usi__pb2.SwitchInfo.SerializeToString, + usi__pb2.SwitchActionResponse.FromString, + options, channel_credentials, + call_credentials, compression, wait_for_ready, timeout, metadata) diff --git a/proto/system_config.proto b/proto/system_config.proto index a0cbfbda48..1566620515 100644 --- a/proto/system_config.proto +++ b/proto/system_config.proto @@ -114,8 +114,17 @@ message DaqConfig { // Set time between port disconnect and host tests shutdown int32 port_flap_timeout_sec = 48; + + // USI url + USISetup usi_setup = 49; } +/** + * USI paramters +**/ +message USISetup { + string url = 1; +} /* * System configuraiton of the access switch. This is used by the system diff --git a/testing/run_unit_tests.sh b/testing/run_unit_tests.sh index b82892e384..a0705015a3 100755 --- a/testing/run_unit_tests.sh +++ b/testing/run_unit_tests.sh @@ -10,7 +10,7 @@ source venv/bin/activate coverage erase -export PYTHONPATH=$BASEDIR/daq:$BASEDIR/mininet:$BASEDIR/faucet:$BASEDIR/forch:$BASEDIR/bin/python +export PYTHONPATH=$BASEDIR/daq:$BASEDIR/mininet:$BASEDIR/faucet:$BASEDIR/forch:$BASEDIR/bin/python:$BASEDIR/libs:$BASEDIR/libs/proto coverage run \ --source $BASEDIR/daq,$BASEDIR/bin/python/ \ -m unittest discover \ diff --git a/usi/Dockerfile.usi b/usi/Dockerfile.usi index ba63658021..4fb6601310 100644 --- a/usi/Dockerfile.usi +++ b/usi/Dockerfile.usi @@ -1,9 +1,8 @@ FROM daqf/aardvark:latest # Do this alone first so it can be re-used by other build files. -RUN $AG update && $AG install openjdk-9-jre -RUN $AG update && $AG install openjdk-9-jdk git +RUN $AG update && $AG install openjdk-11-jdk git maven COPY usi/ usi/ diff --git a/usi/build.conf b/usi/build.conf new file mode 100644 index 0000000000..d469dd0503 --- /dev/null +++ b/usi/build.conf @@ -0,0 +1,2 @@ +build usi +add usi diff --git a/usi/src/main/java/daq/usi/UsiImpl.java b/usi/src/main/java/daq/usi/UsiImpl.java index 6cda498025..840bfe3e90 100644 --- a/usi/src/main/java/daq/usi/UsiImpl.java +++ b/usi/src/main/java/daq/usi/UsiImpl.java @@ -24,9 +24,8 @@ private SwitchController createController(SwitchInfo switchInfo) { SwitchController newController; switch (switchInfo.getModel()) { case ALLIED_TELESIS_X230: { - newController = - new AlliedTelesisX230(switchInfo.getIpAddr(), switchInfo.getUsername(), - switchInfo.getPassword()); + newController = new AlliedTelesisX230(switchInfo.getIpAddr(), switchInfo.getUsername(), + switchInfo.getPassword()); break; } case CISCO_9300: { @@ -39,16 +38,15 @@ private SwitchController createController(SwitchInfo switchInfo) { break; } default: - throw new IllegalArgumentException("Unrecognized switch model " - + switchInfo.getModel()); + throw new IllegalArgumentException("Unrecognized switch model " + switchInfo.getModel()); } newController.start(); return newController; } private SwitchController getSwitchController(SwitchInfo switchInfo) { - String repr = String.join(",", switchInfo.getModel().toString(), - switchInfo.getIpAddr(), switchInfo.getUsername(), + String repr = String.join(",", switchInfo.getModel().toString(), switchInfo.getIpAddr(), + switchInfo.getUsername(), switchInfo.getPassword()); return switchControllers.computeIfAbsent(repr, key -> createController(switchInfo)); } @@ -57,7 +55,10 @@ private SwitchController getSwitchController(SwitchInfo switchInfo) { public void getPower(SwitchInfo request, StreamObserver responseObserver) { SwitchController sc = getSwitchController(request); try { - sc.getPower(request.getDevicePort(), responseObserver::onNext); + sc.getPower(request.getDevicePort(), data -> { + responseObserver.onNext(data); + responseObserver.onCompleted(); + }); } catch (Exception e) { e.printStackTrace(); responseObserver.onError(e); @@ -65,11 +66,13 @@ public void getPower(SwitchInfo request, StreamObserver responseO } @Override - public void getInterface(SwitchInfo request, - StreamObserver responseObserver) { + public void getInterface(SwitchInfo request, StreamObserver responseObserver) { SwitchController sc = getSwitchController(request); try { - sc.getInterface(request.getDevicePort(), responseObserver::onNext); + sc.getInterface(request.getDevicePort(), data -> { + responseObserver.onNext(data); + responseObserver.onCompleted(); + }); } catch (Exception e) { e.printStackTrace(); responseObserver.onError(e); @@ -80,7 +83,10 @@ public void getInterface(SwitchInfo request, public void connect(SwitchInfo request, StreamObserver responseObserver) { SwitchController sc = getSwitchController(request); try { - sc.connect(request.getDevicePort(), responseObserver::onNext); + sc.connect(request.getDevicePort(), data -> { + responseObserver.onNext(data); + responseObserver.onCompleted(); + }); } catch (Exception e) { e.printStackTrace(); responseObserver.onError(e); @@ -92,10 +98,13 @@ public void disconnect(SwitchInfo request, StreamObserver responseObserver) { SwitchController sc = getSwitchController(request); try { - sc.disconnect(request.getDevicePort(), responseObserver::onNext); + sc.disconnect(request.getDevicePort(), data -> { + responseObserver.onNext(data); + responseObserver.onCompleted(); + }); } catch (Exception e) { e.printStackTrace(); responseObserver.onError(e); } } -} \ No newline at end of file +} diff --git a/usi/src/main/java/daq/usi/ovs/OpenVSwitch.java b/usi/src/main/java/daq/usi/ovs/OpenVSwitch.java index 691a04eeb5..ba38631e7e 100644 --- a/usi/src/main/java/daq/usi/ovs/OpenVSwitch.java +++ b/usi/src/main/java/daq/usi/ovs/OpenVSwitch.java @@ -11,7 +11,9 @@ import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; +import java.io.IOException; import java.net.URL; +import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -19,31 +21,29 @@ public class OpenVSwitch implements SwitchController { private static final String OVS_OUTPUT_FILE = "ovs_output.txt"; - protected String getInterfaceByPort(int devicePort) throws FileNotFoundException { + protected String getInterfaceByPort(int devicePort) throws IOException { URL file = OpenVSwitch.class.getClassLoader().getResource(OVS_OUTPUT_FILE); if (file == null) { throw new FileNotFoundException(OVS_OUTPUT_FILE + " is not found!"); } FileReader reader = new FileReader(file.getFile()); - BufferedReader bufferedReader = new BufferedReader(reader); - Pattern pattern = Pattern.compile("(^\\s*" + devicePort + ")(\\((.+)\\))(:.*)", 'g'); - String interfaceLine = bufferedReader.lines().filter(line -> { - Matcher m = pattern.matcher(line); - return m.find(); - }).findFirst().get(); - - Matcher m = pattern.matcher(interfaceLine); - m.matches(); - return m.group(3); + try (BufferedReader bufferedReader = new BufferedReader(reader)) { + Pattern pattern = Pattern.compile("(^\\s*" + devicePort + ")(\\((.+)\\))(:.*)", 'g'); + String interfaceLine = bufferedReader.lines().filter(line -> { + Matcher m = pattern.matcher(line); + return m.find(); + }).findFirst().get(); + Matcher m = pattern.matcher(interfaceLine); + m.matches(); + return m.group(3); + } } @Override public void getPower(int devicePort, ResponseHandler handler) throws Exception { PowerResponse.Builder response = PowerResponse.newBuilder(); - PowerResponse power = response.setPoeStatus(POEStatus.OFF) - .setPoeSupport(POESupport.DISABLED) - .setMaxPowerConsumption(0) - .setCurrentPowerConsumption(0).build(); + PowerResponse power = response.setPoeStatus(POEStatus.OFF).setPoeSupport(POESupport.DISABLED) + .setMaxPowerConsumption(0).setCurrentPowerConsumption(0).build(); handler.receiveData(power); } @@ -51,21 +51,23 @@ public void getPower(int devicePort, ResponseHandler handler) thr public void getInterface(int devicePort, ResponseHandler handler) throws Exception { InterfaceResponse.Builder response = InterfaceResponse.newBuilder(); - InterfaceResponse iface = response.setLinkStatus(LinkStatus.UP) - .setDuplex("") - .setLinkSpeed(0) - .build(); + InterfaceResponse iface = + response.setLinkStatus(LinkStatus.UP).setDuplex("").setLinkSpeed(0).build(); handler.receiveData(iface); } private void managePort(int devicePort, ResponseHandler handler, - boolean enabled) throws Exception { + boolean enabled) + throws Exception { String iface = getInterfaceByPort(devicePort); ProcessBuilder processBuilder = new ProcessBuilder(); - processBuilder.command("bash", "-c", "ifconfig " + iface + (enabled ? " up" : " down")); + processBuilder.command("bash", "-c", "ifconfig " + iface + (enabled ? " up" : " down")) + .inheritIO(); Process process = processBuilder.start(); - int exitCode = process.waitFor(); - handler.receiveData(SwitchActionResponse.newBuilder().setSuccess(exitCode == 0).build()); + boolean exited = process.waitFor(10, TimeUnit.SECONDS); + int exitCode = process.exitValue(); + handler + .receiveData(SwitchActionResponse.newBuilder().setSuccess(exited && exitCode == 0).build()); } @Override diff --git a/usi/start b/usi/start index 4c8350ff73..c3fc5e5b8a 100755 --- a/usi/start +++ b/usi/start @@ -1,2 +1,2 @@ #!/bin/bash -e -java -jar usi/target/usi-0.0.1-jar-with-dependencies.jar +java -cp /ovs:usi/target/usi-0.0.1-jar-with-dependencies.jar daq.usi.UsiServer From 9a95b36d648d1569287be3da1355eaa8a875241a Mon Sep 17 00:00:00 2001 From: pbatta Date: Fri, 10 Jul 2020 15:09:28 -0700 Subject: [PATCH 016/212] Update troubleshooting doc (#528) --- docs/troubleshooting.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 4a8fa1ba09..32e20582bd 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -9,7 +9,7 @@ mailing list, and use it as the primary source of troubleshooting. email somebody directly, but will likely result in a slower response time. * The `inst/cmdrun.log` file contains a copy of the console output from DAQ. * This file should be attached to communications about resolving DAQ issues. - * It's not necessary to include any assocaited `local/system.yaml` file, since the + * It's not necessary to include any associated `local/system.yaml` file, since the contents of that are already included. * Make sure everything is running properly using the internal simulation setup before tackling anything to do with external switches or physical devices. @@ -29,12 +29,15 @@ a summary of all test results. * The determination of _PASS_ vs. _FAIL_ is one of policy, not a technical consideration. If the question is "Is it OK if this tests fails or not?" then you need to contact whomever is responsible for policy, not DAQ-proper. - * The reports are _optionally_ available trough the _optionally_ configured + * The reports are _optionally_ available through the _optionally_ configured GCP instance, but that's only relevant after the basics are working. -* Capturing a complete zip of the `inst/` directory should encompass all the -state neesary to diagnose/debug problems, so simply captuing that and sending -it along would be sufficient in most cases. Be wary of file size, as `inst/` -can collect cruft over time and occasionally need to be cleaned. +* Running `bin/techsupport.sh` will create a zipped techsupport file that + contains all configuration, packet captures and runtime logs of a run. + Sending that file is sufficient in most cases. Be wary of file + size, as `inst/` might have large pcap files or older files that can be + trimmed to get more manageable file sizes for email attachments. +* Unless you are developing for DAQ and want the latest code, ensure that you + are on the latest stable software version tracked by the git tag `release_stable`. ## Test-Specific @@ -82,4 +85,4 @@ directory. * Filter results for the device's MAC address with something like: tcpdump -en -r testing.pacp ether host de:vi:ce:ma:ca:dr. * There is no one-size-fits-all guidance here, because what is expected is - extremeley test-specific. + extremely test-specific. From 02f1fee5f51ac2a93d9b9d7f5cbf52364ee1258b Mon Sep 17 00:00:00 2001 From: pbatta Date: Mon, 13 Jul 2020 11:33:32 -0700 Subject: [PATCH 017/212] Add troubleshooting script (#529) --- bin/troubleshoot | 29 +++++++++++++++++++++++++++++ docs/troubleshooting.md | 2 ++ 2 files changed, 31 insertions(+) create mode 100755 bin/troubleshoot diff --git a/bin/troubleshoot b/bin/troubleshoot new file mode 100755 index 0000000000..06b3432bd3 --- /dev/null +++ b/bin/troubleshoot @@ -0,0 +1,29 @@ +#!/bin/bash + +ROOT=$(realpath $(dirname $0)/..) +cd $ROOT + +if [ ! -d inst ]; then + echo "Error: run this script after a test run completes" + exit 1 +fi + +# After the system settles (early on some dpid=1 messages are expected) if we see +# unknown dpid in faucet log, dpid might be misconfigured +unknown_dpid=`fgrep 'unknown datapath' inst/faucet.log | wc -l` +if [ "$unknown_dpid" -gt 20 ]; then + echo "Error: Faucet reports unknown datapath DPID:" + fgrep 'unknown datapath' inst/faucet.log | tail -n1 + echo "Check if switch_setup:of_dpid in config matches the DPID on the physical switch" +else + echo "Checking DPID misconfig: ok" +fi + +# If the switch test failed with a monitoring timeout, switch login info could be wrong +switch_timeout=`fgrep 'Monitoring timeout for switch' inst/cmdrun.log` +if [ -n "$switch_timeout" ]; then + echo "Error: Timeout connecting to physical switch" + echo "Check switch username/password configuration" +else + echo "Checking Switch timeout: ok" +fi diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 32e20582bd..05aca2c9d6 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -38,6 +38,8 @@ a summary of all test results. trimmed to get more manageable file sizes for email attachments. * Unless you are developing for DAQ and want the latest code, ensure that you are on the latest stable software version tracked by the git tag `release_stable`. +* If a test run blocks or errors out, try running `bin/troubleshoot` to detect + some common misconfiguration and setup related issues. ## Test-Specific From ca5a7f6db66951f1287f5912eb5d66c78d8fa58f Mon Sep 17 00:00:00 2001 From: Trevor Date: Mon, 13 Jul 2020 11:33:54 -0700 Subject: [PATCH 018/212] Remove deprecated topology files (#530) --- bin/setup_testing | 63 ------------------------ topology/alta-dev/faucet.yaml | 92 ----------------------------------- topology/alta-dev/gauge.yaml | 14 ------ topology/normalize.sh | 12 ----- topology/setup.json | 69 -------------------------- 5 files changed, 250 deletions(-) delete mode 100755 bin/setup_testing delete mode 100644 topology/alta-dev/faucet.yaml delete mode 100644 topology/alta-dev/gauge.yaml delete mode 100755 topology/normalize.sh delete mode 100644 topology/setup.json diff --git a/bin/setup_testing b/bin/setup_testing deleted file mode 100755 index f5e73ca8b1..0000000000 --- a/bin/setup_testing +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/bash -e - -ROOT=$(dirname $0)/.. -cd $ROOT - -bin/build_hash check - -TARGET_ROOT=inst/faucet/daq-faucet-faucet - -for postfix in 1 2; do - TARGET=${TARGET_ROOT}$postfix - echo Preparing $TARGET - sudo rm -rf $TARGET && mkdir -p $TARGET - cp topology/alta-dev/faucet.yaml $TARGET/faucet.yaml - cp topology/alta-dev/gauge.yaml $TARGET/gauge.yaml -done - -cmd/faucet faucet1 6655 -cmd/faucet gauge faucet1 6656 9306 -cmd/faucet faucet2 6657 -cmd/faucet gauge faucet2 6658 9308 - -sudo ip addr flush ganga -sudo ip addr add 192.0.2.10/24 dev ganga - -sudo ovs-vsctl --if-exists del-br upstream -- add-br upstream -sudo ip link del daqnw || true -sudo ip link add daqnw type veth peer name t1bond -sudo ip link set daqnw up -sudo ip link set t1bond up -sudo ovs-vsctl add-port upstream daqnw - -sudo ip link del up_bond || true -sudo ip link add up_bond type bond mode 802.3ad lacp_rate fast -sudo ip link set up_bond up -sudo ip link set yamuna down -sudo ip link set yamuna master up_bond -sudo ip link set beas down -sudo ip link set beas master up_bond -sudo ovs-vsctl add-port upstream up_bond - -cmd/faux -n :t1bond -cmd/faux :satlej -cmd/faux :ravi -cmd/faux :tapti - -echo -docker exec daq-networking-t1bond ip addr -echo Waiting for DHCP... -sleep 30 -echo -docker exec daq-faux-satlej ip addr show dev satlej -echo -docker exec daq-faux-ravi ip addr show dev ravi -echo -docker exec daq-faux-tapti ip addr show dev tapti -echo -docker exec daq-faux-satlej ping -c 3 google.com -docker exec daq-faux-ravi ping -c 3 google.com -docker exec daq-faux-tapti ping -c 3 google.com -docker exec daq-faux-satlej ping -c 3 daq-faux-tapti -echo -echo Done with testing setup. diff --git a/topology/alta-dev/faucet.yaml b/topology/alta-dev/faucet.yaml deleted file mode 100644 index 0dcd804b7e..0000000000 --- a/topology/alta-dev/faucet.yaml +++ /dev/null @@ -1,92 +0,0 @@ -dps: - us-mtv-900-t1sw2-0-1: - dp_id: 147058200621 - faucet_dp_mac: 0e:00:00:00:01:01 - hardware: GenericTFM - interfaces: - 9: - lldp_beacon: {enable: true} - lldp_peer_mac: 0e:00:00:00:02:01 - tagged_vlans: [171] - receive_lldp: true - 10: - lldp_beacon: {enable: true} - lldp_peer_mac: 0e:00:00:00:02:02 - tagged_vlans: [171] - receive_lldp: true - 28: - description: Juniper-Uplink-1 - lacp: 3 - lacp_passthrough: [9, 10] - lldp_beacon: {enable: true} - native_vlan: 171 - receive_lldp: true - lldp_beacon: {max_per_interval: 5, send_interval: 5} - use_hard_timeout: true - us-mtv-900-t1sw2-0-2: - dp_id: 147058200561 - faucet_dp_mac: 0e:00:00:00:01:02 - hardware: GenericTFM - interfaces: - 9: - lldp_beacon: {enable: true} - lldp_peer_mac: 0e:00:00:00:02:01 - tagged_vlans: [171] - receive_lldp: true - 10: - lldp_beacon: {enable: true} - lldp_peer_mac: 0e:00:00:00:02:02 - tagged_vlans: [171] - receive_lldp: true - 28: - description: Juniper-Uplink-2 - lacp: 3 - lacp_passthrough: [9, 10] - lldp_beacon: {enable: true} - native_vlan: 171 - receive_lldp: true - lldp_beacon: {max_per_interval: 5, send_interval: 5} - use_hard_timeout: true - us-mtv-900-t2sw2-0-1: - dp_id: 246406200719452 - faucet_dp_mac: 0e:00:00:00:02:01 - hardware: Allied-Telesis - interface_ranges: - 1-46: {description: IoT Host, native_vlan: 171} - interfaces: - 47: - lldp_beacon: {enable: true} - lldp_failover: 48 - loop_protect_external: true - tagged_vlans: [171] - receive_lldp: true - 48: - lldp_beacon: {enable: true} - loop_protect_external: true - tagged_vlans: [171] - receive_lldp: true - lldp_beacon: {max_per_interval: 5, send_interval: 5} - use_hard_timeout: true - us-mtv-900-t2sw2-0-2: - dp_id: 246406200719346 - faucet_dp_mac: 0e:00:00:00:02:02 - hardware: Allied-Telesis - interface_ranges: - 1-46: {description: IoT Host, native_vlan: 171} - interfaces: - 47: - lldp_beacon: {enable: true} - loop_protect_external: true - tagged_vlans: [171] - receive_lldp: true - 48: - lldp_beacon: {enable: true} - lldp_failover: 47 - loop_protect_external: true - tagged_vlans: [171] - receive_lldp: true - lldp_beacon: {max_per_interval: 5, send_interval: 5} - use_hard_timeout: true -version: 2 -vlans: - 171: {description: BOS-IOT} diff --git a/topology/alta-dev/gauge.yaml b/topology/alta-dev/gauge.yaml deleted file mode 100644 index bf0f0e0f1e..0000000000 --- a/topology/alta-dev/gauge.yaml +++ /dev/null @@ -1,14 +0,0 @@ -dbs: - prometheus: {prometheus_addr: 0.0.0.0, prometheus_port: 9303, type: prometheus} -faucet_configs: [/etc/faucet/faucet.yaml] -watchers: - flow_table: - db: prometheus - dps: [us-mtv-900-t1sw2-0-1, us-mtv-900-t2sw2-0-1, us-mtv-900-t1sw2-0-2, us-mtv-900-t2sw2-0-2] - interval: 10 - type: flow_table - port_stats: - db: prometheus - dps: [us-mtv-900-t1sw2-0-1, us-mtv-900-t2sw2-0-1, us-mtv-900-t1sw2-0-2, us-mtv-900-t2sw2-0-2] - interval: 10 - type: port_stats diff --git a/topology/normalize.sh b/topology/normalize.sh deleted file mode 100755 index 71fb4da312..0000000000 --- a/topology/normalize.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -e - -ROOT=$(dirname $0)/.. -if [ ! -d "$1" ]; then - echo $0 [topology dir] - false -fi - -TDIR=$(realpath $1) - -$ROOT/bin/generate_topology raw_topo=$TDIR topo_dir=$TDIR - diff --git a/topology/setup.json b/topology/setup.json deleted file mode 100644 index 7206b7cfdf..0000000000 --- a/topology/setup.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - 'faucet_yaml': '/etc/faucet/faucet.yaml', - 'faucet_dp_mac_format': '0e:00:00:00:%02x:%02x', - 'lacp_timeout': 5, - 'default_hardware': 'GenericTFM', - 'egress_description': 'egress', - 'combinatorial_port_flood': true, - 'naming': { - 'tier1': '-t1sw', - 'tier2': '-t2sw', - 'control': '-ctr' - }, - 'device_description': 'IoT Device', - 'vlan': { - 'description': 'Faucet IoT', - 'name': 'Faucet_IoT' - }, - 'gauge': { - 'db_type': 'prometheus', - 'interval': 10 - }, - 'db_types': { - 'prometheus': { - 'prometheus_addr': '0.0.0.0', - 'prometheus_port': 9303, - 'type': 'prometheus' - } - }, - 'receive_lldp': true, - 'switch_lldp_beacon': { - 'max_per_interval': 5, - 'send_interval': 5 - }, - 'port_lldp_beacon': { - 'enable': true - }, - 'loop_protect_external': true, - "pre_acls": [ - { - "description": "ICMP Allow", - "nw_proto": 1 - }, - { - "description": "ARP Allow", - "dl_type": "0x0806" - }, - { - "description": "DHCP Allow", - "udp_src": 68, - "udp_dst": 67 - }, - { - "description": "DNS Allow", - "udp_dst": 53 - }, - { - "description": "DHCP Broadcast", - "dl_dst": "ff:ff:ff:ff:ff:ff", - "udp_src": 68, - "udp_dst": 67 - } - ], - "post_acls": [ - { - "description": "Default Deny", - "allow": false - } - ] -} From 2361f80e4b53516af21fc06d70dd1cf5a31ca30c Mon Sep 17 00:00:00 2001 From: Trevor Date: Mon, 13 Jul 2020 16:01:05 -0700 Subject: [PATCH 019/212] Support for alternate sec switch (not managed by DAQ) (#531) --- .gitignore | 18 ++-- bin/alt_faucet | 24 +++++ bin/build_proto | 7 +- bin/external_ovs | 9 +- cmd/exrun | 6 +- config/faucet/faucet_alt-switch.yaml | 22 ++++ config/system/all.conf | 2 +- config/system/alt.yaml | 20 ++++ config/system/ext.conf | 2 +- config/system/ext.yaml | 2 +- config/system/muddy.conf | 2 +- config/system/multi.conf | 2 +- daq/topology.py | 8 +- firebase/public/protos.hash | 2 +- firebase/public/protos.html | 9 +- libs/proto/system_config_pb2.py | 156 ++++++++++++++------------- proto/system_config.proto | 9 +- testing/test_base.out | 2 + testing/test_base.sh | 5 + testing/test_preamble.sh | 1 + 20 files changed, 206 insertions(+), 102 deletions(-) create mode 100755 bin/alt_faucet create mode 100644 config/faucet/faucet_alt-switch.yaml create mode 100644 config/system/alt.yaml diff --git a/.gitignore b/.gitignore index ada16ef8f5..5e280a7725 100644 --- a/.gitignore +++ b/.gitignore @@ -21,16 +21,14 @@ validations/ *.save # Runtime or sub-module files -inst/ -faucet/ -forch/ -mininet/ -local/ -local_xxx -local.old -firebase/.firebaserc -firebase/.firebase -firebase/functions/package-lock.json +/inst/ +/faucet/ +/forch/ +/mininet/ +/local/ +/firebase/.firebaserc +/firebase/.firebase +/firebase/functions/package-lock.json nohup.out **/node_modules/ .vscode/ diff --git a/bin/alt_faucet b/bin/alt_faucet new file mode 100755 index 0000000000..757ad64218 --- /dev/null +++ b/bin/alt_faucet @@ -0,0 +1,24 @@ +#!/bin/bash -e + +ROOT=$(realpath $(dirname $0)/..) +cd $ROOT +source etc/config_base.sh + +if [ -z "$switch_setup_ext_br" ]; then + echo switch_setup.ext_br not defined for alternate faucet setup. + false +fi + +if [ -z "$switch_setup_alt_port" ]; then + echo switch_setup.alt_port not defined for alternate faucet setup. + false +fi + +inst_name=$switch_setup_ext_br + +inst_dir=inst/faucet/daq-faucet-$inst_name +mkdir -p $inst_dir +cp config/faucet/faucet_$inst_name.yaml $inst_dir/faucet.yaml +echo Launching alternate faucet install $inst_name on $switch_setup_alt_port +echo DAQ autoclean docker kill daq-faucet-$inst_name +cmd/faucet $inst_name $switch_setup_alt_port diff --git a/bin/build_proto b/bin/build_proto index b0886e5d86..cd20e074ef 100755 --- a/bin/build_proto +++ b/bin/build_proto @@ -32,6 +32,11 @@ sha1sum $proto_files > $WEB_ROOT/protos.hash gen_path=$ROOT/protoc-gen-doc/bin/protoc-gen-doc +if [ -d venv ]; then + echo Entering virtual python environment... + source venv/bin/activate +fi + mkdir -p build/daq/proto build/proto cp $proto_files build/daq/proto/ proto_files2= @@ -57,4 +62,4 @@ touch libs/proto/__init__.py cp build/daq/proto/*.py libs/proto/ cp build/protos.html $WEB_ROOT/ -python -m grpc_tools.protoc -I usi/src/main/proto/ --python_out=libs/proto/ --grpc_python_out=libs/proto/ usi/src/main/proto/usi.proto +python3 -m grpc_tools.protoc -I usi/src/main/proto/ --python_out=libs/proto/ --grpc_python_out=libs/proto/ usi/src/main/proto/usi.proto diff --git a/bin/external_ovs b/bin/external_ovs index a289bd9cff..080fdcdecb 100755 --- a/bin/external_ovs +++ b/bin/external_ovs @@ -6,14 +6,19 @@ source etc/config_base.sh ext_intf=$switch_setup_data_intf ext_dpid=$switch_setup_of_dpid -ext_ofpt=$switch_setup_lo_port ext_brid=$switch_setup_ext_br ext_brpt=$switch_setup_uplink_port ext_pri=${ext_intf} ext_sec=${ext_intf%-pri}-sec -echo ext_dpid is $ext_dpid +if [ -z "$switch_setup_alt_port" ]; then + ext_ofpt=$switch_setup_lo_port +else + ext_ofpt=$switch_setup_alt_port +fi + +echo ext_dpid is $ext_dpid on port $ext_ofpt echo network_config is $network_config dpid=$(printf %016x $ext_dpid) diff --git a/cmd/exrun b/cmd/exrun index 88a047994b..da511d373f 100755 --- a/cmd/exrun +++ b/cmd/exrun @@ -70,7 +70,7 @@ fi export PYTHONPATH=$FORCH:$FAUCET:$MININET:$LIBS:$PROTO mkdir -p $INSTDIR -rm -f $INSTDIR/faucet* $cleanup_file +rm -rf $INSTDIR/faucet* $cleanup_file docker ps > /dev/null 2>&1 || service docker start @@ -101,6 +101,10 @@ if [ -n "$switch_setup_ext_br" ]; then autostart bin/external_ovs fi +if [ -n "$switch_setup_alt_port" ]; then + autostart bin/alt_faucet +fi + if [ -n "$switch_setup_model" ]; then autostart bin/physical_sec else diff --git a/config/faucet/faucet_alt-switch.yaml b/config/faucet/faucet_alt-switch.yaml new file mode 100644 index 0000000000..876cf786fd --- /dev/null +++ b/config/faucet/faucet_alt-switch.yaml @@ -0,0 +1,22 @@ +dps: + alt-switch: + dp_id: 2 + interfaces: + 1: + native_vlan: 1001 + 2: + native_vlan: 1002 + 3: + native_vlan: 1003 + 4: + native_vlan: 1004 + 5: + native_vlan: 1005 + 100: + tagged_vlans: [1001, 1002, 1003, 1004, 1005] +vlans: + 1001: + 1002: + 1003: + 1004: + 1005: diff --git a/config/system/all.conf b/config/system/all.conf index 0fe77da8fb..612cdc89cb 100644 --- a/config/system/all.conf +++ b/config/system/all.conf @@ -3,7 +3,7 @@ # Load defaults. source config/system/default.yaml -# Description description for dashboard. +# Description for dashboard. site_description="Multi-Device All-Tests Configuration" # Upstream dataplane port from the external (secondary) switch. diff --git a/config/system/alt.yaml b/config/system/alt.yaml new file mode 100644 index 0000000000..e429326c7f --- /dev/null +++ b/config/system/alt.yaml @@ -0,0 +1,20 @@ +# Example configuration file for using an OVS switch not managed by DAQ. + +# Load defaults. +include: config/system/default.yaml + +# Description for dashboard. +site_description: "Alternate (not managed by DAQ) OVS switch configuration" + +# Network switch configuration. +switch_setup: + data_intf: alt-intf + alt_port: 6669 + uplink_port: 100 + ext_br: alt-switch + +# Faux device connection for testing. +interfaces: + faux: + opts: + port: 2 diff --git a/config/system/ext.conf b/config/system/ext.conf index 8625109734..28dc34b707 100644 --- a/config/system/ext.conf +++ b/config/system/ext.conf @@ -3,7 +3,7 @@ # Load defaults. source config/system/default.yaml -# Description description for dashboard. +# Description for dashboard. site_description="External (not integrated with DAQ) OVS switch configuration" # Network switch configuration. diff --git a/config/system/ext.yaml b/config/system/ext.yaml index 7ad626341e..4fef079c1e 100644 --- a/config/system/ext.yaml +++ b/config/system/ext.yaml @@ -3,7 +3,7 @@ # Load defaults. include: config/system/default.yaml -# Description description for dashboard. +# Description for dashboard. site_description: "External (not integrated with DAQ) OVS switch configuration" # Network switch configuration. diff --git a/config/system/muddy.conf b/config/system/muddy.conf index 6510e2b113..3d3a17b30c 100644 --- a/config/system/muddy.conf +++ b/config/system/muddy.conf @@ -3,7 +3,7 @@ # Load defaults. source config/system/default.yaml -# Description description for dashboard. +# Description for dashboard. site_description="Multi-Device Configuration" # Upstream dataplane port from the external (secondary) switch. diff --git a/config/system/multi.conf b/config/system/multi.conf index 185bbc40df..367a94e86b 100644 --- a/config/system/multi.conf +++ b/config/system/multi.conf @@ -3,7 +3,7 @@ # Load defaults. source config/system/default.yaml -# Description description for dashboard. +# Description for dashboard. site_description="Multi-Device Configuration" # Upstream dataplane port from the external (secondary) switch. diff --git a/daq/topology.py b/daq/topology.py index 8d0cb62390..2cda43ebe4 100644 --- a/daq/topology.py +++ b/daq/topology.py @@ -231,22 +231,24 @@ def _make_acl_include(self): def _make_pri_topology(self): pri_dp = {} pri_dp['dp_id'] = self.PRI_DPID - pri_dp['name'] = self.pri_name pri_dp['interfaces'] = self._make_pri_interfaces() return pri_dp def _make_sec_topology(self): sec_dp = {} sec_dp['dp_id'] = self.sec_dpid - sec_dp['name'] = self.sec_name sec_dp['interfaces'] = self._make_sec_interfaces() return sec_dp + def _has_sec_switch(self): + return self.sec_dpid and self.sec_port + def _make_base_network_topology(self): assert self.pri, 'pri dataplane not configured' dps = {} dps['pri'] = self._make_pri_topology() - dps['sec'] = self._make_sec_topology() + if self._has_sec_switch(): + dps['sec'] = self._make_sec_topology() topology = {} topology['dps'] = dps topology['vlans'] = self._make_vlan_description(10) diff --git a/firebase/public/protos.hash b/firebase/public/protos.hash index 3873f3c004..786633c8a9 100644 --- a/firebase/public/protos.hash +++ b/firebase/public/protos.hash @@ -1 +1 @@ -96148b4135bc7326586f96fc38a18beeca8147c4 proto/system_config.proto +b335b4bd73bb5242e822a9b72cf4de6bd010cea3 proto/system_config.proto diff --git a/firebase/public/protos.html b/firebase/public/protos.html index cfcb14e33d..13290969b0 100644 --- a/firebase/public/protos.html +++ b/firebase/public/protos.html @@ -624,7 +624,14 @@

    SwitchSetup

    lo_port int32 -

    Local port of open flow controller

    +

    Local port of DAQ OpenFlow controller

    + + + + alt_port + int32 + +

    Local port for an alternate OpenFlow controller

    diff --git a/libs/proto/system_config_pb2.py b/libs/proto/system_config_pb2.py index e110d5eade..d82945d1c4 100644 --- a/libs/proto/system_config_pb2.py +++ b/libs/proto/system_config_pb2.py @@ -1,8 +1,7 @@ +# -*- coding: utf-8 -*- # Generated by the protocol buffer compiler. DO NOT EDIT! # source: daq/proto/system_config.proto -import sys -_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection @@ -19,7 +18,7 @@ package='', syntax='proto3', serialized_options=None, - serialized_pb=_b('\n\x1d\x64\x61q/proto/system_config.proto\"\x99\x08\n\tDaqConfig\x12\x18\n\x10site_description\x18\x01 \x01(\t\x12\x18\n\x10monitor_scan_sec\x18\x02 \x01(\x05\x12\x1b\n\x13\x64\x65\x66\x61ult_timeout_sec\x18\x03 \x01(\x05\x12\x12\n\nsettle_sec\x18& \x01(\x05\x12\x11\n\tbase_conf\x18\x04 \x01(\t\x12\x11\n\tsite_path\x18\x05 \x01(\t\x12\x1f\n\x17initial_dhcp_lease_time\x18\x06 \x01(\t\x12\x17\n\x0f\x64hcp_lease_time\x18\x07 \x01(\t\x12\x19\n\x11\x64hcp_response_sec\x18\' \x01(\x05\x12\x1e\n\x16long_dhcp_response_sec\x18\x08 \x01(\x05\x12\"\n\x0cswitch_setup\x18\t \x01(\x0b\x32\x0c.SwitchSetup\x12\x12\n\nhost_tests\x18\x10 \x01(\t\x12\x13\n\x0b\x62uild_tests\x18$ \x01(\x08\x12\x11\n\trun_limit\x18\x11 \x01(\x05\x12\x11\n\tfail_mode\x18\x12 \x01(\x08\x12\x13\n\x0bsingle_shot\x18\" \x01(\x08\x12\x15\n\rresult_linger\x18\x13 \x01(\x08\x12\x0f\n\x07no_test\x18\x14 \x01(\x08\x12\x11\n\tkeep_hold\x18( \x01(\x08\x12\x14\n\x0c\x64\x61q_loglevel\x18\x15 \x01(\t\x12\x18\n\x10mininet_loglevel\x18\x16 \x01(\t\x12\x13\n\x0b\x66inish_hook\x18# \x01(\t\x12\x10\n\x08gcp_cred\x18\x17 \x01(\t\x12\x11\n\tgcp_topic\x18\x18 \x01(\t\x12\x13\n\x0bschema_path\x18\x19 \x01(\t\x12\x11\n\tmud_files\x18\x1a \x01(\t\x12\x14\n\x0c\x64\x65vice_specs\x18\x1b \x01(\t\x12\x13\n\x0btest_config\x18\x1c \x01(\t\x12\x19\n\x11port_debounce_sec\x18\x1d \x01(\x05\x12\x11\n\tfail_hook\x18\x1e \x01(\t\x12\x17\n\x0f\x64\x65vice_template\x18\x1f \x01(\t\x12\x14\n\x0csite_reports\x18 \x01(\t\x12\x1f\n\x17run_data_retention_days\x18! \x01(\x02\x12.\n\ninterfaces\x18% \x03(\x0b\x32\x1a.DaqConfig.InterfacesEntry\x12/\n\x0b\x66\x61il_module\x18/ \x03(\x0b\x32\x1a.DaqConfig.FailModuleEntry\x12\x1d\n\x15port_flap_timeout_sec\x18\x30 \x01(\x05\x12\x1c\n\tusi_setup\x18\x31 \x01(\x0b\x32\t.USISetup\x1a=\n\x0fInterfacesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x19\n\x05value\x18\x02 \x01(\x0b\x32\n.Interface:\x02\x38\x01\x1a\x31\n\x0f\x46\x61ilModuleEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x17\n\x08USISetup\x12\x0b\n\x03url\x18\x01 \x01(\t\"\xe2\x01\n\x0bSwitchSetup\x12\x11\n\tctrl_intf\x18\t \x01(\t\x12\x0f\n\x07ip_addr\x18\x0b \x01(\t\x12\x13\n\x0buplink_port\x18\r \x01(\x05\x12\x0f\n\x07lo_port\x18\x0e \x01(\x05\x12\x0f\n\x07lo_addr\x18\x0f \x01(\t\x12\x11\n\tmods_addr\x18\x10 \x01(\t\x12\x0f\n\x07of_dpid\x18) \x01(\t\x12\x11\n\tdata_intf\x18* \x01(\t\x12\x0e\n\x06\x65xt_br\x18+ \x01(\t\x12\r\n\x05model\x18, \x01(\t\x12\x10\n\x08username\x18- \x01(\t\x12\x10\n\x08password\x18. \x01(\t\"\'\n\tInterface\x12\x0c\n\x04opts\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05\x62\x06proto3') + serialized_pb=b'\n\x1d\x64\x61q/proto/system_config.proto\"\x99\x08\n\tDaqConfig\x12\x18\n\x10site_description\x18\x01 \x01(\t\x12\x18\n\x10monitor_scan_sec\x18\x02 \x01(\x05\x12\x1b\n\x13\x64\x65\x66\x61ult_timeout_sec\x18\x03 \x01(\x05\x12\x12\n\nsettle_sec\x18& \x01(\x05\x12\x11\n\tbase_conf\x18\x04 \x01(\t\x12\x11\n\tsite_path\x18\x05 \x01(\t\x12\x1f\n\x17initial_dhcp_lease_time\x18\x06 \x01(\t\x12\x17\n\x0f\x64hcp_lease_time\x18\x07 \x01(\t\x12\x19\n\x11\x64hcp_response_sec\x18\' \x01(\x05\x12\x1e\n\x16long_dhcp_response_sec\x18\x08 \x01(\x05\x12\"\n\x0cswitch_setup\x18\t \x01(\x0b\x32\x0c.SwitchSetup\x12\x12\n\nhost_tests\x18\x10 \x01(\t\x12\x13\n\x0b\x62uild_tests\x18$ \x01(\x08\x12\x11\n\trun_limit\x18\x11 \x01(\x05\x12\x11\n\tfail_mode\x18\x12 \x01(\x08\x12\x13\n\x0bsingle_shot\x18\" \x01(\x08\x12\x15\n\rresult_linger\x18\x13 \x01(\x08\x12\x0f\n\x07no_test\x18\x14 \x01(\x08\x12\x11\n\tkeep_hold\x18( \x01(\x08\x12\x14\n\x0c\x64\x61q_loglevel\x18\x15 \x01(\t\x12\x18\n\x10mininet_loglevel\x18\x16 \x01(\t\x12\x13\n\x0b\x66inish_hook\x18# \x01(\t\x12\x10\n\x08gcp_cred\x18\x17 \x01(\t\x12\x11\n\tgcp_topic\x18\x18 \x01(\t\x12\x13\n\x0bschema_path\x18\x19 \x01(\t\x12\x11\n\tmud_files\x18\x1a \x01(\t\x12\x14\n\x0c\x64\x65vice_specs\x18\x1b \x01(\t\x12\x13\n\x0btest_config\x18\x1c \x01(\t\x12\x19\n\x11port_debounce_sec\x18\x1d \x01(\x05\x12\x11\n\tfail_hook\x18\x1e \x01(\t\x12\x17\n\x0f\x64\x65vice_template\x18\x1f \x01(\t\x12\x14\n\x0csite_reports\x18 \x01(\t\x12\x1f\n\x17run_data_retention_days\x18! \x01(\x02\x12.\n\ninterfaces\x18% \x03(\x0b\x32\x1a.DaqConfig.InterfacesEntry\x12/\n\x0b\x66\x61il_module\x18/ \x03(\x0b\x32\x1a.DaqConfig.FailModuleEntry\x12\x1d\n\x15port_flap_timeout_sec\x18\x30 \x01(\x05\x12\x1c\n\tusi_setup\x18\x31 \x01(\x0b\x32\t.USISetup\x1a=\n\x0fInterfacesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x19\n\x05value\x18\x02 \x01(\x0b\x32\n.Interface:\x02\x38\x01\x1a\x31\n\x0f\x46\x61ilModuleEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x17\n\x08USISetup\x12\x0b\n\x03url\x18\x01 \x01(\t\"\xf4\x01\n\x0bSwitchSetup\x12\x11\n\tctrl_intf\x18\t \x01(\t\x12\x0f\n\x07ip_addr\x18\x0b \x01(\t\x12\x13\n\x0buplink_port\x18\r \x01(\x05\x12\x0f\n\x07lo_port\x18\x0e \x01(\x05\x12\x10\n\x08\x61lt_port\x18\x10 \x01(\x05\x12\x0f\n\x07lo_addr\x18\x12 \x01(\t\x12\x11\n\tmods_addr\x18\x14 \x01(\t\x12\x0f\n\x07of_dpid\x18) \x01(\t\x12\x11\n\tdata_intf\x18* \x01(\t\x12\x0e\n\x06\x65xt_br\x18+ \x01(\t\x12\r\n\x05model\x18, \x01(\t\x12\x10\n\x08username\x18- \x01(\t\x12\x10\n\x08password\x18. \x01(\t\"\'\n\tInterface\x12\x0c\n\x04opts\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05\x62\x06proto3' ) @@ -35,7 +34,7 @@ _descriptor.FieldDescriptor( name='key', full_name='DaqConfig.InterfacesEntry.key', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -52,7 +51,7 @@ nested_types=[], enum_types=[ ], - serialized_options=_b('8\001'), + serialized_options=b'8\001', is_extendable=False, syntax='proto3', extension_ranges=[], @@ -72,14 +71,14 @@ _descriptor.FieldDescriptor( name='key', full_name='DaqConfig.FailModuleEntry.key', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='value', full_name='DaqConfig.FailModuleEntry.value', index=1, number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -89,7 +88,7 @@ nested_types=[], enum_types=[ ], - serialized_options=_b('8\001'), + serialized_options=b'8\001', is_extendable=False, syntax='proto3', extension_ranges=[], @@ -109,7 +108,7 @@ _descriptor.FieldDescriptor( name='site_description', full_name='DaqConfig.site_description', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -137,28 +136,28 @@ _descriptor.FieldDescriptor( name='base_conf', full_name='DaqConfig.base_conf', index=4, number=4, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='site_path', full_name='DaqConfig.site_path', index=5, number=5, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='initial_dhcp_lease_time', full_name='DaqConfig.initial_dhcp_lease_time', index=6, number=6, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='dhcp_lease_time', full_name='DaqConfig.dhcp_lease_time', index=7, number=7, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -186,7 +185,7 @@ _descriptor.FieldDescriptor( name='host_tests', full_name='DaqConfig.host_tests', index=11, number=16, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -242,63 +241,63 @@ _descriptor.FieldDescriptor( name='daq_loglevel', full_name='DaqConfig.daq_loglevel', index=19, number=21, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='mininet_loglevel', full_name='DaqConfig.mininet_loglevel', index=20, number=22, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='finish_hook', full_name='DaqConfig.finish_hook', index=21, number=35, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='gcp_cred', full_name='DaqConfig.gcp_cred', index=22, number=23, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='gcp_topic', full_name='DaqConfig.gcp_topic', index=23, number=24, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='schema_path', full_name='DaqConfig.schema_path', index=24, number=25, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='mud_files', full_name='DaqConfig.mud_files', index=25, number=26, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='device_specs', full_name='DaqConfig.device_specs', index=26, number=27, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='test_config', full_name='DaqConfig.test_config', index=27, number=28, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -312,21 +311,21 @@ _descriptor.FieldDescriptor( name='fail_hook', full_name='DaqConfig.fail_hook', index=29, number=30, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='device_template', full_name='DaqConfig.device_template', index=30, number=31, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='site_reports', full_name='DaqConfig.site_reports', index=31, number=32, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -392,7 +391,7 @@ _descriptor.FieldDescriptor( name='url', full_name='USISetup.url', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -423,14 +422,14 @@ _descriptor.FieldDescriptor( name='ctrl_intf', full_name='SwitchSetup.ctrl_intf', index=0, number=9, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='ip_addr', full_name='SwitchSetup.ip_addr', index=1, number=11, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -449,58 +448,65 @@ is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( - name='lo_addr', full_name='SwitchSetup.lo_addr', index=4, - number=15, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + name='alt_port', full_name='SwitchSetup.alt_port', index=4, + number=16, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( - name='mods_addr', full_name='SwitchSetup.mods_addr', index=5, - number=16, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + name='lo_addr', full_name='SwitchSetup.lo_addr', index=5, + number=18, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='mods_addr', full_name='SwitchSetup.mods_addr', index=6, + number=20, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( - name='of_dpid', full_name='SwitchSetup.of_dpid', index=6, + name='of_dpid', full_name='SwitchSetup.of_dpid', index=7, number=41, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( - name='data_intf', full_name='SwitchSetup.data_intf', index=7, + name='data_intf', full_name='SwitchSetup.data_intf', index=8, number=42, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( - name='ext_br', full_name='SwitchSetup.ext_br', index=8, + name='ext_br', full_name='SwitchSetup.ext_br', index=9, number=43, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( - name='model', full_name='SwitchSetup.model', index=9, + name='model', full_name='SwitchSetup.model', index=10, number=44, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( - name='username', full_name='SwitchSetup.username', index=10, + name='username', full_name='SwitchSetup.username', index=11, number=45, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( - name='password', full_name='SwitchSetup.password', index=11, + name='password', full_name='SwitchSetup.password', index=12, number=46, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -517,7 +523,7 @@ oneofs=[ ], serialized_start=1111, - serialized_end=1337, + serialized_end=1355, ) @@ -531,7 +537,7 @@ _descriptor.FieldDescriptor( name='opts', full_name='Interface.opts', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -554,8 +560,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1339, - serialized_end=1378, + serialized_start=1357, + serialized_end=1396, ) _DAQCONFIG_INTERFACESENTRY.fields_by_name['value'].message_type = _INTERFACE @@ -571,48 +577,48 @@ DESCRIPTOR.message_types_by_name['Interface'] = _INTERFACE _sym_db.RegisterFileDescriptor(DESCRIPTOR) -DaqConfig = _reflection.GeneratedProtocolMessageType('DaqConfig', (_message.Message,), dict( +DaqConfig = _reflection.GeneratedProtocolMessageType('DaqConfig', (_message.Message,), { - InterfacesEntry = _reflection.GeneratedProtocolMessageType('InterfacesEntry', (_message.Message,), dict( - DESCRIPTOR = _DAQCONFIG_INTERFACESENTRY, - __module__ = 'daq.proto.system_config_pb2' + 'InterfacesEntry' : _reflection.GeneratedProtocolMessageType('InterfacesEntry', (_message.Message,), { + 'DESCRIPTOR' : _DAQCONFIG_INTERFACESENTRY, + '__module__' : 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:DaqConfig.InterfacesEntry) - )) + }) , - FailModuleEntry = _reflection.GeneratedProtocolMessageType('FailModuleEntry', (_message.Message,), dict( - DESCRIPTOR = _DAQCONFIG_FAILMODULEENTRY, - __module__ = 'daq.proto.system_config_pb2' + 'FailModuleEntry' : _reflection.GeneratedProtocolMessageType('FailModuleEntry', (_message.Message,), { + 'DESCRIPTOR' : _DAQCONFIG_FAILMODULEENTRY, + '__module__' : 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:DaqConfig.FailModuleEntry) - )) + }) , - DESCRIPTOR = _DAQCONFIG, - __module__ = 'daq.proto.system_config_pb2' + 'DESCRIPTOR' : _DAQCONFIG, + '__module__' : 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:DaqConfig) - )) + }) _sym_db.RegisterMessage(DaqConfig) _sym_db.RegisterMessage(DaqConfig.InterfacesEntry) _sym_db.RegisterMessage(DaqConfig.FailModuleEntry) -USISetup = _reflection.GeneratedProtocolMessageType('USISetup', (_message.Message,), dict( - DESCRIPTOR = _USISETUP, - __module__ = 'daq.proto.system_config_pb2' +USISetup = _reflection.GeneratedProtocolMessageType('USISetup', (_message.Message,), { + 'DESCRIPTOR' : _USISETUP, + '__module__' : 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:USISetup) - )) + }) _sym_db.RegisterMessage(USISetup) -SwitchSetup = _reflection.GeneratedProtocolMessageType('SwitchSetup', (_message.Message,), dict( - DESCRIPTOR = _SWITCHSETUP, - __module__ = 'daq.proto.system_config_pb2' +SwitchSetup = _reflection.GeneratedProtocolMessageType('SwitchSetup', (_message.Message,), { + 'DESCRIPTOR' : _SWITCHSETUP, + '__module__' : 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:SwitchSetup) - )) + }) _sym_db.RegisterMessage(SwitchSetup) -Interface = _reflection.GeneratedProtocolMessageType('Interface', (_message.Message,), dict( - DESCRIPTOR = _INTERFACE, - __module__ = 'daq.proto.system_config_pb2' +Interface = _reflection.GeneratedProtocolMessageType('Interface', (_message.Message,), { + 'DESCRIPTOR' : _INTERFACE, + '__module__' : 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:Interface) - )) + }) _sym_db.RegisterMessage(Interface) diff --git a/proto/system_config.proto b/proto/system_config.proto index 1566620515..1d1d3c6475 100644 --- a/proto/system_config.proto +++ b/proto/system_config.proto @@ -140,14 +140,17 @@ message SwitchSetup { // Dataplane uplink port int32 uplink_port = 13; - // Local port of open flow controller + // Local port of DAQ OpenFlow controller int32 lo_port = 14; + // Local port for an alternate OpenFlow controller + int32 alt_port = 16; + // IP address and subnet for local control plane interface - string lo_addr = 15; + string lo_addr = 18; // IP address template and subnet for module ip addresses - string mods_addr = 16; + string mods_addr = 20; // Dataplane id of external OpenFlow switch string of_dpid = 41; diff --git a/testing/test_base.out b/testing/test_base.out index 86580802e2..edc14eaa30 100644 --- a/testing/test_base.out +++ b/testing/test_base.out @@ -152,6 +152,8 @@ RESULT pass base.switch.ping target %% 192.0.2.138:2 Switch test with target 192.0.2.138:2 Monolog processing base.switch.ping... switch ping 2 +%%%%%%%%%%%%%%%%%%%%%% Alt switch tests +XXX faucet.valve INFO DPID 1 (0x1) pri L2 learned on Port 1 9a:02:57:1e:8f:00 (L2 type 0x0800, L2 dst ff:ff:ff:ff:ff:ff, L3 src X.X.X.X, L3 dst 255.255.255.255) Port 1 VLAN 1002 (1 hosts total) %%%%%%%%%%%%%%%%%%%%%% Mud profile tests result open 01: [] 02: [] 03: [] device open 1 1 1 diff --git a/testing/test_base.sh b/testing/test_base.sh index d39e1c692c..3a4363e93a 100755 --- a/testing/test_base.sh +++ b/testing/test_base.sh @@ -52,6 +52,11 @@ cat -vet inst/run-port-02/nodes/ping02/activate.log count=$(fgrep icmp_seq=5 inst/run-port-02/nodes/ping02/activate.log | wc -l) echo switch ping $count | tee -a $TEST_RESULTS +echo %%%%%%%%%%%%%%%%%%%%%% Alt switch tests | tee -a $TEST_RESULTS +cp config/system/alt.yaml local/system.yaml +# TODO: Replace this with proper test once VLAN-triggers are added. +timeout 120s cmd/run -s +fgrep 'Port 1 9a:02:57:1e:8f:00' inst/faucet.log | redact | tee -a $TEST_RESULTS echo %%%%%%%%%%%%%%%%%%%%%% Mud profile tests | tee -a $TEST_RESULTS rm -f local/system.yaml cp config/system/muddy.conf local/system.conf diff --git a/testing/test_preamble.sh b/testing/test_preamble.sh index 93ca247d89..d01fc546f4 100644 --- a/testing/test_preamble.sh +++ b/testing/test_preamble.sh @@ -56,6 +56,7 @@ function redact { -e 's/[0-9]{4}-.*T.*Z/XXX/' \ -e 's/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2} [A-Z]{3}/XXX/' \ -e 's/[a-zA-Z]{3} [a-zA-Z]{3}\s+[0-9]{1,2} [0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2} [0-9]{4}/XXX/' \ + -e 's/[A-Za-z]{3} [0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/XXX/' \ -e 's/[0-9]{4}-(0|1)[0-9]-(0|1|2|3)[0-9] [0-9]{2}:[0-9]{2}:[0-9]{2}(\+00:00)?/XXX/g' \ -e 's/[0-9]+\.[0-9]{2} seconds/XXX/' \ -e 's/0\.[0-9]+s latency/XXX/' \ From fe0bf8b3c9dee0152d76dc9f4d64439d1f043a18 Mon Sep 17 00:00:00 2001 From: henry54809 Date: Tue, 14 Jul 2020 14:34:37 -0700 Subject: [PATCH 020/212] Additional DHCP test part 1 (#532) Port toggle DHCP test --- daq/host.py | 233 ++++++++++++------- daq/report.py | 5 +- docs/device_report.md | 1 + resources/setups/baseline/module_config.json | 19 +- testing/test_aux.out | 30 +++ testing/test_base.out | 1 + testing/test_many.out | 2 + testing/test_many.sh | 49 +++- 8 files changed, 249 insertions(+), 91 deletions(-) diff --git a/daq/host.py b/daq/host.py index 8dc3d5f8ac..2113693132 100644 --- a/daq/host.py +++ b/daq/host.py @@ -5,6 +5,7 @@ import shutil import time from datetime import timedelta, datetime +import logging import grpc from clib import tcpdump_helper @@ -17,9 +18,6 @@ import gcp import logger -LOGGER = logger.get_logger('host') - - class _STATE: """Host state enum for testing cycle""" ERROR = 'Error condition' @@ -55,11 +53,22 @@ def pre_states(): return ['startup', 'sanity', 'ipaddr', 'base', 'monitor'] +def dhcp_tests(): + """Returns all supported dhcp tests""" + return ['port_toggle', 'multi_subnet', 'ip_change'] + + def post_states(): """Return post-test states for recording finalization""" return ['finish', 'info', 'timer'] +def get_test_config(config, test): + """Get a single test module's config""" + if test in dhcp_tests(): + return config['modules'].get('ipaddr', {}).get('dhcp_tests', {}).get(test) + return config["modules"].get(test) + class ConnectedHost: """Class managing a device-under-test""" @@ -73,6 +82,7 @@ class ConnectedHost: _CONFIG_DIR = "config/" _TIMEOUT_EXCEPTION = TimeoutError('Timeout expired') + # pylint: disable=too-many-statements def __init__(self, runner, gateway, target, config): self.configurator = configurator.Configurator() self.runner = runner @@ -86,6 +96,7 @@ def __init__(self, runner, gateway, target, config): self.devdir = self._init_devdir() self.run_id = self.make_runid() self.scan_base = os.path.abspath(os.path.join(self.devdir, 'scans')) + self.logger = logger.get_logger('host%s' % self.target_port) self._port_base = self._get_port_base() self._device_base = self._get_device_base() self.state = None @@ -112,7 +123,9 @@ def __init__(self, runner, gateway, target, config): assert self._loaded_config, 'config was not loaded' self._write_module_config(self._loaded_config, self._device_aux_path()) self.remaining_tests = self._get_enabled_tests() - LOGGER.info('Host %s running with enabled tests %s', self.target_port, self.remaining_tests) + self.dhcp_tests = self._get_dhcp_tests() + self.logger.info('Host %s running with enabled tests %s', self.target_port, + self.remaining_tests) self._report = ReportGenerator(config, self._INST_DIR, self.target_mac, self._loaded_config) self.record_result('startup', state=MODE.PREP) @@ -121,6 +134,12 @@ def __init__(self, runner, gateway, target, config): self._startup_file = None self.timeout_handler = self._aux_module_timeout_handler self._all_ips = [] + self._ip_listener = None + self._dhcp_tests_map = { + 'port_toggle': self._dhcp_port_toggle_test, + 'multi_subnet': None, # TODO + 'ip_change': None # TODO + } @staticmethod def make_runid(): @@ -139,7 +158,7 @@ def _get_port_base(self): return None conf_base = os.path.abspath(os.path.join(test_config, 'port-%02d' % self.target_port)) if not os.path.isdir(conf_base): - LOGGER.warning('Test config directory not found: %s', conf_base) + self.logger.warning('Test config directory not found: %s', conf_base) return None return conf_base @@ -154,22 +173,25 @@ def _make_control_bundle(self): 'paused': self.state == _STATE.READY } + def _get_test_config(self, test): + return get_test_config(self._loaded_config, test) + def _test_enabled(self, test): fallback_config = {'enabled': test in self._CORE_TESTS} - test_config = self._loaded_config['modules'].get(test, fallback_config) + test_config = self._get_test_config(test) or fallback_config return test_config.get('enabled', True) def _get_test_timeout(self, test): - test_module = self._loaded_config['modules'].get(test) if test == 'hold': return None + test_module = self._get_test_config(test) if not test_module: return self._default_timeout_sec return test_module.get('timeout_sec', self._default_timeout_sec) def get_port_flap_timeout(self, test): """Get port toggle timeout configuration that's specific to each test module""" - test_module = self._loaded_config['modules'].get(test) + test_module = self._get_test_config(test) if not test_module: return None return test_module.get('port_flap_timeout_sec') @@ -194,6 +216,10 @@ def _get_static_ip(self): def _get_dhcp_mode(self): return self._loaded_config['modules'].get('ipaddr', {}).get('dhcp_mode', 'normal') + def _get_dhcp_tests(self): + tests = self._loaded_config['modules'].get('ipaddr', {}).get('dhcp_tests', {}).keys() + return list(filter(self._test_enabled, tests)) + def _get_unique_upload_path(self, file_name): base = os.path.basename(file_name) partial = os.path.join('tests', self.test_name, base) if self.test_name else base @@ -210,7 +236,7 @@ def _type_path(self): device_type = dev_config.get('device_type') if not device_type: return None - LOGGER.info('Configuring device %s as type %s', self.target_mac, device_type) + self.logger.info('Configuring device %s as type %s', self.target_mac, device_type) site_path = self.config.get('site_path') type_path = os.path.abspath(os.path.join(site_path, 'device_types', device_type)) return type_path @@ -221,20 +247,20 @@ def _type_aux_path(self): return None aux_path = os.path.join(type_path, self._AUX_DIR) if not os.path.exists(aux_path): - LOGGER.info('Skipping missing type dir %s', aux_path) + self.logger.info('Skipping missing type dir %s', aux_path) return None return aux_path def _create_device_dir(self, path): - LOGGER.warning('Creating new device dir: %s', path) + self.logger.warning('Creating new device dir: %s', path) os.makedirs(path) template_dir = self.config.get('device_template') if not template_dir: - LOGGER.warning('Skipping defaults since no device_template found') + self.logger.warning('Skipping defaults since no device_template found') return - LOGGER.info('Copying template files from %s to %s', template_dir, path) + self.logger.info('Copying template files from %s to %s', template_dir, path) for file in os.listdir(template_dir): - LOGGER.info('Copying %s...', file) + self.logger.info('Copying %s...', file) shutil.copy(os.path.join(template_dir, file), path) def _upload_file(self, path): @@ -243,7 +269,7 @@ def _upload_file(self, path): def initialize(self): """Fully initialize a new host set""" - LOGGER.info('Target port %d initializing...', self.target_port) + self.logger.info('Target port %d initializing...', self.target_port) # There is a race condition here with ovs assigning ports, so wait a bit. time.sleep(2) shutil.rmtree(self.devdir, ignore_errors=True) @@ -265,7 +291,7 @@ def _start_run(self): self._startup_scan() def _mark_skipped_tests(self): - for test in self.config['test_list']: + for test in self.config['test_list'] + dhcp_tests(): if not self._test_enabled(test): self._record_result(test, state=MODE.NOPE) @@ -274,7 +300,7 @@ def _state_transition(self, target, expected=None): message = 'state was %s expected %s' % (self.state, expected) assert self.state == expected, message assert self.state != _STATE.TERM, 'host already terminated' - LOGGER.debug('Target port %d state: %s -> %s', self.target_port, self.state, target) + self.logger.debug('Target port %d state: %s -> %s', self.target_port, self.state, target) self.state = target def _build_switch_info(self) -> usi.SwitchInfo: @@ -316,19 +342,20 @@ def connect_port(self, connect): res = stub.connect(switch_info) else: res = stub.disconnect(switch_info) - LOGGER.info('Target port %s %s successful? %s', self.target_port, "connect" - if connect else "disconnect", res.success) + self.logger.info('Target port %s %s successful? %s', self.target_port, "connect" + if connect else "disconnect", res.success) except Exception as e: - LOGGER.error(e) + self.logger.error(e) + raise e def _prepare(self): - LOGGER.info('Target port %d waiting for ip as %s', self.target_port, self.target_mac) + self.logger.info('Target port %d waiting for ip as %s', self.target_port, self.target_mac) self._state_transition(_STATE.WAITING, _STATE.INIT) self.record_result('sanity', state=MODE.DONE) self.record_result('ipaddr', state=MODE.EXEC) static_ip = self._get_static_ip() if static_ip: - LOGGER.info('Target port %d using static ip', self.target_port) + self.logger.info('Target port %d using static ip', self.target_port) time.sleep(self._STARTUP_MIN_TIME_SEC) self.runner.ip_notify(MODE.NOPE, { 'mac': self.target_mac, @@ -340,8 +367,8 @@ def _prepare(self): # enables dhcp response for this device wait_time = self.runner.config.get("long_dhcp_response_sec") \ if dhcp_mode == 'long_response' else 0 - LOGGER.info('Target port %d using %s DHCP mode, wait %s', - self.target_port, dhcp_mode, wait_time) + self.logger.info('Target port %d using %s DHCP mode, wait %s', + self.target_port, dhcp_mode, wait_time) self.gateway.change_dhcp_response_time(self.target_mac, wait_time) _ = [listener(self) for listener in self._dhcp_listeners] @@ -362,7 +389,8 @@ def heartbeat(self): nowtime = gcp.parse_timestamp(gcp.get_timestamp()) if nowtime >= timeout: if self.timeout_handler: - LOGGER.error('Monitoring timeout for %s after %ds', self.test_name, timeout_sec) + self.logger.error('Monitoring timeout for %s after %ds', self.test_name, + timeout_sec) # ensure it's called once handler, self.timeout_handler = self.timeout_handler, None handler() @@ -376,15 +404,15 @@ def _finalize_report(self): report_paths = self._report.finalize() if self._trigger_path: report_paths.update({'trigger_path': self._trigger_path}) - LOGGER.info('Finalized with reports %s', list(report_paths.keys())) + self.logger.info('Finalized with reports %s', list(report_paths.keys())) report_blobs = {name: self._upload_file(path) for name, path in report_paths.items()} self.record_result('terminate', state=MODE.TERM, **report_blobs) self._report = None def terminate(self, reason, trigger=True): """Terminate this host""" - LOGGER.info('Target port %d terminate, running %s, trigger %s: %s', self.target_port, - self._host_name(), trigger, reason) + self.logger.info('Target port %d terminate, running %s, trigger %s: %s', self.target_port, + self._host_name(), trigger, reason) self._state_transition(_STATE.TERM) self._release_config() self._monitor_cleanup() @@ -396,8 +424,8 @@ def terminate(self, reason, trigger=True): self.test_host = None self.timeout_handler = None except Exception as e: - LOGGER.error('Target port %d terminating test: %s', self.target_port, e) - LOGGER.exception(e) + self.logger.error('Target port %d terminating test: %s', self.target_port, e) + self.logger.exception(e) if trigger: self.runner.target_set_complete(self.target_port, 'Target port %d termination: %s' % ( @@ -418,6 +446,8 @@ def ip_notify(self, target_ip, state=MODE.DONE, delta_sec=-1): self._all_ips.append({"ip": target_ip, "timestamp": time.time()}) if self._get_dhcp_mode() == "ip_change" and len(self._all_ips) == 1: self.gateway.request_new_ip(self.target_mac) + if self._ip_listener: + self._ip_listener(target_ip) def trigger_ready(self): """Check if this host is ready to be triggered""" @@ -433,10 +463,10 @@ def trigger_ready(self): def trigger(self, state=MODE.DONE, target_ip=None, exception=None, delta_sec=-1): """Handle device trigger""" if not self.target_ip and not self.trigger_ready(): - LOGGER.warn('Target port %d ignoring premature trigger', self.target_port) + self.logger.warn('Target port %d ignoring premature trigger', self.target_port) return False if self.target_ip: - LOGGER.debug('Target port %d already triggered', self.target_port) + self.logger.debug('Target port %d already triggered', self.target_port) assert self.target_ip == target_ip, "target_ip mismatch" return True self.target_ip = target_ip @@ -446,28 +476,28 @@ def trigger(self, state=MODE.DONE, target_ip=None, exception=None, delta_sec=-1) self._state_transition(_STATE.ERROR) self.runner.target_set_error(self.target_port, exception) else: - LOGGER.info('Target port %d triggered as %s', self.target_port, target_ip) + self.logger.info('Target port %d triggered as %s', self.target_port, target_ip) self._state_transition(_STATE.BASE, _STATE.WAITING) return True def _ping_test(self, src, dst, src_addr=None): if not src or not dst: - LOGGER.error('Invalid ping test params, src=%s, dst=%s', src, dst) + self.logger.error('Invalid ping test params, src=%s, dst=%s', src, dst) return False return self.runner.ping_test(src, dst, src_addr=src_addr) def _startup_scan(self): self._startup_file = os.path.join(self.scan_base, 'startup.pcap') self._startup_time = datetime.now() - LOGGER.info('Target port %d startup pcap capture', self.target_port) + self.logger.info('Target port %d startup pcap capture', self.target_port) self._monitor_scan(self._startup_file) def _monitor_scan(self, output_file, timeout=None): assert not self._monitor_ref, 'tcp_monitor already active' network = self.runner.network tcp_filter = '' - LOGGER.info('Target port %d pcap intf %s for %ss output in %s', - self.target_port, self._mirror_intf_name, timeout, output_file) + self.logger.info('Target port %d pcap intf %s for %ss output in %s', + self.target_port, self._mirror_intf_name, timeout, output_file) helper = tcpdump_helper.TcpdumpHelper(network.pri, tcp_filter, packets=None, intf_name=self._mirror_intf_name, timeout=timeout, pcap_out=output_file, @@ -483,10 +513,10 @@ def _base_start(self): success = self._base_tests() self._monitor_cleanup() if not success: - LOGGER.warning('Target port %d base tests failed', self.target_port) + self.logger.warning('Target port %d base tests failed', self.target_port) self._state_transition(_STATE.ERROR) return - LOGGER.info('Target port %d done with base.', self.target_port) + self.logger.info('Target port %d done with base.', self.target_port) self._background_scan() except Exception as e: self._monitor_cleanup() @@ -494,7 +524,7 @@ def _base_start(self): def _monitor_cleanup(self, forget=True): if self._monitor_ref: - LOGGER.info('Target port %d network pcap complete', self.target_port) + self.logger.info('Target port %d network pcap complete', self.target_port) active = self._monitor_ref.stream() and not self._monitor_ref.stream().closed assert active == forget, 'forget and active mismatch' self._upload_file(self._startup_file) @@ -504,7 +534,8 @@ def _monitor_cleanup(self, forget=True): self._monitor_ref = None def _monitor_error(self, exception, forget=False): - LOGGER.error('Target port %d monitor error: %s', self.target_port, exception) + self.logger.error('Target port %d monitor error: %s', self.target_port, exception) + self._ip_listener = None self._monitor_cleanup(forget=forget) self.record_result(self.test_name, exception=exception) self._state_transition(_STATE.ERROR) @@ -513,13 +544,13 @@ def _monitor_error(self, exception, forget=False): def _background_scan(self): self._state_transition(_STATE.MONITOR, _STATE.BASE) if not self._monitor_scan_sec: - LOGGER.info('Target port %d skipping background pcap', self.target_port) + self.logger.info('Target port %d skipping background pcap', self.target_port) self._monitor_continue() return self.record_result('monitor', time=self._monitor_scan_sec, state=MODE.EXEC) monitor_file = os.path.join(self.scan_base, 'monitor.pcap') - LOGGER.info('Target port %d background pcap for %ds', - self.target_port, self._monitor_scan_sec) + self.logger.info('Target port %d background pcap for %ds', + self.target_port, self._monitor_scan_sec) self._monitor_scan(monitor_file, timeout=self._monitor_scan_sec) def _monitor_timeout(self, timeout): @@ -530,7 +561,7 @@ def _monitor_timeout(self, timeout): self._monitor_complete() def _monitor_complete(self): - LOGGER.info('Target port %d pcap complete', self.target_port) + self.logger.info('Target port %d pcap complete', self.target_port) self._monitor_cleanup(forget=False) self.record_result('monitor', state=MODE.DONE) self._monitor_continue() @@ -542,7 +573,7 @@ def _monitor_continue(self): def _base_tests(self): self.record_result('base', state=MODE.EXEC) if not self._ping_test(self.gateway.host, self.target_ip): - LOGGER.debug('Target port %d warmup ping failed', self.target_port) + self.logger.debug('Target port %d warmup ping failed', self.target_port) try: success1 = self._ping_test(self.gateway.host, self.target_ip), 'simple ping failed' success2 = self._ping_test(self.gateway.host, self.target_ip, @@ -556,21 +587,36 @@ def _base_tests(self): self.record_result('base', state=MODE.DONE) return True + def _dhcp_port_toggle_test(self, logging_handler): + def ip_listener(target_ip): + self.logger.info("%s test Received ip: %s" % (self.test_name, target_ip)) + if logging_handler: + self.logger.removeHandler(logging_handler) + self._ip_listener = None + self._end_test() + + self.connect_port(False) + time.sleep(self.runner.config.get("port_debounce_sec", 0) + 1) + self.connect_port(True) + self._ip_listener = ip_listener + def _run_next_test(self): try: if self.remaining_tests: - LOGGER.debug('Target port %d executing tests %s', - self.target_port, self.remaining_tests) + self.logger.debug('Target port %d executing tests %s', + self.target_port, self.remaining_tests) self.timeout_handler = self._main_module_timeout_handler self._docker_test(self.remaining_tests.pop(0)) + elif self.dhcp_tests: + self._dhcp_test(self.dhcp_tests.pop(0)) else: - LOGGER.info('Target port %d no more tests remaining', self.target_port) + self.logger.info('Target port %d no more tests remaining', self.target_port) self.timeout_handler = self._aux_module_timeout_handler self._state_transition(_STATE.DONE, _STATE.NEXT) self.test_name = None self.record_result('finish', state=MODE.FINE) except Exception as e: - LOGGER.error('Target port %d start error: %s', self.target_port, e) + self.logger.error('Target port %d start error: %s', self.target_port, e) self._state_transition(_STATE.ERROR) self.runner.target_set_error(self.target_port, e) @@ -584,11 +630,9 @@ def _device_aux_path(self): return path def _docker_test(self, test_name): - self.test_name = test_name - self.test_start = gcp.get_timestamp() self.test_host = docker_test.DockerTest(self.runner, self.target_port, self.devdir, test_name) - LOGGER.debug('test_host start %s/%s', test_name, self._host_name()) + self.logger.debug('test_host start %s/%s', test_name, self._host_name()) try: self.test_port = self.runner.allocate_test_port(self.target_port) @@ -597,7 +641,9 @@ def _docker_test(self, test_name): raise e try: - self._start_test_host() + self._start_test(test_name) + params = self._get_module_params() + self.test_host.start(self.test_port, params, self._docker_callback, self._finish_hook) except Exception as e: self.test_host = None self.runner.release_test_port(self.target_port, self.test_port) @@ -605,14 +651,49 @@ def _docker_test(self, test_name): self._monitor_cleanup() raise e - def _start_test_host(self): - params = self._get_module_params() + def _dhcp_test(self, test_name): + self.logger.info('Target port %d dhcp test %s running', self.target_port, test_name) + self.timeout_handler = self._aux_module_timeout_handler + self._start_test(test_name) + test_fn = self._dhcp_tests_map[test_name] + logging_handler = logging.FileHandler( + os.path.join(self._host_dir_path(), 'activate.log')) + # All the logging from this host will also go to activation log to be stored + self.logger.addHandler(logging_handler) + try: + test_fn(logging_handler) + except Exception as e: + self._end_test(state=MODE.MERR, exception=e) + self.logger.removeHandler(logging_handler) + self._run_next_test() + + def _start_test(self, test_name): + self.test_name = test_name + self.test_start = gcp.get_timestamp() self._write_module_config(self._loaded_config, self._host_tmp_path()) self._record_result(self.test_name, config=self._loaded_config, state=MODE.CONF) self.record_result(self.test_name, state=MODE.EXEC) self._monitor_scan(os.path.join(self.scan_base, 'test_%s.pcap' % self.test_name)) self._state_transition(_STATE.TESTING, _STATE.NEXT) - self.test_host.start(self.test_port, params, self._docker_callback, self._finish_hook) + + def _end_test(self, state=MODE.DONE, return_code=None, exception=None): + self._monitor_cleanup() + self._state_transition(_STATE.NEXT, _STATE.TESTING) + report_path = os.path.join(self._host_tmp_path(), 'report.txt') + activation_log_path = os.path.join(self._host_dir_path(), 'activate.log') + module_config_path = os.path.join(self._host_tmp_path(), self._MODULE_CONFIG) + remote_paths = {} + for result_type, path in ((ResultType.REPORT_PATH, report_path), + (ResultType.ACTIVATION_LOG_PATH, activation_log_path), + (ResultType.MODULE_CONFIG_PATH, module_config_path)): + if os.path.isfile(path): + self._report.accumulate(self.test_name, {result_type: path}) + remote_paths[result_type.value] = self._upload_file(path) + self.record_result(self.test_name, state=state, code=return_code, exception=exception, + **remote_paths) + self.test_host = None + self.timeout_handler = None + self._run_next_test() def _get_module_params(self): switch_setup = self.switch_setup if 'mods_addr' in self.switch_setup else None @@ -643,7 +724,7 @@ def _get_switch_config(self): } def _host_name(self): - return self.test_host.host_name if self.test_host else 'unknown' + return self.test_host.host_name if self.test_host else (self.test_name or 'unknown') def _host_dir_path(self): return os.path.join(self.devdir, 'nodes', self._host_name()) @@ -656,35 +737,19 @@ def _finish_hook(self): finish_dir = os.path.join(self.devdir, 'finish', self._host_name()) shutil.rmtree(finish_dir, ignore_errors=True) os.makedirs(finish_dir) - LOGGER.info('Executing finish_hook: %s %s', self._finish_hook_script, finish_dir) + self.logger.info('Executing finish_hook: %s %s', self._finish_hook_script, finish_dir) os.system('%s %s 2>&1 > %s/finish.out' % (self._finish_hook_script, finish_dir, finish_dir)) def _docker_callback(self, return_code=None, exception=None): host_name = self._host_name() - LOGGER.info('Host callback %s/%s was %s with %s', - self.test_name, host_name, return_code, exception) - self._monitor_cleanup() + self.logger.info('Host callback %s/%s was %s with %s', + self.test_name, host_name, return_code, exception) failed = return_code or exception state = MODE.MERR if failed else MODE.DONE - report_path = os.path.join(self._host_tmp_path(), 'report.txt') - activation_log_path = os.path.join(self._host_dir_path(), 'activate.log') - module_config_path = os.path.join(self._host_tmp_path(), self._MODULE_CONFIG) - remote_paths = {} - for result_type, path in ((ResultType.REPORT_PATH, report_path), - (ResultType.ACTIVATION_LOG_PATH, activation_log_path), - (ResultType.MODULE_CONFIG_PATH, module_config_path)): - if os.path.isfile(path): - self._report.accumulate(self.test_name, {result_type: path}) - remote_paths[result_type.value] = self._upload_file(path) - self.record_result(self.test_name, state=state, code=return_code, exception=exception, - **remote_paths) self.runner.release_test_port(self.target_port, self.test_port) - self._state_transition(_STATE.NEXT, _STATE.TESTING) assert self.test_host, '_docker_callback with no test_host defined' - self.test_host = None - self.timeout_handler = None - self._run_next_test() + self._end_test(state=state, return_code=return_code, exception=exception) def _merge_run_info(self, config): config['run_info'] = { @@ -708,8 +773,8 @@ def record_result(self, name, **kwargs): """Record a named result for this test""" current = gcp.get_timestamp() if name != self.test_name: - LOGGER.debug('Target port %d report %s start %s', - self.target_port, name, current) + self.logger.debug('Target port %d report %s start %s', + self.target_port, name, current) self.test_name = name self.test_start = current if name: @@ -745,12 +810,12 @@ def _exception_message(self, exception): return str(exception) def _control_updated(self, control_config): - LOGGER.info('Updated control config: %s %s', self.target_mac, control_config) + self.logger.info('Updated control config: %s %s', self.target_mac, control_config) paused = control_config.get('paused') if not paused and self.is_ready(): self._start_run() elif paused and not self.is_ready(): - LOGGER.warning('Inconsistent control state for update of %s', self.target_mac) + self.logger.warning('Inconsistent control state for update of %s', self.target_mac) def reload_config(self): """Trigger a config reload due to an external config change.""" @@ -759,12 +824,12 @@ def reload_config(self): if device_ready: self._loaded_config = new_config config_bundle = self._make_config_bundle(new_config) - LOGGER.info('Device config reloaded: %s %s', device_ready, self.target_mac) + self.logger.info('Device config reloaded: %s %s', device_ready, self.target_mac) self._record_result(None, run_info=device_ready, config=config_bundle) return new_config def _dev_config_updated(self, dev_config): - LOGGER.info('Device config update: %s %s', self.target_mac, dev_config) + self.logger.info('Device config update: %s %s', self.target_mac, dev_config) self._write_module_config(dev_config, self._device_base) self.reload_config() diff --git a/daq/report.py b/daq/report.py index 311c8fe89e..d3ee8e5046 100644 --- a/daq/report.py +++ b/daq/report.py @@ -16,7 +16,6 @@ import gcp import logger - LOGGER = logger.get_logger('report') class ResultType(Enum): @@ -306,6 +305,7 @@ def _get_test_info(self, test_name): return self._module_config.get('tests', {}).get(test_name, {}) def _write_repitems(self): + from host import get_test_config # Deferring import for (test_name, result_dict) in self._repitems.items(): # To not write a module header if there is nothing to report def writeln(line, test_name=test_name): @@ -318,7 +318,8 @@ def writeln(line, test_name=test_name): writeln(self._TEST_SUBHEADER % "Report") self._append_file(result_dict[ResultType.REPORT_PATH]) if ResultType.MODULE_CONFIG in result_dict: - config = result_dict[ResultType.MODULE_CONFIG].get("modules", {}).get(test_name) + module_configs = result_dict[ResultType.MODULE_CONFIG] + config = get_test_config(module_configs, test_name) if config and len(config) > 0: writeln(self._TEST_SUBHEADER % "Module Config") table = MdTable(["Attribute", "Value"]) diff --git a/docs/device_report.md b/docs/device_report.md index b22465300b..a2c17dcff1 100644 --- a/docs/device_report.md +++ b/docs/device_report.md @@ -101,6 +101,7 @@ Overall device result FAIL |Attribute|Value| |---|---| |timeout_sec|300| +|dhcp_tests|{'port_toggle': {'enabled': False, 'port_flap_timeout_sec': 20}, 'multi_subnet': {'subnets': [], 'timeout_sec': 600, 'enabled': False}, 'ip_change': {'timeout_sec': 500, 'enabled': False}}| ## Module pass diff --git a/resources/setups/baseline/module_config.json b/resources/setups/baseline/module_config.json index ea0f335568..cb9249d4ca 100644 --- a/resources/setups/baseline/module_config.json +++ b/resources/setups/baseline/module_config.json @@ -1,7 +1,22 @@ { "modules": { "ipaddr": { - "timeout_sec": 300 + "timeout_sec": 300, + "dhcp_tests": { + "port_toggle": { + "enabled": false, + "port_flap_timeout_sec": 20 + }, + "multi_subnet": { + "subnets": [], + "timeout_sec": 600, + "enabled": false + }, + "ip_change": { + "timeout_sec": 500, + "enabled": false + } + } }, "pass": { "enabled": true @@ -37,4 +52,4 @@ "enabled": true } } -} +} \ No newline at end of file diff --git a/testing/test_aux.out b/testing/test_aux.out index bed2e7dec1..816eec3538 100644 --- a/testing/test_aux.out +++ b/testing/test_aux.out @@ -94,6 +94,21 @@ port-01 module_config modules "enabled": false }, "ipaddr": { + "dhcp_tests": { + "ip_change": { + "enabled": false, + "timeout_sec": 500 + }, + "multi_subnet": { + "enabled": false, + "subnets": [], + "timeout_sec": 600 + }, + "port_toggle": { + "enabled": false, + "port_flap_timeout_sec": 20 + } + }, "timeout_sec": 300 }, "macoui": { @@ -145,6 +160,21 @@ port-02 module_config modules "enabled": true }, "ipaddr": { + "dhcp_tests": { + "ip_change": { + "enabled": false, + "timeout_sec": 500 + }, + "multi_subnet": { + "enabled": false, + "subnets": [], + "timeout_sec": 600 + }, + "port_toggle": { + "enabled": false, + "port_flap_timeout_sec": 20 + } + }, "timeout_sec": 300 }, "macoui": { diff --git a/testing/test_base.out b/testing/test_base.out index edc14eaa30..312ac5445f 100644 --- a/testing/test_base.out +++ b/testing/test_base.out @@ -44,6 +44,7 @@ Overall device result PASS |Attribute|Value| |---|---| |timeout_sec|300| +|dhcp_tests|{'port_toggle': {'enabled': False, 'port_flap_timeout_sec': 20}, 'multi_subnet': {'subnets': [], 'timeout_sec': 600, 'enabled': False}, 'ip_change': {'timeout_sec': 500, 'enabled': False}}| ## Module pass diff --git a/testing/test_many.out b/testing/test_many.out index fdef3cc356..2f518961a8 100644 --- a/testing/test_many.out +++ b/testing/test_many.out @@ -4,6 +4,8 @@ DAQ stress test Enough results: 1 Enough DHCP timeouts: 1 Enough static ips: 1 +Enough port toggle tests: 1 +Enough port toggle timeouts: 1 Redacted soak diff No soak report diff Done with many diff --git a/testing/test_many.sh b/testing/test_many.sh index 2dabc2e0c0..7c13bb6644 100755 --- a/testing/test_many.sh +++ b/testing/test_many.sh @@ -3,11 +3,16 @@ source testing/test_preamble.sh # num of devices need to less than 10 -NUM_DEVICES=8 +NUM_DEVICES=9 RUN_LIMIT=20 # num of timeout devices need to be less or equal to num dhcp devices NUM_NO_DHCP_DEVICES=4 NUM_TIMEOUT_DEVICES=2 + +# Extended DHCP tests +NUM_PORT_TOGGLE_DHCP_TEST_DEVICES=2 +NUM_PORT_TOGGLE_DHCP_TEST_TIMEOUT_DEVICES=1 + echo Many Tests >> $TEST_RESULTS echo source config/system/default.yaml > local/system.conf @@ -18,11 +23,11 @@ echo gcp_cred=$gcp_cred >> local/system.conf for iface in $(seq 1 $NUM_DEVICES); do xdhcp="" + intf_mac="9a02571e8f0$iface" + mkdir -p local/site/mac_addrs/$intf_mac if [[ $iface -le $NUM_NO_DHCP_DEVICES ]]; then ip="10.20.0.$((iface+5))" - intf_mac="9a02571e8f0$iface" xdhcp="xdhcp=$ip" - mkdir -p local/site/mac_addrs/$intf_mac if [[ $iface -gt $NUM_TIMEOUT_DEVICES ]]; then #Install site specific configs for xdhcp ips cat < local/site/mac_addrs/$intf_mac/module_config.json @@ -39,6 +44,39 @@ EOF } } } +EOF + fi + elif [[ $iface -le $((NUM_NO_DHCP_DEVICES + NUM_PORT_TOGGLE_DHCP_TEST_DEVICES)) ]]; then + if [[ $iface -le $((NUM_NO_DHCP_DEVICES + NUM_PORT_TOGGLE_DHCP_TEST_TIMEOUT_DEVICES)) ]]; then + cat < local/site/mac_addrs/$intf_mac/module_config.json + { + "modules": { + "ipaddr": { + "dhcp_tests": { + "port_toggle": { + "enabled": true, + "port_flap_timeout_sec": 20, + "timeout_sec": 1 + } + } + } + } + } +EOF + else + cat < local/site/mac_addrs/$intf_mac/module_config.json + { + "modules": { + "ipaddr": { + "dhcp_tests": { + "port_toggle": { + "enabled": true, + "port_flap_timeout_sec": 20 + } + } + } + } + } EOF fi fi @@ -54,6 +92,8 @@ end_time=`date -u -Isec` cat inst/result.log results=$(fgrep [] inst/result.log | wc -l) timeouts=$(fgrep "ipaddr:TimeoutError" inst/result.log | wc -l) +port_toggle_timeouts=$(fgrep "port_toggle:TimeoutError" inst/result.log | wc -l) +port_toggles=$(fgrep "port_toggle test Received ip:" inst/cmdrun.log | wc -l) cat inst/run-port-*/scans/ip_triggers.txt static_ips=$(fgrep nope inst/run-port-*/scans/ip_triggers.txt | wc -l) @@ -69,6 +109,9 @@ echo Enough results: $((results >= 6*RUN_LIMIT/10)) | tee -a $TEST_RESULTS echo Enough DHCP timeouts: $((timeouts >= NUM_TIMEOUT_DEVICES)) | tee -a $TEST_RESULTS echo Enough static ips: $((static_ips >= (NUM_NO_DHCP_DEVICES - NUM_TIMEOUT_DEVICES))) | tee -a $TEST_RESULTS +echo Enough port toggle tests: $((port_toggles >= (NUM_PORT_TOGGLE_DHCP_TEST_DEVICES - NUM_PORT_TOGGLE_DHCP_TEST_TIMEOUT_DEVICES) )) | tee -a $TEST_RESULTS +echo Enough port toggle timeouts: $((port_toggle_timeouts >= NUM_PORT_TOGGLE_DHCP_TEST_TIMEOUT_DEVICES)) | tee -a $TEST_RESULTS + echo bin/combine_reports device=9a:02:57:1e:8f:05 from_time=$start_time to_time=$end_time count=2 bin/combine_reports device=9a:02:57:1e:8f:05 from_time=$start_time to_time=$end_time count=2 From 9f6add897de6474a2ae1e242ac130b8056fa77ad Mon Sep 17 00:00:00 2001 From: Trevor Date: Wed, 15 Jul 2020 14:55:53 -0700 Subject: [PATCH 021/212] Refactor ipaddress module (#536) --- .idea/codeStyles/codeStyleConfig.xml | 5 + .idea/vcs.xml | 4 + config/modules/host.conf | 1 + daq/docker_test.py | 10 +- daq/gcp.py | 3 +- daq/host.py | 96 ++++++++------------ daq/ipaddr_test.py | 70 ++++++++++++++ docs/device_report.md | 21 +++-- libs/proto/usi_pb2.py | 26 ++++-- resources/setups/baseline/module_config.json | 19 +--- testing/test_aux.out | 39 ++------ testing/test_base.out | 21 +++-- testing/test_dhcp.out | 2 +- testing/test_many.out | 4 +- testing/test_many.sh | 38 ++++---- 15 files changed, 192 insertions(+), 167 deletions(-) create mode 100644 .idea/codeStyles/codeStyleConfig.xml create mode 100644 daq/ipaddr_test.py diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000000..b9d18bf599 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml index b8fa9bb7a4..3fc93409e7 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -36,6 +36,10 @@ + + + + \ No newline at end of file diff --git a/config/modules/host.conf b/config/modules/host.conf index 8ec24df938..deda32bdd6 100644 --- a/config/modules/host.conf +++ b/config/modules/host.conf @@ -7,6 +7,7 @@ build docker/modules add pass add fail add ping +add ipaddr add bacnet add mudgee diff --git a/daq/docker_test.py b/daq/docker_test.py index fdabebd0f7..c38b210b8d 100644 --- a/daq/docker_test.py +++ b/daq/docker_test.py @@ -19,18 +19,17 @@ class DockerTest: CONTAINER_PREFIX = 'daq' # pylint: disable=too-many-arguments - def __init__(self, runner, target_port, tmpdir, test_name, env_vars=None): + def __init__(self, host, target_port, tmpdir, test_name, module_config): self.target_port = target_port self.tmpdir = tmpdir self.test_name = test_name - self.runner = runner + self.runner = host.runner self.host_name = '%s%02d' % (test_name, self.target_port) self.docker_log = None self.docker_host = None self.callback = None self.start_time = None self.pipe = None - self.env_vars = env_vars or [] self._finish_hook = None def start(self, port, params, callback, finish_hook): @@ -44,7 +43,7 @@ def start(self, port, params, callback, finish_hook): def opt_param(key): return params.get(key) or '' # Substitute empty string for None - env_vars = self.env_vars + [ + env_vars = [ "TARGET_NAME=" + self.host_name, "TARGET_IP=" + params['target_ip'], "TARGET_MAC=" + params['target_mac'], @@ -168,3 +167,6 @@ def _docker_complete(self): LOGGER.info("Target port %d test %s passed %ss", self.target_port, self.test_name, delay) self.callback(return_code=return_code, exception=exception) + + def ip_listener(self, target_ip): + """Do nothing b/c docker tests don't care about ip notifications""" diff --git a/daq/gcp.py b/daq/gcp.py index 17051870a1..67db631e0b 100644 --- a/daq/gcp.py +++ b/daq/gcp.py @@ -24,6 +24,7 @@ # pylint: disable=no-member DESCENDING = firestore.Query.DESCENDING + def get_timestamp(): """"Get a JSON-compatible formatted timestamp""" return to_timestamp(datetime.datetime.now(datetime.timezone.utc)) @@ -49,7 +50,7 @@ def __init__(self, config, callback_handler): self._callback_handler = callback_handler cred_file = self.config.get('gcp_cred') if not cred_file: - LOGGER.info('No gcp_cred filr specified in config, disabling gcp use.') + LOGGER.info('No gcp_cred file specified in config, disabling gcp use.') self._pubber = None self._storage = None self._firestore = None diff --git a/daq/host.py b/daq/host.py index 2113693132..5de826f8c9 100644 --- a/daq/host.py +++ b/daq/host.py @@ -5,10 +5,10 @@ import shutil import time from datetime import timedelta, datetime -import logging import grpc from clib import tcpdump_helper + from report import ResultType, ReportGenerator from proto import usi_pb2 as usi from proto import usi_pb2_grpc as usi_service @@ -16,8 +16,10 @@ import configurator import docker_test import gcp +import ipaddr_test import logger + class _STATE: """Host state enum for testing cycle""" ERROR = 'Error condition' @@ -50,7 +52,7 @@ class MODE: def pre_states(): """Return pre-test states for basic operation""" - return ['startup', 'sanity', 'ipaddr', 'base', 'monitor'] + return ['startup', 'sanity', 'acquire', 'base', 'monitor'] def dhcp_tests(): @@ -65,10 +67,9 @@ def post_states(): def get_test_config(config, test): """Get a single test module's config""" - if test in dhcp_tests(): - return config['modules'].get('ipaddr', {}).get('dhcp_tests', {}).get(test) return config["modules"].get(test) + class ConnectedHost: """Class managing a device-under-test""" @@ -123,7 +124,6 @@ def __init__(self, runner, gateway, target, config): assert self._loaded_config, 'config was not loaded' self._write_module_config(self._loaded_config, self._device_aux_path()) self.remaining_tests = self._get_enabled_tests() - self.dhcp_tests = self._get_dhcp_tests() self.logger.info('Host %s running with enabled tests %s', self.target_port, self.remaining_tests) self._report = ReportGenerator(config, self._INST_DIR, self.target_mac, @@ -135,11 +135,6 @@ def __init__(self, runner, gateway, target, config): self.timeout_handler = self._aux_module_timeout_handler self._all_ips = [] self._ip_listener = None - self._dhcp_tests_map = { - 'port_toggle': self._dhcp_port_toggle_test, - 'multi_subnet': None, # TODO - 'ip_change': None # TODO - } @staticmethod def make_runid(): @@ -305,8 +300,11 @@ def _state_transition(self, target, expected=None): def _build_switch_info(self) -> usi.SwitchInfo: switch_config = self._get_switch_config() - if switch_config["model"]: - switch_model = usi.SwitchModel.Value(switch_config["model"]) + model_str = switch_config['model'] + if model_str == 'FAUX_SWITCH': + return None + if model_str: + switch_model = usi.SwitchModel.Value(model_str) else: switch_model = usi.SwitchModel.OVS_SWITCH params = { @@ -335,6 +333,9 @@ def notify_activate(self): def connect_port(self, connect): """Connects/Disconnects port for this host""" switch_info = self._build_switch_info() + if not switch_info: + self.logger.info('No switch model found, skipping port connect') + return False try: with grpc.insecure_channel(self._usi_url) as channel: stub = usi_service.USIServiceStub(channel) @@ -347,12 +348,13 @@ def connect_port(self, connect): except Exception as e: self.logger.error(e) raise e + return True def _prepare(self): self.logger.info('Target port %d waiting for ip as %s', self.target_port, self.target_mac) self._state_transition(_STATE.WAITING, _STATE.INIT) self.record_result('sanity', state=MODE.DONE) - self.record_result('ipaddr', state=MODE.EXEC) + self.record_result('acquire', state=MODE.EXEC) static_ip = self._get_static_ip() if static_ip: self.logger.info('Target port %d using static ip', self.target_port) @@ -378,7 +380,7 @@ def _aux_module_timeout_handler(self): def _main_module_timeout_handler(self): self.test_host.terminate() - self._docker_callback(exception=self._TIMEOUT_EXCEPTION) + self._module_callback(exception=self._TIMEOUT_EXCEPTION) def heartbeat(self): """Checks module run time for each event loop""" @@ -446,8 +448,8 @@ def ip_notify(self, target_ip, state=MODE.DONE, delta_sec=-1): self._all_ips.append({"ip": target_ip, "timestamp": time.time()}) if self._get_dhcp_mode() == "ip_change" and len(self._all_ips) == 1: self.gateway.request_new_ip(self.target_mac) - if self._ip_listener: - self._ip_listener(target_ip) + if self.test_host: + self.test_host.ip_listener(target_ip) def trigger_ready(self): """Check if this host is ready to be triggered""" @@ -471,7 +473,7 @@ def trigger(self, state=MODE.DONE, target_ip=None, exception=None, delta_sec=-1) return True self.target_ip = target_ip self._record_result('info', state='%s/%s' % (self.target_mac, target_ip)) - self.record_result('ipaddr', ip=target_ip, state=state, exception=exception) + self.record_result('acquire', ip=target_ip, state=state, exception=exception) if exception: self._state_transition(_STATE.ERROR) self.runner.target_set_error(self.target_port, exception) @@ -535,7 +537,6 @@ def _monitor_cleanup(self, forget=True): def _monitor_error(self, exception, forget=False): self.logger.error('Target port %d monitor error: %s', self.target_port, exception) - self._ip_listener = None self._monitor_cleanup(forget=forget) self.record_result(self.test_name, exception=exception) self._state_transition(_STATE.ERROR) @@ -568,6 +569,7 @@ def _monitor_complete(self): def _monitor_continue(self): self._state_transition(_STATE.NEXT, _STATE.MONITOR) + self.test_name = None self._run_next_test() def _base_tests(self): @@ -587,33 +589,17 @@ def _base_tests(self): self.record_result('base', state=MODE.DONE) return True - def _dhcp_port_toggle_test(self, logging_handler): - def ip_listener(target_ip): - self.logger.info("%s test Received ip: %s" % (self.test_name, target_ip)) - if logging_handler: - self.logger.removeHandler(logging_handler) - self._ip_listener = None - self._end_test() - - self.connect_port(False) - time.sleep(self.runner.config.get("port_debounce_sec", 0) + 1) - self.connect_port(True) - self._ip_listener = ip_listener - def _run_next_test(self): + assert not self.test_name, 'test_name defined: %s' % self.test_name try: if self.remaining_tests: self.logger.debug('Target port %d executing tests %s', self.target_port, self.remaining_tests) - self.timeout_handler = self._main_module_timeout_handler - self._docker_test(self.remaining_tests.pop(0)) - elif self.dhcp_tests: - self._dhcp_test(self.dhcp_tests.pop(0)) + self._run_test(self.remaining_tests.pop(0)) else: self.logger.info('Target port %d no more tests remaining', self.target_port) self.timeout_handler = self._aux_module_timeout_handler self._state_transition(_STATE.DONE, _STATE.NEXT) - self.test_name = None self.record_result('finish', state=MODE.FINE) except Exception as e: self.logger.error('Target port %d start error: %s', self.target_port, e) @@ -629,10 +615,15 @@ def _device_aux_path(self): os.makedirs(path) return path - def _docker_test(self, test_name): - self.test_host = docker_test.DockerTest(self.runner, self.target_port, - self.devdir, test_name) - self.logger.debug('test_host start %s/%s', test_name, self._host_name()) + def _new_test(self, test_name): + clazz = ipaddr_test.IpAddrTest if test_name == 'ipaddr' else docker_test.DockerTest + return clazz(self, self.target_port, self.devdir, test_name, self._loaded_config) + + def _run_test(self, test_name): + self.timeout_handler = self._main_module_timeout_handler + self.test_host = self._new_test(test_name) + + self.logger.info('Target port %d start %s', self.target_port, self._host_name()) try: self.test_port = self.runner.allocate_test_port(self.target_port) @@ -643,7 +634,7 @@ def _docker_test(self, test_name): try: self._start_test(test_name) params = self._get_module_params() - self.test_host.start(self.test_port, params, self._docker_callback, self._finish_hook) + self.test_host.start(self.test_port, params, self._module_callback, self._finish_hook) except Exception as e: self.test_host = None self.runner.release_test_port(self.target_port, self.test_port) @@ -651,22 +642,6 @@ def _docker_test(self, test_name): self._monitor_cleanup() raise e - def _dhcp_test(self, test_name): - self.logger.info('Target port %d dhcp test %s running', self.target_port, test_name) - self.timeout_handler = self._aux_module_timeout_handler - self._start_test(test_name) - test_fn = self._dhcp_tests_map[test_name] - logging_handler = logging.FileHandler( - os.path.join(self._host_dir_path(), 'activate.log')) - # All the logging from this host will also go to activation log to be stored - self.logger.addHandler(logging_handler) - try: - test_fn(logging_handler) - except Exception as e: - self._end_test(state=MODE.MERR, exception=e) - self.logger.removeHandler(logging_handler) - self._run_next_test() - def _start_test(self, test_name): self.test_name = test_name self.test_start = gcp.get_timestamp() @@ -691,6 +666,7 @@ def _end_test(self, state=MODE.DONE, return_code=None, exception=None): remote_paths[result_type.value] = self._upload_file(path) self.record_result(self.test_name, state=state, code=return_code, exception=exception, **remote_paths) + self.test_name = None self.test_host = None self.timeout_handler = None self._run_next_test() @@ -724,7 +700,7 @@ def _get_switch_config(self): } def _host_name(self): - return self.test_host.host_name if self.test_host else (self.test_name or 'unknown') + return self.test_host.host_name if self.test_host else 'unknown' def _host_dir_path(self): return os.path.join(self.devdir, 'nodes', self._host_name()) @@ -741,14 +717,14 @@ def _finish_hook(self): os.system('%s %s 2>&1 > %s/finish.out' % (self._finish_hook_script, finish_dir, finish_dir)) - def _docker_callback(self, return_code=None, exception=None): + def _module_callback(self, return_code=None, exception=None): host_name = self._host_name() self.logger.info('Host callback %s/%s was %s with %s', self.test_name, host_name, return_code, exception) failed = return_code or exception state = MODE.MERR if failed else MODE.DONE self.runner.release_test_port(self.target_port, self.test_port) - assert self.test_host, '_docker_callback with no test_host defined' + assert self.test_host, '_module_callback with no test_host defined' self._end_test(state=state, return_code=return_code, exception=exception) def _merge_run_info(self, config): diff --git a/daq/ipaddr_test.py b/daq/ipaddr_test.py new file mode 100644 index 0000000000..6bf29fafe2 --- /dev/null +++ b/daq/ipaddr_test.py @@ -0,0 +1,70 @@ +"""Test module encapsulating ip-address tests (including DHCP)""" + +from __future__ import absolute_import +import time +import os +import logger + +LOGGER = logger.get_logger('ipaddr') + + +class IpAddrTest: + """Module for inline ipaddr tests""" + + DEFAULT_WAIT_SEC = 10 + + # pylint: disable=too-many-arguments + def __init__(self, host, target_port, tmpdir, test_name, module_config): + self.host = host + self.target_port = target_port + self.tmpdir = tmpdir + self.test_config = module_config.get('modules').get('ipaddr') + self.test_name = test_name + self.host_name = '%s%02d' % (test_name, self.target_port) + self.log_path = os.path.join(self.tmpdir, 'nodes', self.host_name, 'activate.log') + self.log_file = None + self.callback = None + self.tests = [ + self._dhcp_port_toggle_test, + self._finalize + ] + + def start(self, port, params, callback, finish_hook): + """Start the ip-addr tests""" + self.callback = callback + LOGGER.debug('Target port %d starting ipaddr test %s', self.target_port, self.test_name) + self.log_file = open(self.log_path, 'w') + self._next_test() + + def _next_test(self): + try: + self.tests.pop(0)() + except Exception as e: + self._finalize(exception=e) + + def activate_log(self, message): + """Log an activation message""" + self.log_file.write(message + '\n') + + def _dhcp_port_toggle_test(self): + self.activate_log('dhcp_port_toggle_test') + if not self.host.connect_port(False): + self.activate_log('disconnect port not enabled') + return + time.sleep(self.host.config.get("port_debounce_sec", 0) + 1) + self.host.connect_port(True) + + def _finalize(self, exception=None): + self.terminate() + self.callback(exception=exception) + + def terminate(self): + """Terminate this set of tests""" + self.log_file.close() + self.log_file = None + + def ip_listener(self, target_ip): + """Respond to a ip notification event""" + self.activate_log('ip notification %s' % target_ip) + LOGGER.info("%s received ip %s" % (self.test_name, target_ip)) + self._next_test() diff --git a/docs/device_report.md b/docs/device_report.md index a2c17dcff1..3cc2ac6675 100644 --- a/docs/device_report.md +++ b/docs/device_report.md @@ -93,16 +93,6 @@ Overall device result FAIL |gone|unknown.fake.monkey|Other|Other|| -## Module ipaddr - - -#### Module Config - -|Attribute|Value| -|---|---| -|timeout_sec|300| -|dhcp_tests|{'port_toggle': {'enabled': False, 'port_flap_timeout_sec': 20}, 'multi_subnet': {'subnets': [], 'timeout_sec': 600, 'enabled': False}, 'ip_change': {'timeout_sec': 500, 'enabled': False}}| - ## Module pass @@ -154,6 +144,17 @@ RESULT pass base.target.ping target reached ``` +## Module ipaddr + + +#### Module Config + +|Attribute|Value| +|---|---| +|enabled|True| +|timeout_sec|300| +|port_flap_timeout_sec|20| + ## Module nmap diff --git a/libs/proto/usi_pb2.py b/libs/proto/usi_pb2.py index c9189dc119..9414eb0416 100644 --- a/libs/proto/usi_pb2.py +++ b/libs/proto/usi_pb2.py @@ -20,7 +20,7 @@ syntax='proto3', serialized_options=b'\n\004grpcB\010USIProtoP\001', create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\tusi.proto\x12\x03usi\"\'\n\x14SwitchActionResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\"\x9b\x01\n\rPowerResponse\x12!\n\x19\x63urrent_power_consumption\x18\x01 \x01(\x02\x12\x1d\n\x15max_power_consumption\x18\x02 \x01(\x02\x12$\n\x0bpoe_support\x18\x03 \x01(\x0e\x32\x0f.usi.POESupport\x12\"\n\npoe_status\x18\x04 \x01(\x0e\x32\x0e.usi.POEStatus\"]\n\x11InterfaceResponse\x12$\n\x0blink_status\x18\x01 \x01(\x0e\x32\x0f.usi.LinkStatus\x12\x12\n\nlink_speed\x18\x02 \x01(\x05\x12\x0e\n\x06\x64uplex\x18\x03 \x01(\t\"w\n\nSwitchInfo\x12\x0f\n\x07ip_addr\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65vice_port\x18\x03 \x01(\x05\x12\x1f\n\x05model\x18\x04 \x01(\x0e\x32\x10.usi.SwitchModel\x12\x10\n\x08username\x18\x05 \x01(\t\x12\x10\n\x08password\x18\x06 \x01(\t*F\n\x0bSwitchModel\x12\x17\n\x13\x41LLIED_TELESIS_X230\x10\x00\x12\x0e\n\nCISCO_9300\x10\x01\x12\x0e\n\nOVS_SWITCH\x10\x02*\x1e\n\nLinkStatus\x12\x06\n\x02UP\x10\x00\x12\x08\n\x04\x44OWN\x10\x01*\'\n\nPOESupport\x12\x0b\n\x07\x45NABLED\x10\x00\x12\x0c\n\x08\x44ISABLED\x10\x01*1\n\tPOEStatus\x12\x06\n\x02ON\x10\x00\x12\x07\n\x03OFF\x10\x01\x12\t\n\x05\x46\x41ULT\x10\x02\x12\x08\n\x04\x44\x45NY\x10\x03\x32\xef\x01\n\nUSIService\x12\x31\n\x08GetPower\x12\x0f.usi.SwitchInfo\x1a\x12.usi.PowerResponse\"\x00\x12\x39\n\x0cGetInterface\x12\x0f.usi.SwitchInfo\x1a\x16.usi.InterfaceResponse\"\x00\x12:\n\ndisconnect\x12\x0f.usi.SwitchInfo\x1a\x19.usi.SwitchActionResponse\"\x00\x12\x37\n\x07\x63onnect\x12\x0f.usi.SwitchInfo\x1a\x19.usi.SwitchActionResponse\"\x00\x42\x12\n\x04grpcB\x08USIProtoP\x01\x62\x06proto3' + serialized_pb=b'\n\tusi.proto\x12\x03usi\"\'\n\x14SwitchActionResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\"\x9b\x01\n\rPowerResponse\x12!\n\x19\x63urrent_power_consumption\x18\x01 \x01(\x02\x12\x1d\n\x15max_power_consumption\x18\x02 \x01(\x02\x12$\n\x0bpoe_support\x18\x03 \x01(\x0e\x32\x0f.usi.POESupport\x12\"\n\npoe_status\x18\x04 \x01(\x0e\x32\x0e.usi.POEStatus\"]\n\x11InterfaceResponse\x12$\n\x0blink_status\x18\x01 \x01(\x0e\x32\x0f.usi.LinkStatus\x12\x12\n\nlink_speed\x18\x02 \x01(\x05\x12\x0e\n\x06\x64uplex\x18\x03 \x01(\t\"w\n\nSwitchInfo\x12\x0f\n\x07ip_addr\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65vice_port\x18\x03 \x01(\x05\x12\x1f\n\x05model\x18\x04 \x01(\x0e\x32\x10.usi.SwitchModel\x12\x10\n\x08username\x18\x05 \x01(\t\x12\x10\n\x08password\x18\x06 \x01(\t*W\n\x0bSwitchModel\x12\x17\n\x13\x41LLIED_TELESIS_X230\x10\x00\x12\x0e\n\nCISCO_9300\x10\x01\x12\x0e\n\nOVS_SWITCH\x10\x02\x12\x0f\n\x0b\x46\x41UX_SWITCH\x10\x03*\x1e\n\nLinkStatus\x12\x06\n\x02UP\x10\x00\x12\x08\n\x04\x44OWN\x10\x01*\'\n\nPOESupport\x12\x0b\n\x07\x45NABLED\x10\x00\x12\x0c\n\x08\x44ISABLED\x10\x01*1\n\tPOEStatus\x12\x06\n\x02ON\x10\x00\x12\x07\n\x03OFF\x10\x01\x12\t\n\x05\x46\x41ULT\x10\x02\x12\x08\n\x04\x44\x45NY\x10\x03\x32\xef\x01\n\nUSIService\x12\x31\n\x08GetPower\x12\x0f.usi.SwitchInfo\x1a\x12.usi.PowerResponse\"\x00\x12\x39\n\x0cGetInterface\x12\x0f.usi.SwitchInfo\x1a\x16.usi.InterfaceResponse\"\x00\x12:\n\ndisconnect\x12\x0f.usi.SwitchInfo\x1a\x19.usi.SwitchActionResponse\"\x00\x12\x37\n\x07\x63onnect\x12\x0f.usi.SwitchInfo\x1a\x19.usi.SwitchActionResponse\"\x00\x42\x12\n\x04grpcB\x08USIProtoP\x01\x62\x06proto3' ) _SWITCHMODEL = _descriptor.EnumDescriptor( @@ -45,11 +45,16 @@ serialized_options=None, type=None, create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='FAUX_SWITCH', index=3, number=3, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), ], containing_type=None, serialized_options=None, serialized_start=433, - serialized_end=503, + serialized_end=520, ) _sym_db.RegisterEnumDescriptor(_SWITCHMODEL) @@ -74,8 +79,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=505, - serialized_end=535, + serialized_start=522, + serialized_end=552, ) _sym_db.RegisterEnumDescriptor(_LINKSTATUS) @@ -100,8 +105,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=537, - serialized_end=576, + serialized_start=554, + serialized_end=593, ) _sym_db.RegisterEnumDescriptor(_POESUPPORT) @@ -136,8 +141,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=578, - serialized_end=627, + serialized_start=595, + serialized_end=644, ) _sym_db.RegisterEnumDescriptor(_POESTATUS) @@ -145,6 +150,7 @@ ALLIED_TELESIS_X230 = 0 CISCO_9300 = 1 OVS_SWITCH = 2 +FAUX_SWITCH = 3 UP = 0 DOWN = 1 ENABLED = 0 @@ -398,8 +404,8 @@ index=0, serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_start=630, - serialized_end=869, + serialized_start=647, + serialized_end=886, methods=[ _descriptor.MethodDescriptor( name='GetPower', diff --git a/resources/setups/baseline/module_config.json b/resources/setups/baseline/module_config.json index cb9249d4ca..83eaa9a3b5 100644 --- a/resources/setups/baseline/module_config.json +++ b/resources/setups/baseline/module_config.json @@ -1,22 +1,9 @@ { "modules": { "ipaddr": { + "enabled": true, "timeout_sec": 300, - "dhcp_tests": { - "port_toggle": { - "enabled": false, - "port_flap_timeout_sec": 20 - }, - "multi_subnet": { - "subnets": [], - "timeout_sec": 600, - "enabled": false - }, - "ip_change": { - "timeout_sec": 500, - "enabled": false - } - } + "port_flap_timeout_sec": 20 }, "pass": { "enabled": true @@ -52,4 +39,4 @@ "enabled": true } } -} \ No newline at end of file +} diff --git a/testing/test_aux.out b/testing/test_aux.out index 816eec3538..cf65e1a828 100644 --- a/testing/test_aux.out +++ b/testing/test_aux.out @@ -60,7 +60,7 @@ RESULT pass security.firmware version found: ?\xFF\xFF\x19,>u\x08\x00no RESULT pass connection.network.ntp_support Using NTPv4. RESULT fail connection.network.ntp_support Not using NTPv4. RESULT skip connection.network.ntp_support No NTP packets received. -dhcp requests 1 1 0 1 +dhcp requests 1 1 1 1 01: [] 02: ['02:macoui:TimeoutError', '02:ping:TimeoutError'] 03: [] @@ -94,21 +94,8 @@ port-01 module_config modules "enabled": false }, "ipaddr": { - "dhcp_tests": { - "ip_change": { - "enabled": false, - "timeout_sec": 500 - }, - "multi_subnet": { - "enabled": false, - "subnets": [], - "timeout_sec": 600 - }, - "port_toggle": { - "enabled": false, - "port_flap_timeout_sec": 20 - } - }, + "enabled": true, + "port_flap_timeout_sec": 20, "timeout_sec": 300 }, "macoui": { @@ -160,21 +147,8 @@ port-02 module_config modules "enabled": true }, "ipaddr": { - "dhcp_tests": { - "ip_change": { - "enabled": false, - "timeout_sec": 500 - }, - "multi_subnet": { - "enabled": false, - "subnets": [], - "timeout_sec": 600 - }, - "port_toggle": { - "enabled": false, - "port_flap_timeout_sec": 20 - } - }, + "enabled": true, + "port_flap_timeout_sec": 20, "timeout_sec": 300 }, "macoui": { @@ -232,16 +206,19 @@ inst/gw01/nodes/gw01/activate.log inst/gw02/nodes/gw02/activate.log inst/gw03/nodes/gw03/activate.log inst/run-port-01/nodes/fail01/activate.log +inst/run-port-01/nodes/ipaddr01/activate.log inst/run-port-01/nodes/nmap01/activate.log inst/run-port-01/nodes/pass01/activate.log inst/run-port-01/nodes/ping01/activate.log inst/run-port-02/nodes/fail02/activate.log inst/run-port-02/nodes/hold02/activate.log +inst/run-port-02/nodes/ipaddr02/activate.log inst/run-port-02/nodes/nmap02/activate.log inst/run-port-02/nodes/pass02/activate.log inst/run-port-02/nodes/ping02/activate.log inst/run-port-03/nodes/fail03/activate.log inst/run-port-03/nodes/hold03/activate.log +inst/run-port-03/nodes/ipaddr03/activate.log inst/run-port-03/nodes/nmap03/activate.log inst/run-port-03/nodes/pass03/activate.log inst/run-port-03/nodes/ping03/activate.log diff --git a/testing/test_base.out b/testing/test_base.out index 312ac5445f..d0181c88d0 100644 --- a/testing/test_base.out +++ b/testing/test_base.out @@ -36,16 +36,6 @@ Overall device result PASS |pass|security.ports.nmap|Other|Other|Only allowed ports found open.| -## Module ipaddr - - -#### Module Config - -|Attribute|Value| -|---|---| -|timeout_sec|300| -|dhcp_tests|{'port_toggle': {'enabled': False, 'port_flap_timeout_sec': 20}, 'multi_subnet': {'subnets': [], 'timeout_sec': 600, 'enabled': False}, 'ip_change': {'timeout_sec': 500, 'enabled': False}}| - ## Module pass @@ -97,6 +87,17 @@ RESULT pass base.target.ping target reached ``` +## Module ipaddr + + +#### Module Config + +|Attribute|Value| +|---|---| +|enabled|True| +|timeout_sec|300| +|port_flap_timeout_sec|20| + ## Module nmap diff --git a/testing/test_dhcp.out b/testing/test_dhcp.out index 6d2dc2e822..e7bf981faa 100644 --- a/testing/test_dhcp.out +++ b/testing/test_dhcp.out @@ -1,7 +1,7 @@ Running testing/test_dhcp.sh DHCP Tests 01: [] -02: ['02:ipaddr:TimeoutError'] +02: ['02:acquire:TimeoutError'] 03: [] 04: [] Device 1 ip triggers: 1 0 diff --git a/testing/test_many.out b/testing/test_many.out index 2f518961a8..3e8525aa5e 100644 --- a/testing/test_many.out +++ b/testing/test_many.out @@ -4,8 +4,8 @@ DAQ stress test Enough results: 1 Enough DHCP timeouts: 1 Enough static ips: 1 -Enough port toggle tests: 1 -Enough port toggle timeouts: 1 +Enough ipaddr tests: 1 +Enough ipaddr timeouts: 1 Redacted soak diff No soak report diff Done with many diff --git a/testing/test_many.sh b/testing/test_many.sh index 7c13bb6644..7befe66a76 100755 --- a/testing/test_many.sh +++ b/testing/test_many.sh @@ -10,8 +10,8 @@ NUM_NO_DHCP_DEVICES=4 NUM_TIMEOUT_DEVICES=2 # Extended DHCP tests -NUM_PORT_TOGGLE_DHCP_TEST_DEVICES=2 -NUM_PORT_TOGGLE_DHCP_TEST_TIMEOUT_DEVICES=1 +NUM_IPADDR_TEST_DEVICES=2 +NUM_IPADDR_TEST_TIMEOUT_DEVICES=1 echo Many Tests >> $TEST_RESULTS @@ -46,19 +46,15 @@ EOF } EOF fi - elif [[ $iface -le $((NUM_NO_DHCP_DEVICES + NUM_PORT_TOGGLE_DHCP_TEST_DEVICES)) ]]; then - if [[ $iface -le $((NUM_NO_DHCP_DEVICES + NUM_PORT_TOGGLE_DHCP_TEST_TIMEOUT_DEVICES)) ]]; then + elif [[ $iface -le $((NUM_NO_DHCP_DEVICES + NUM_IPADDR_TEST_DEVICES)) ]]; then + if [[ $iface -le $((NUM_NO_DHCP_DEVICES + NUM_IPADDR_TEST_TIMEOUT_DEVICES)) ]]; then cat < local/site/mac_addrs/$intf_mac/module_config.json { "modules": { "ipaddr": { - "dhcp_tests": { - "port_toggle": { - "enabled": true, - "port_flap_timeout_sec": 20, - "timeout_sec": 1 - } - } + "enabled": true, + "port_flap_timeout_sec": 20, + "timeout_sec": 1 } } } @@ -68,12 +64,8 @@ EOF { "modules": { "ipaddr": { - "dhcp_tests": { - "port_toggle": { - "enabled": true, - "port_flap_timeout_sec": 20 - } - } + "enabled": true, + "port_flap_timeout_sec": 20 } } } @@ -92,25 +84,27 @@ end_time=`date -u -Isec` cat inst/result.log results=$(fgrep [] inst/result.log | wc -l) timeouts=$(fgrep "ipaddr:TimeoutError" inst/result.log | wc -l) -port_toggle_timeouts=$(fgrep "port_toggle:TimeoutError" inst/result.log | wc -l) -port_toggles=$(fgrep "port_toggle test Received ip:" inst/cmdrun.log | wc -l) +ipaddr_timeouts=$(fgrep "ipaddr:TimeoutError" inst/result.log | wc -l) +ip_notifications=$(fgrep "ip notification" inst/run-port-*/nodes/ipaddr*/activate.log | wc -l) cat inst/run-port-*/scans/ip_triggers.txt static_ips=$(fgrep nope inst/run-port-*/scans/ip_triggers.txt | wc -l) more inst/run-port-*/nodes/ping*/activate.log | cat +more inst/run-port-*/nodes/ipaddr*/activate.log | cat echo Found $results clean runs, $timeouts timeouts, and $static_ips static_ips. +echo ipaddr had $ip_notifications notifications and $ipaddr_timeouts timeouts. # This is broken -- should have many more results available! -echo Enough results: $((results >= 6*RUN_LIMIT/10)) | tee -a $TEST_RESULTS +echo Enough results: $((results >= 5*RUN_LIMIT/10)) | tee -a $TEST_RESULTS # $timeouts should strictly equal $NUM_TIMEOUT_DEVICES when dhcp step is fixed. echo Enough DHCP timeouts: $((timeouts >= NUM_TIMEOUT_DEVICES)) | tee -a $TEST_RESULTS echo Enough static ips: $((static_ips >= (NUM_NO_DHCP_DEVICES - NUM_TIMEOUT_DEVICES))) | tee -a $TEST_RESULTS -echo Enough port toggle tests: $((port_toggles >= (NUM_PORT_TOGGLE_DHCP_TEST_DEVICES - NUM_PORT_TOGGLE_DHCP_TEST_TIMEOUT_DEVICES) )) | tee -a $TEST_RESULTS -echo Enough port toggle timeouts: $((port_toggle_timeouts >= NUM_PORT_TOGGLE_DHCP_TEST_TIMEOUT_DEVICES)) | tee -a $TEST_RESULTS +echo Enough ipaddr tests: $((ip_notifications >= (NUM_IPADDR_TEST_DEVICES - NUM_IPADDR_TEST_TIMEOUT_DEVICES) )) | tee -a $TEST_RESULTS +echo Enough ipaddr timeouts: $((ipaddr_timeouts >= NUM_IPADDR_TEST_TIMEOUT_DEVICES)) | tee -a $TEST_RESULTS echo bin/combine_reports device=9a:02:57:1e:8f:05 from_time=$start_time to_time=$end_time count=2 bin/combine_reports device=9a:02:57:1e:8f:05 from_time=$start_time to_time=$end_time count=2 From ff20a21fa7cc9bf7bbb1160a8ec870c87ff99d05 Mon Sep 17 00:00:00 2001 From: Trevor Date: Wed, 15 Jul 2020 20:07:15 -0700 Subject: [PATCH 022/212] Remove old python2 components (#537) --- bin/setup_dev | 4 ---- 1 file changed, 4 deletions(-) diff --git a/bin/setup_dev b/bin/setup_dev index 59eb0f6df3..c39518dc96 100755 --- a/bin/setup_dev +++ b/bin/setup_dev @@ -75,10 +75,6 @@ $AG install \ python$PVERSION python3-pkg-resources python3-setuptools \ python$PVERSION-dev python3-pip python emacs-nox python$PVERSION-venv -# Jump through some hoops for mininet, which still has some python2 deps. -$AG install python-pip -python2 -m pip install setuptools - if [ -d mininet ]; then echo Checking mininet version matches $MININETV... targetrev=$(cd mininet; git rev-parse $MININETV) From 02e4cc8789e3ce5b024076fa705a6ab9bc174f9f Mon Sep 17 00:00:00 2001 From: henry54809 Date: Thu, 16 Jul 2020 15:30:05 -0700 Subject: [PATCH 023/212] Additional DHCP test part 2. Multisubnet test (#539) --- config/modules/host.conf | 4 +- daq/gateway.py | 6 ++- daq/host.py | 7 ++-- daq/ipaddr_test.py | 38 +++++++++++++------ .../networking_scripts/change_dhcp_range | 24 ++++++++++++ .../networking_scripts/change_lease_time | 4 +- docs/device_report.md | 11 ------ resources/setups/baseline/module_config.json | 7 ++-- testing/test_aux.out | 25 ++++++++---- testing/test_aux.sh | 2 +- testing/test_base.out | 11 ------ testing/test_many.out | 1 + testing/test_many.sh | 5 ++- 13 files changed, 92 insertions(+), 53 deletions(-) create mode 100755 docker/include/networking_scripts/change_dhcp_range diff --git a/config/modules/host.conf b/config/modules/host.conf index deda32bdd6..cd9e9421b4 100644 --- a/config/modules/host.conf +++ b/config/modules/host.conf @@ -7,7 +7,6 @@ build docker/modules add pass add fail add ping -add ipaddr add bacnet add mudgee @@ -15,5 +14,8 @@ add mudgee include subset/pentests/build.conf include usi/build.conf +# Extended dhcp tests +add ipaddr + # Example of how to remove something. remove unused diff --git a/daq/gateway.py b/daq/gateway.py index 9984dc7a6e..4ee9bc2fd1 100644 --- a/daq/gateway.py +++ b/daq/gateway.py @@ -131,9 +131,13 @@ def change_dhcp_response_time(self, mac, time): self.execute_script('change_dhcp_response_time', mac, time) def stop_dhcp_response(self, mac): - """Stops DHCP respopnse for the device""" + """Stops DHCP response for the device""" self.change_dhcp_response_time(mac, -1) + def change_dhcp_range(self, start, end, prefix_length): + """Change dhcp range for devices""" + self.execute_script('change_dhcp_range', start, end, prefix_length) + def allocate_test_port(self): """Get the test port to use for this gateway setup""" test_port = self._switch_port(self.TEST_OFFSET_START) diff --git a/daq/host.py b/daq/host.py index 5de826f8c9..50d8fe224e 100644 --- a/daq/host.py +++ b/daq/host.py @@ -211,10 +211,6 @@ def _get_static_ip(self): def _get_dhcp_mode(self): return self._loaded_config['modules'].get('ipaddr', {}).get('dhcp_mode', 'normal') - def _get_dhcp_tests(self): - tests = self._loaded_config['modules'].get('ipaddr', {}).get('dhcp_tests', {}).keys() - return list(filter(self._test_enabled, tests)) - def _get_unique_upload_path(self, file_name): base = os.path.basename(file_name) partial = os.path.join('tests', self.test_name, base) if self.test_name else base @@ -448,6 +444,9 @@ def ip_notify(self, target_ip, state=MODE.DONE, delta_sec=-1): self._all_ips.append({"ip": target_ip, "timestamp": time.time()}) if self._get_dhcp_mode() == "ip_change" and len(self._all_ips) == 1: self.gateway.request_new_ip(self.target_mac) + # Update ip directly if it's already triggered. + if self.target_ip: + self.target_ip = target_ip if self.test_host: self.test_host.ip_listener(target_ip) diff --git a/daq/ipaddr_test.py b/daq/ipaddr_test.py index 6bf29fafe2..b56948d9e8 100644 --- a/daq/ipaddr_test.py +++ b/daq/ipaddr_test.py @@ -3,6 +3,7 @@ from __future__ import absolute_import import time import os +import copy import logger LOGGER = logger.get_logger('ipaddr') @@ -11,22 +12,23 @@ class IpAddrTest: """Module for inline ipaddr tests""" - DEFAULT_WAIT_SEC = 10 - # pylint: disable=too-many-arguments def __init__(self, host, target_port, tmpdir, test_name, module_config): self.host = host self.target_port = target_port self.tmpdir = tmpdir self.test_config = module_config.get('modules').get('ipaddr') + self.test_dhcp_ranges = copy.copy(self.test_config.get('dhcp_ranges', [])) self.test_name = test_name self.host_name = '%s%02d' % (test_name, self.target_port) self.log_path = os.path.join(self.tmpdir, 'nodes', self.host_name, 'activate.log') self.log_file = None self.callback = None + self._ip_callback = None self.tests = [ - self._dhcp_port_toggle_test, - self._finalize + ('dhcp port_toggle test', self._dhcp_port_toggle_test), + ('dhcp multi subnet test', self._multi_subnet_test), + ('finalize', self._finalize) ] def start(self, port, params, callback, finish_hook): @@ -38,21 +40,34 @@ def start(self, port, params, callback, finish_hook): def _next_test(self): try: - self.tests.pop(0)() + name, func = self.tests.pop(0) + self.log('Running ' + name) + func() except Exception as e: + self.log(str(e)) self._finalize(exception=e) - def activate_log(self, message): + def log(self, message): """Log an activation message""" + LOGGER.info(message) self.log_file.write(message + '\n') def _dhcp_port_toggle_test(self): - self.activate_log('dhcp_port_toggle_test') if not self.host.connect_port(False): - self.activate_log('disconnect port not enabled') + self.log('disconnect port not enabled') return time.sleep(self.host.config.get("port_debounce_sec", 0) + 1) self.host.connect_port(True) + self._ip_callback = self._next_test + + def _multi_subnet_test(self): + if not self.test_dhcp_ranges: + self._next_test() + return + dhcp_range = self.test_dhcp_ranges.pop(0) + self.log('Testing dhcp range: ' + ",".join([str(arg) for arg in dhcp_range])) + self.host.gateway.change_dhcp_range(*dhcp_range) + self._ip_callback = self._multi_subnet_test if self.test_dhcp_ranges else self._next_test def _finalize(self, exception=None): self.terminate() @@ -60,11 +75,12 @@ def _finalize(self, exception=None): def terminate(self): """Terminate this set of tests""" + self.log('Module terminating') self.log_file.close() self.log_file = None def ip_listener(self, target_ip): """Respond to a ip notification event""" - self.activate_log('ip notification %s' % target_ip) - LOGGER.info("%s received ip %s" % (self.test_name, target_ip)) - self._next_test() + self.log('ip notification %s' % target_ip) + if self._ip_callback: + self._ip_callback() diff --git a/docker/include/networking_scripts/change_dhcp_range b/docker/include/networking_scripts/change_dhcp_range new file mode 100755 index 0000000000..0c45cd6bae --- /dev/null +++ b/docker/include/networking_scripts/change_dhcp_range @@ -0,0 +1,24 @@ +#!/bin/bash -e +# +# Dynamically change DHCP lease range, requires killing and restarting +# dnsmasq as per documentation (SIGHUP does not reload configuration file). +LOCAL_IF=${LOCAL_IF:-$HOSTNAME-eth0} + +range_start=$1 +range_end=$2 +prefix_len=$3 +if [ -z $range_start -o -z $range_end -o -z $prefix_len ]; then + echo "Usage: change_dhcp_range range_start range_end prefix_len" + exit 1 +fi +while [ $(cat /etc/dnsmasq.conf | egrep "^dhcp-range=" | wc -l) == 0 ]; do + sleep 1 +done +ip addr add $range_start/$prefix_len dev $LOCAL_IF || true +original=$(cat /etc/dnsmasq.conf | egrep "^dhcp-range=" | head -1) +lease=$(echo $original | cut -d',' -f 3) +if [ -n "lease" ]; then + lease=",$lease" +fi +new="dhcp-range=$range_start,$range_end$lease" +flock /etc/dnsmasq.conf sed -i s/$original/$new/ /etc/dnsmasq.conf \ No newline at end of file diff --git a/docker/include/networking_scripts/change_lease_time b/docker/include/networking_scripts/change_lease_time index 306e985604..0cb8986c8a 100755 --- a/docker/include/networking_scripts/change_lease_time +++ b/docker/include/networking_scripts/change_lease_time @@ -7,10 +7,10 @@ if [ -z $lease ]; then echo "Lease time not defined." exit 1 fi -while [ $(cat /etc/dnsmasq.conf | grep dhcp-range=10.20 | wc -l) == 0 ]; do +while [ $(cat /etc/dnsmasq.conf | grep "^dhcp-range=" | wc -l) == 0 ]; do sleep 1 done -original=$(cat /etc/dnsmasq.conf | grep dhcp-range=10.20 | head -1) +original=$(cat /etc/dnsmasq.conf | grep "^dhcp-range=" | head -1) new="$(echo $original | cut -d',' -f 1,2),$lease" flock /etc/dnsmasq.conf sed -i s/$original/$new/ /etc/dnsmasq.conf diff --git a/docs/device_report.md b/docs/device_report.md index 3cc2ac6675..4a5be26839 100644 --- a/docs/device_report.md +++ b/docs/device_report.md @@ -144,17 +144,6 @@ RESULT pass base.target.ping target reached ``` -## Module ipaddr - - -#### Module Config - -|Attribute|Value| -|---|---| -|enabled|True| -|timeout_sec|300| -|port_flap_timeout_sec|20| - ## Module nmap diff --git a/resources/setups/baseline/module_config.json b/resources/setups/baseline/module_config.json index 83eaa9a3b5..144c249ce2 100644 --- a/resources/setups/baseline/module_config.json +++ b/resources/setups/baseline/module_config.json @@ -1,9 +1,10 @@ { "modules": { "ipaddr": { - "enabled": true, - "timeout_sec": 300, - "port_flap_timeout_sec": 20 + "enabled": false, + "timeout_sec": 900, + "port_flap_timeout_sec": 20, + "dhcp_ranges": [["192.168.0.1", "192.168.255.254", 16]] }, "pass": { "enabled": true diff --git a/testing/test_aux.out b/testing/test_aux.out index cf65e1a828..b46c806282 100644 --- a/testing/test_aux.out +++ b/testing/test_aux.out @@ -94,9 +94,16 @@ port-01 module_config modules "enabled": false }, "ipaddr": { - "enabled": true, + "dhcp_ranges": [ + [ + "192.168.0.1", + "192.168.255.254", + 16 + ] + ], + "enabled": false, "port_flap_timeout_sec": 20, - "timeout_sec": 300 + "timeout_sec": 900 }, "macoui": { "enabled": true @@ -147,9 +154,16 @@ port-02 module_config modules "enabled": true }, "ipaddr": { - "enabled": true, + "dhcp_ranges": [ + [ + "192.168.0.1", + "192.168.255.254", + 16 + ] + ], + "enabled": false, "port_flap_timeout_sec": 20, - "timeout_sec": 300 + "timeout_sec": 900 }, "macoui": { "enabled": true, @@ -206,19 +220,16 @@ inst/gw01/nodes/gw01/activate.log inst/gw02/nodes/gw02/activate.log inst/gw03/nodes/gw03/activate.log inst/run-port-01/nodes/fail01/activate.log -inst/run-port-01/nodes/ipaddr01/activate.log inst/run-port-01/nodes/nmap01/activate.log inst/run-port-01/nodes/pass01/activate.log inst/run-port-01/nodes/ping01/activate.log inst/run-port-02/nodes/fail02/activate.log inst/run-port-02/nodes/hold02/activate.log -inst/run-port-02/nodes/ipaddr02/activate.log inst/run-port-02/nodes/nmap02/activate.log inst/run-port-02/nodes/pass02/activate.log inst/run-port-02/nodes/ping02/activate.log inst/run-port-03/nodes/fail03/activate.log inst/run-port-03/nodes/hold03/activate.log -inst/run-port-03/nodes/ipaddr03/activate.log inst/run-port-03/nodes/nmap03/activate.log inst/run-port-03/nodes/pass03/activate.log inst/run-port-03/nodes/ping03/activate.log diff --git a/testing/test_aux.sh b/testing/test_aux.sh index f78d30f506..23861b04b1 100755 --- a/testing/test_aux.sh +++ b/testing/test_aux.sh @@ -121,7 +121,7 @@ more inst/run-port-*/scans/ip_triggers.txt | cat dhcp_done=$(fgrep done inst/run-port-01/scans/ip_triggers.txt | wc -l) dhcp_long=$(fgrep long inst/run-port-01/scans/ip_triggers.txt | wc -l) echo dhcp requests $((dhcp_done > 1)) $((dhcp_done < 3)) \ - $((dhcp_long > 1)) $((dhcp_long < 4)) | tee -a $TEST_RESULTS + $((dhcp_long >= 1)) $((dhcp_long < 4)) | tee -a $TEST_RESULTS sort inst/result.log | tee -a $TEST_RESULTS # Show partial logs from each test diff --git a/testing/test_base.out b/testing/test_base.out index d0181c88d0..7ad42c6cce 100644 --- a/testing/test_base.out +++ b/testing/test_base.out @@ -87,17 +87,6 @@ RESULT pass base.target.ping target reached ``` -## Module ipaddr - - -#### Module Config - -|Attribute|Value| -|---|---| -|enabled|True| -|timeout_sec|300| -|port_flap_timeout_sec|20| - ## Module nmap diff --git a/testing/test_many.out b/testing/test_many.out index 3e8525aa5e..29cc0367df 100644 --- a/testing/test_many.out +++ b/testing/test_many.out @@ -5,6 +5,7 @@ Enough results: 1 Enough DHCP timeouts: 1 Enough static ips: 1 Enough ipaddr tests: 1 +Enough alternate subnet ips: 1 Enough ipaddr timeouts: 1 Redacted soak diff No soak report diff diff --git a/testing/test_many.sh b/testing/test_many.sh index 7befe66a76..c63c99a182 100755 --- a/testing/test_many.sh +++ b/testing/test_many.sh @@ -20,6 +20,7 @@ echo source config/system/default.yaml > local/system.conf echo monitor_scan_sec=5 >> local/system.conf echo switch_setup.uplink_port=$((NUM_DEVICES+1)) >> local/system.conf echo gcp_cred=$gcp_cred >> local/system.conf +echo dhcp_lease_time=120s >> local/system.conf for iface in $(seq 1 $NUM_DEVICES); do xdhcp="" @@ -86,6 +87,7 @@ results=$(fgrep [] inst/result.log | wc -l) timeouts=$(fgrep "ipaddr:TimeoutError" inst/result.log | wc -l) ipaddr_timeouts=$(fgrep "ipaddr:TimeoutError" inst/result.log | wc -l) ip_notifications=$(fgrep "ip notification" inst/run-port-*/nodes/ipaddr*/activate.log | wc -l) +alternate_subnet_ip=$(fgrep "ip notification 192.168" inst/run-port-*/nodes/ipaddr*/activate.log | wc -l) cat inst/run-port-*/scans/ip_triggers.txt static_ips=$(fgrep nope inst/run-port-*/scans/ip_triggers.txt | wc -l) @@ -103,7 +105,8 @@ echo Enough results: $((results >= 5*RUN_LIMIT/10)) | tee -a $TEST_RESULTS echo Enough DHCP timeouts: $((timeouts >= NUM_TIMEOUT_DEVICES)) | tee -a $TEST_RESULTS echo Enough static ips: $((static_ips >= (NUM_NO_DHCP_DEVICES - NUM_TIMEOUT_DEVICES))) | tee -a $TEST_RESULTS -echo Enough ipaddr tests: $((ip_notifications >= (NUM_IPADDR_TEST_DEVICES - NUM_IPADDR_TEST_TIMEOUT_DEVICES) )) | tee -a $TEST_RESULTS +echo Enough ipaddr tests: $((ip_notifications >= (NUM_IPADDR_TEST_DEVICES - NUM_IPADDR_TEST_TIMEOUT_DEVICES) * 2 )) | tee -a $TEST_RESULTS +echo Enough alternate subnet ips: $((alternate_subnet_ip >= (NUM_IPADDR_TEST_DEVICES - NUM_IPADDR_TEST_TIMEOUT_DEVICES) )) | tee -a $TEST_RESULTS echo Enough ipaddr timeouts: $((ipaddr_timeouts >= NUM_IPADDR_TEST_TIMEOUT_DEVICES)) | tee -a $TEST_RESULTS echo bin/combine_reports device=9a:02:57:1e:8f:05 from_time=$start_time to_time=$end_time count=2 From adb4c254e1fdfc1fc060321821766071bd1ca34e Mon Sep 17 00:00:00 2001 From: pbatta Date: Thu, 16 Jul 2020 23:55:41 -0700 Subject: [PATCH 024/212] Use multiple NTP requests and the monitor pcap capture, to reduce flakiness in NTP tests (#541) --- docker/include/bin/start_faux | 20 +++++++++++++------- docker/include/bin/test_ping | 4 ++-- testing/test_aux.sh | 2 +- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/docker/include/bin/start_faux b/docker/include/bin/start_faux index 15c85bbf4e..bb80df1507 100755 --- a/docker/include/bin/start_faux +++ b/docker/include/bin/start_faux @@ -138,13 +138,19 @@ fi # Queries the NTP server learnt from DHCP. if [ -n "${options[ntpv4]}" ]; then - dhcp_ntp=$(fgrep NTPSERVERS= /run/ntpdate.dhcp) - ntp_server=`echo $dhcp_ntp | cut -d "'" -f 2` - echo Transmitting NTP query to $ntp_server using NTPv4 - ntpdate -q -o 4 $ntp_server & + (while date; do + dhcp_ntp=$(fgrep NTPSERVERS= /run/ntpdate.dhcp) + ntp_server=`echo $dhcp_ntp | cut -d "'" -f 2` + echo Transmitting NTP query to $ntp_server using NTPv4 + ntpdate -q -o 4 $ntp_server + sleep 5 + done) & elif [ -n "${options[ntpv3]}" ]; then - echo Transmitting NTP query to time.google.com using NTPv3 - ntpdate -q -o 3 time.google.com & + (while date; do + echo Transmitting NTP query to time.google.com using NTPv3 + ntpdate -q -o 3 time.google.com + sleep 5 + done) & fi # ntp_pass queries the NTP server learnt from DHCP. ntp_fail sends to time.google.com @@ -161,7 +167,7 @@ if [ -n "${options[ntp_pass]}" -o -n "${options[ntp_fail]}" ]; then fi echo Transmitting NTP query to $ntp_server ntpdate -q -p 1 $ntp_server - sleep 10 + sleep 5 done) & fi diff --git a/docker/include/bin/test_ping b/docker/include/bin/test_ping index 99bc957d83..b66393a079 100755 --- a/docker/include/bin/test_ping +++ b/docker/include/bin/test_ping @@ -88,8 +88,8 @@ echo Done with basic connectivity tests | tee -a $MONO_LOG echo Checking startup NTP ntp_target=${TARGET_IP%.*}.2 -ntp_request=`tcpdump -env -c 1 -r /scans/startup.pcap dst port 123 | wc -l` -ntp_proper=`tcpdump -env -c 1 -r /scans/startup.pcap dst port 123 and dst host $ntp_target | wc -l` +ntp_request=`tcpdump -env -c 1 -r /scans/monitor.pcap dst port 123 | wc -l` +ntp_proper=`tcpdump -env -c 1 -r /scans/monitor.pcap dst port 123 and dst host $ntp_target | wc -l` if [ "$ntp_request" == 0 ]; then ntp_result=skip ntp_summary="No NTP traffic detected" diff --git a/testing/test_aux.sh b/testing/test_aux.sh index 23861b04b1..edc08f149e 100755 --- a/testing/test_aux.sh +++ b/testing/test_aux.sh @@ -68,7 +68,7 @@ interfaces: faux-3: opts: tls macoui passwordpass bacnet pubber broadcast_client long_dhcp_response_sec: 0 -monitor_scan_sec: 0 +monitor_scan_sec: 20 EOF if [ -f "$gcp_cred" ]; then From b2bfed74c46a1ec377d40b4b876de789ef64b794 Mon Sep 17 00:00:00 2001 From: Trevor Date: Fri, 17 Jul 2020 18:22:24 -0700 Subject: [PATCH 025/212] Disable GCP combine check (#542) --- testing/test_many.gcp | 4 ---- testing/test_many.sh | 3 ++- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/testing/test_many.gcp b/testing/test_many.gcp index b24657de64..eccaaa37a2 100644 --- a/testing/test_many.gcp +++ b/testing/test_many.gcp @@ -1,6 +1,2 @@ Running testing/test_many.sh GCP results diff -5c5 -< Source: gcp ---- -> Source: local diff --git a/testing/test_many.sh b/testing/test_many.sh index c63c99a182..3dd796452b 100755 --- a/testing/test_many.sh +++ b/testing/test_many.sh @@ -126,7 +126,8 @@ if [ -f "$gcp_cred" ]; then bin/combine_reports device=9a:02:57:1e:8f:05 from_time=$start_time to_time=$end_time \ count=2 from_gcp=true echo GCP results diff | tee -a $GCP_RESULTS - diff inst/reports/combo_*.md out/report_local.md | tee -a $GCP_RESULTS + # TODO: Re-enable as per b/161529445 + # diff inst/reports/combo_*.md out/report_local.md | tee -a $GCP_RESULTS fi echo Done with many | tee -a $TEST_RESULTS From 98480217fc376c83aca0a5728b3b98a49e2597f7 Mon Sep 17 00:00:00 2001 From: henry54809 Date: Fri, 17 Jul 2020 18:39:19 -0700 Subject: [PATCH 026/212] Additional DHCP test part 3. Ip change test (#543) --- daq/host.py | 10 +--------- daq/ipaddr_test.py | 5 +++++ testing/test_dhcp.out | 5 ++++- testing/test_dhcp.sh | 40 ++++++++++++++++++++++++++++++++-------- 4 files changed, 42 insertions(+), 18 deletions(-) diff --git a/daq/host.py b/daq/host.py index 50d8fe224e..ee1e1a7e21 100644 --- a/daq/host.py +++ b/daq/host.py @@ -54,12 +54,6 @@ def pre_states(): """Return pre-test states for basic operation""" return ['startup', 'sanity', 'acquire', 'base', 'monitor'] - -def dhcp_tests(): - """Returns all supported dhcp tests""" - return ['port_toggle', 'multi_subnet', 'ip_change'] - - def post_states(): """Return post-test states for recording finalization""" return ['finish', 'info', 'timer'] @@ -282,7 +276,7 @@ def _start_run(self): self._startup_scan() def _mark_skipped_tests(self): - for test in self.config['test_list'] + dhcp_tests(): + for test in self.config['test_list']: if not self._test_enabled(test): self._record_result(test, state=MODE.NOPE) @@ -442,8 +436,6 @@ def ip_notify(self, target_ip, state=MODE.DONE, delta_sec=-1): with open(self._trigger_path, 'a') as output_stream: output_stream.write('%s %s %d\n' % (target_ip, state, delta_sec)) self._all_ips.append({"ip": target_ip, "timestamp": time.time()}) - if self._get_dhcp_mode() == "ip_change" and len(self._all_ips) == 1: - self.gateway.request_new_ip(self.target_mac) # Update ip directly if it's already triggered. if self.target_ip: self.target_ip = target_ip diff --git a/daq/ipaddr_test.py b/daq/ipaddr_test.py index b56948d9e8..451192f75d 100644 --- a/daq/ipaddr_test.py +++ b/daq/ipaddr_test.py @@ -28,6 +28,7 @@ def __init__(self, host, target_port, tmpdir, test_name, module_config): self.tests = [ ('dhcp port_toggle test', self._dhcp_port_toggle_test), ('dhcp multi subnet test', self._multi_subnet_test), + ('ip change test', self._ip_change_test), ('finalize', self._finalize) ] @@ -69,6 +70,10 @@ def _multi_subnet_test(self): self.host.gateway.change_dhcp_range(*dhcp_range) self._ip_callback = self._multi_subnet_test if self.test_dhcp_ranges else self._next_test + def _ip_change_test(self): + self.host.gateway.request_new_ip(self.host.target_mac) + self._ip_callback = self._next_test + def _finalize(self, exception=None): self.terminate() self.callback(exception=exception) diff --git a/testing/test_dhcp.out b/testing/test_dhcp.out index e7bf981faa..31148ca8b6 100644 --- a/testing/test_dhcp.out +++ b/testing/test_dhcp.out @@ -4,9 +4,12 @@ DHCP Tests 02: ['02:acquire:TimeoutError'] 03: [] 04: [] +05: [] Device 1 ip triggers: 1 0 Device 2 ip triggers: 0 0 Device 3 long ip triggers: 1 Device 4 ip triggers: 1 -Number of ips: 2 +Device 4 subnet 1 ip: 1 subnet 2 ip: 1 subnet 3 ip: 2 +Device 5 ip triggers: 1 +Device 5 num of ips: 2 Done with tests diff --git a/testing/test_dhcp.sh b/testing/test_dhcp.sh index c979de2a98..791b091669 100755 --- a/testing/test_dhcp.sh +++ b/testing/test_dhcp.sh @@ -7,11 +7,12 @@ echo DHCP Tests >> $TEST_RESULTS cat < local/system.conf source config/system/default.yaml site_description="Multi-Device Configuration" -switch_setup.uplink_port=5 +switch_setup.uplink_port=6 interfaces.faux-1.opts= interfaces.faux-2.opts=xdhcp interfaces.faux-3.opts= interfaces.faux-4.opts= +interfaces.faux-5.opts= monitor_scan_sec=1 EOF @@ -29,14 +30,31 @@ cat < local/site/mac_addrs/$intf_mac/module_config.json } EOF +# Multi subnet multi subnet tests intf_mac="9a02571e8f04" mkdir -p local/site/mac_addrs/$intf_mac cat < local/site/mac_addrs/$intf_mac/module_config.json { "modules": { "ipaddr": { - "timeout_sec": 320, - "dhcp_mode": "ip_change" + "enabled": true, + "port_flap_timeout_sec": 20, + "dhcp_ranges": [["192.168.0.1", "192.168.255.254", 16], ["10.255.255.1", "10.255.255.255", 24], ["172.16.0.1", "172.16.0.200", 24]] + } + } +} +EOF + +# ip change test +intf_mac="9a02571e8f05" +mkdir -p local/site/mac_addrs/$intf_mac +cat < local/site/mac_addrs/$intf_mac/module_config.json +{ + "modules": { + "ipaddr": { + "enabled": true, + "port_flap_timeout_sec": 20, + "dhcp_ranges": [] } } } @@ -47,7 +65,7 @@ cmd/run -b -s settle_sec=0 dhcp_lease_time=120s cat inst/result.log | sort | tee -a $TEST_RESULTS -for iface in $(seq 1 4); do +for iface in $(seq 1 5); do intf_mac=9a:02:57:1e:8f:0$iface ip_file=inst/run-port-0$iface/scans/ip_triggers.txt cat $ip_file @@ -55,11 +73,17 @@ for iface in $(seq 1 4); do long_triggers=$(fgrep long $ip_file | wc -l) num_ips=$(cat $ip_file | cut -d ' ' -f 1 | sort | uniq | wc -l) echo Found $ip_triggers ip triggers and $long_triggers long ip responses. - if [ $iface == 4 ]; then - echo "Device $iface ip triggers: $(((ip_triggers + long_triggers) >= 2))" | tee -a $TEST_RESULTS - echo "Number of ips: $num_ips" | tee -a $TEST_RESULTS + if [ $iface == 5 ]; then + echo "Device $iface ip triggers: $(((ip_triggers + long_triggers) >= 3))" | tee -a $TEST_RESULTS + echo "Device $iface num of ips: $num_ips" | tee -a $TEST_RESULTS + elif [ $iface == 4 ]; then + echo "Device $iface ip triggers: $(((ip_triggers + long_triggers) >= 4))" | tee -a $TEST_RESULTS + subnet_ip=$(fgrep "ip notification 192.168" inst/run-port-*/nodes/ipaddr*/activate.log | wc -l) + subnet2_ip=$(fgrep "ip notification 10.255.255" inst/run-port-*/nodes/ipaddr*/activate.log | wc -l) + subnet3_ip=$(fgrep "ip notification 172.16.0" inst/run-port-*/nodes/ipaddr*/activate.log | wc -l) + echo "Device $iface subnet 1 ip: $subnet_ip subnet 2 ip: $subnet2_ip subnet 3 ip: $subnet3_ip" | tee -a $TEST_RESULTS elif [ $iface == 3 ]; then - echo "Device $iface long ip triggers: $((long_triggers > 0))" | tee -a $TEST_RESULTS + echo "Device $iface long ip triggers: $((long_triggers > 0))" | tee -a $TEST_RESULTS else echo "Device $iface ip triggers: $((ip_triggers > 0)) $((long_triggers > 0))" | tee -a $TEST_RESULTS fi From 1eaaffd9846d202ac543e53bce78e35b6df68ee9 Mon Sep 17 00:00:00 2001 From: henry54809 Date: Mon, 20 Jul 2020 08:51:11 -0700 Subject: [PATCH 027/212] USI cisco9300 fix (#545) --- .../java/daq/usi/SwitchTelnetClientSocket.java | 2 +- .../java/daq/usi/allied/AlliedTelesisX230.java | 8 ++++---- usi/src/main/java/daq/usi/cisco/Cisco9300.java | 10 +++++----- .../java/daq/usi/BaseSwitchControllerTest.java | 15 +++++++++++++++ .../test/java/daq/usi/ovs/OpenVSwitchTest.java | 4 ++-- 5 files changed, 27 insertions(+), 12 deletions(-) diff --git a/usi/src/main/java/daq/usi/SwitchTelnetClientSocket.java b/usi/src/main/java/daq/usi/SwitchTelnetClientSocket.java index a8349ff8a1..0530f44022 100644 --- a/usi/src/main/java/daq/usi/SwitchTelnetClientSocket.java +++ b/usi/src/main/java/daq/usi/SwitchTelnetClientSocket.java @@ -129,7 +129,7 @@ protected void gatherData() { } rxTemp = rxTemp.replace(MORE_INDICATOR, ""); rxData.append(rxTemp); - } else if (interrogator.userAuthorised + } else if ((interrogator.userAuthorised && interrogator.userEnabled) && !interrogator.promptReady((rxData.toString() + rxTemp).trim())) { rxData.append(rxTemp); if (debug) { diff --git a/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java b/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java index 50007a2086..1b36d26fab 100644 --- a/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java +++ b/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java @@ -115,11 +115,11 @@ public void getPower(int devicePort, ResponseHandler handler) thr synchronized (this) { commandPending = true; responseHandler = data -> { - Map powerMap = processPowerStatusInline(data); - handler.receiveData(buildPowerResponse(powerMap)); synchronized (this) { commandPending = false; } + Map powerMap = processPowerStatusInline(data); + handler.receiveData(buildPowerResponse(powerMap)); }; telnetClientSocket.writeData(command + "\n"); } @@ -135,11 +135,11 @@ public void getInterface(int devicePort, ResponseHandler hand synchronized (this) { commandPending = true; responseHandler = data -> { - Map interfaceMap = processInterfaceStatus(data); - handler.receiveData(buildInterfaceResponse(interfaceMap)); synchronized (this) { commandPending = false; } + Map interfaceMap = processInterfaceStatus(data); + handler.receiveData(buildInterfaceResponse(interfaceMap)); }; telnetClientSocket.writeData(command + "\n"); } diff --git a/usi/src/main/java/daq/usi/cisco/Cisco9300.java b/usi/src/main/java/daq/usi/cisco/Cisco9300.java index 1dd3683e6c..b63ae64285 100644 --- a/usi/src/main/java/daq/usi/cisco/Cisco9300.java +++ b/usi/src/main/java/daq/usi/cisco/Cisco9300.java @@ -77,7 +77,7 @@ private String showIfacePowerStatusCommand(int interfacePort) { private String[] portManagementCommand(int interfacePort, boolean enabled) { return new String[] { "configure terminal", - "interface FastEthernet0/" + interfacePort, + "interface gigabitethernet1/0/" + interfacePort, (enabled ? "no " : "") + "shutdown", "end" }; @@ -148,11 +148,11 @@ public void getPower(int devicePort, ResponseHandler powerRespons synchronized (this) { commandPending = true; responseHandler = data -> { - Map powerMap = processPowerStatusInline(data); - powerResponseHandler.receiveData(buildPowerResponse(powerMap)); synchronized (this) { commandPending = false; } + Map powerMap = processPowerStatusInline(data); + powerResponseHandler.receiveData(buildPowerResponse(powerMap)); }; telnetClientSocket.writeData(command + "\n"); } @@ -168,11 +168,11 @@ public void getInterface(int devicePort, ResponseHandler hand synchronized (this) { commandPending = true; responseHandler = data -> { - Map interfaceMap = processInterfaceStatus(data); - handler.receiveData(buildInterfaceResponse(interfaceMap)); synchronized (this) { commandPending = false; } + Map interfaceMap = processInterfaceStatus(data); + handler.receiveData(buildInterfaceResponse(interfaceMap)); }; telnetClientSocket.writeData(command + "\n"); } diff --git a/usi/src/test/java/daq/usi/BaseSwitchControllerTest.java b/usi/src/test/java/daq/usi/BaseSwitchControllerTest.java index f2867c1b65..03a3ce8505 100644 --- a/usi/src/test/java/daq/usi/BaseSwitchControllerTest.java +++ b/usi/src/test/java/daq/usi/BaseSwitchControllerTest.java @@ -44,4 +44,19 @@ void mapSimpleTableSampleInputAT() { } } + @Test + void mapSimpleTableSampleInputCisco9300() { + String raw = "Port         Name               Status       Vlan       Duplex  Speed Type\n" + + "Gi1/0/1                         connected    routed     a-full  a-100 10/100/1000BaseTX"; + String[] colNames = {"Port", "Name", "Status", "Vlan", "Duplex", "Speed", "Type"}; + String[] mapNames = {"interface", "name", "status", "vlan", "duplex", "speed", "type"}; + Map expected = Map.of("interface", "Gi1/0/1", "name", "", "status", + "Connected", "vlan", "routed", "Duplex", "a-full", "speed", "a-100", + "type", "10/100/1000BaseTX"); + Map response = BaseSwitchController.mapSimpleTable(raw, colNames, mapNames); + System.out.println(response); + for (String key : response.keySet()) { + assertEquals(response.get(key), expected.get(key)); + } + } } \ No newline at end of file diff --git a/usi/src/test/java/daq/usi/ovs/OpenVSwitchTest.java b/usi/src/test/java/daq/usi/ovs/OpenVSwitchTest.java index fb951cf29f..9a123a7c82 100644 --- a/usi/src/test/java/daq/usi/ovs/OpenVSwitchTest.java +++ b/usi/src/test/java/daq/usi/ovs/OpenVSwitchTest.java @@ -2,7 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -import java.io.FileNotFoundException; +import java.io.IOException; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -20,7 +20,7 @@ void tearDown() { } @Test - void getInterfaceByPort() throws FileNotFoundException { + void getInterfaceByPort() throws IOException { assertEquals(ovs.getInterfaceByPort(1), "faux"); assertEquals(ovs.getInterfaceByPort(2), "faux-2"); assertEquals(ovs.getInterfaceByPort(7), "sec-eth7"); From e77a6e8950e4547d738ba4edd565f8fddeaaa27c Mon Sep 17 00:00:00 2001 From: Trevor Date: Mon, 20 Jul 2020 09:48:21 -0700 Subject: [PATCH 028/212] Refactor UDMI to external repo (#544) --- .gitignore | 1 + bin/registrar | 30 --- bin/setup_dev | 27 ++- bin/validate | 33 ---- docker/include/bin/start_faux | 8 +- docker/modules/Dockerfile.faux1 | 4 +- docs/pubber.md | 81 -------- docs/registrar.md | 182 ------------------ docs/validator.md | 152 --------------- etc/MININET_VERSION | 1 + etc/UDMI_VERSION | 1 + firebase/functions/package.json | 2 +- .../test_site/devices/AHU-1/metadata.json | 6 +- subset/cloud/Dockerfile.test_udmi | 6 +- subset/cloud/test_udmi | 8 +- testing/test_aux.gcp | 14 +- testing/test_aux.sh | 3 +- testing/test_topo.out | 1 - testing/test_topo.sh | 5 - 19 files changed, 56 insertions(+), 509 deletions(-) delete mode 100755 bin/registrar delete mode 100755 bin/validate delete mode 100644 docs/pubber.md delete mode 100644 docs/registrar.md delete mode 100644 docs/validator.md create mode 100644 etc/MININET_VERSION create mode 100644 etc/UDMI_VERSION diff --git a/.gitignore b/.gitignore index 5e280a7725..0ee48512c9 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ validations/ /inst/ /faucet/ /forch/ +/udmi/ /mininet/ /local/ /firebase/.firebaserc diff --git a/bin/registrar b/bin/registrar deleted file mode 100755 index 3f941ba188..0000000000 --- a/bin/registrar +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash -e - -ROOT=$(realpath $(dirname $0)/..) -cd $ROOT - -if [ $# != 1 ]; then - echo $0 [project_id] - false -fi -project_id=$1 -shift - -source etc/config_base.sh - -if [ -z "$site_path" ]; then - echo Need to define [site_path] config variable. - false -fi - -if [ -z "$schema_path" ]; then - echo Need to define [schema_path] config variable. - false -fi - -echo Building validator... -validator/bin/build > /dev/null - -echo Running tools version `git describe` - -validator/bin/registrar $project_id $site_path $schema_path $* 2>&1 diff --git a/bin/setup_dev b/bin/setup_dev index c39518dc96..65c9441987 100755 --- a/bin/setup_dev +++ b/bin/setup_dev @@ -20,8 +20,13 @@ FORCHB=${DAQ_FORCH_BRANCH} FORCHX=$(cat etc/FORCH_VERSION) FORCHV=${DAQ_FORCH_VER:-$FORCHX} +UDMIR=${DAQ_UDMI_REPO:-https://github.com/faucetsdn/udmi} +UDMIB=${DAQ_UDMI_BRANCH} +UDMIX=$(cat etc/UDMI_VERSION) +UDMIV=${DAQ_UDMI_VER:-$UDMIX} + MININET=https://github.com/mininet/mininet -MININETV=2.3.0d6 +MININETV=$(cat etc/MININET_VERSION) if [ -f .daq.local ]; then echo Loading config from .daq.local @@ -36,6 +41,10 @@ if [ "$FORCHX" != "$FORCHV" ]; then echo $FORCHV > etc/FORCH_VERSION fi +if [ "$UDMIX" != "$UDMIV" ]; then + echo $UDMIV > etc/UDMI_VERSION +fi + if [ -z "$AG" ]; then AG="sudo apt-get -qqy --no-install-recommends" fi @@ -164,6 +173,18 @@ else (cd forch; git fetch; git checkout $FORCHV) fi +if [ -z "$UDMIV" ]; then + echo No udmi version found, skipping. +else + if [ ! -d udmi ]; then + echo Cloning $UDMIR... + git clone $UDMIR udmi + fi + + echo Setting udmi version $UDMIV + (cd udmi; git fetch; git checkout $UDMIV) +fi + echo -n "DAQ commit " git log -n 1 --pretty=format:"%h - %an, %ar : %s" || true echo @@ -176,6 +197,10 @@ echo -n "Last FORCH commit " (cd forch; git log -n 1 --pretty=format:"%h - %an, %ar : %s" || true) echo +echo -n "Last UDMI commit " +(cd udmi; git log -n 1 --pretty=format:"%h - %an, %ar : %s" || true) +echo + docker --version if ! docker images > /dev/null; then diff --git a/bin/validate b/bin/validate deleted file mode 100755 index 9789659c11..0000000000 --- a/bin/validate +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -e - -ROOT=$(realpath $(dirname $0)/..) -cd $ROOT - -source etc/config_base.sh - -if [ -z "$gcp_cred" ]; then - echo Please make sure gcp_cred is defined in local/system.conf - false -fi - -if [ -z "$gcp_topic" ]; then - echo Please make sure gcp_topic is defined in local/system.conf - false -fi - -if [ -z "$schema_path" ]; then - echo Please make sure schema_path is defined in local/system.conf - false -fi - -echo Building validator... -validator/bin/build > /dev/null - -echo Configured topic is $gcp_topic -echo Configured schema is $schema_path -echo Configured site path is $site_path -echo - -echo Running tools version `git describe` - -validator/bin/validate $schema_path pubsub:$gcp_topic dev $site_path diff --git a/docker/include/bin/start_faux b/docker/include/bin/start_faux index bb80df1507..911ef72415 100755 --- a/docker/include/bin/start_faux +++ b/docker/include/bin/start_faux @@ -213,10 +213,10 @@ fi if [ -n "${options[pubber]}" ]; then echo Running cloud pubber tool... (while date; do - pubber/bin/run - # Do https query in case pubber is not configured, for testing port 443 - curl -o /dev/null https://google.com - sleep 30 + pubber/bin/run local/pubber.json + # Do https query in case pubber is not configured, for testing port 443 + curl -o /dev/null https://google.com + sleep 30 done) & fi diff --git a/docker/modules/Dockerfile.faux1 b/docker/modules/Dockerfile.faux1 index 7c8e9c0be0..5789e8beb5 100644 --- a/docker/modules/Dockerfile.faux1 +++ b/docker/modules/Dockerfile.faux1 @@ -15,7 +15,7 @@ ENV BACHASH=94a794a756ee0d37c6a2e53e08747ee021415aa8 RUN bin/retry_cmd git clone https://github.com/grafnu/bacnet4j.git --single-branch \ && cd bacnet4j && git reset --hard $BACHASH && ../bin/retry_cmd ./gradlew shadow -COPY pubber/ pubber/ +COPY udmi/pubber/ pubber/ RUN pubber/bin/build FROM daqf/aardvark:latest @@ -42,7 +42,7 @@ COPY --from=java_build /root/bacnet4j/*.jar bacnet4j/ COPY docker/include/bin/bacnet_discover bin/ COPY --from=java_build /root/pubber/build/libs/*.jar pubber/build/libs/ -COPY pubber/bin/run pubber/bin/ +COPY udmi/pubber/bin/run pubber/bin/ COPY subset/pentests/brute_server.py pentests/ COPY subset/security/tlsfaux tlsfaux/ diff --git a/docs/pubber.md b/docs/pubber.md deleted file mode 100644 index 588396d1ac..0000000000 --- a/docs/pubber.md +++ /dev/null @@ -1,81 +0,0 @@ -# Pubber Reference Client - -The _Pubber_ reference client is a sample implementation of a client-side 'device' that implements -the [UDMI Schema](../schemas/udmi/README.md). It's not intended to be any sort of production-worthy -code or library, rather just a proof-of-concept of what needs to happen. - -## Build Pubber - -
    -~/daq$ pubber/bin/build
    -Running in /home/peringknife/daq/pubber
    -
    -> Task :compileJava
    -…
    -
    -BUILD SUCCESSFUL in 2s
    -2 actionable tasks: 1 executed, 1 up-to-date
    -
    - -## Key Generation - -
    -~/daq$ pubber/bin/keygen
    -Generating a 2048 bit RSA private key
    -............+++
    -......................................+++
    -writing new private key to 'local/rsa_private.pem'
    ------
    -~/daq$ ls -l local/rsa_*
    --rw-r--r-- 1 user primarygroup 1094 Nov 19 18:56 local/rsa_cert.pem
    --rw------- 1 user primarygroup 1704 Nov 19 18:56 local/rsa_private.pem
    --rw-r--r-- 1 user primarygroup 1216 Nov 19 18:56 local/rsa_private.pkcs8
    -
    - -After generating the key pair, you'll have to upload/associate the `pubber_cert.pem` public certificate -with the device entry in the cloud console as an _RS256_cert_. (This can be done when the device is -created, or anytime after.) - -## Configuration - -The `local/pubber.json` file configures the key cloud parameters needed for operation -(the actual values in the file shold match your GCP setup): -
    -~/daq$ cat local/pubber.json
    -{
    -  "projectId": "gcp-account",
    -  "cloudRegion": "us-central1",
    -  "registryId": "sensor_hub",
    -  "deviceId": "AHU-1"
    -}
    -
    - -## Operation - -
    -~/daq$ pubber/bin/run
    -[main] INFO daq.pubber.Pubber - Reading configuration from /home/user/daq/local/pubber.json
    -[main] INFO daq.pubber.Pubber - Starting instance for registry sensor_hub
    -[main] INFO daq.pubber.MqttPublisher - Creating new publisher-client for GAT-001
    -[main] INFO daq.pubber.MqttPublisher - Attempting connection to sensor_hub:GAT-001
    -[MQTT Call: projects/gcp-account/locations/us-central1/registries/sensor_hub/devices/GAT-001] INFO daq.pubber.Pubber - Received new config daq.udmi.Message$Config@209307c7
    -[MQTT Call: projects/gcp-account/locations/us-central1/registries/sensor_hub/devices/GAT-001] INFO daq.pubber.Pubber - Starting executor with send message delay 2000
    -[main] INFO daq.pubber.Pubber - synchronized start config result true
    -[MQTT Call: projects/gcp-account/locations/us-central1/registries/sensor_hub/devices/GAT-001] INFO daq.pubber.Pubber - Sending state message for device GAT-001
    -…
    -[pool-1-thread-1] INFO daq.pubber.Pubber - Sending test message for sensor_hub/GAT-001
    -[pool-1-thread-1] INFO daq.pubber.Pubber - Sending test message for sensor_hub/GAT-001
    -
    - - -## Cloud Setup - -To use Pubber, there needs to be a cloud-side device entry configured in a GCP project configured to -use [Cloud IoT](https://cloud.google.com/iot/docs/). The -[Creating or Editing a Device](https://cloud.google.com/iot/docs/how-tos/devices#creating_or_editing_a_device) -section of the documentation describe how to create a simple device and key-pair (see next section for -a helper script). You can/should substitute the relevant values in the configuration below for your -specific setup. The relevant bits of configuration are the information in the local/pubber.json -file (see above), and the generated public key (also see above). - -Alternatively, you can use the [registrar tool](registrar.md) to automate device registration. diff --git a/docs/registrar.md b/docs/registrar.md deleted file mode 100644 index f63dfc43c4..0000000000 --- a/docs/registrar.md +++ /dev/null @@ -1,182 +0,0 @@ -# Registrar Overview - -The `registrar` is a utility program that registers and updates devies in Cloud IoT. -Running `bin/registrar` will pull the necessary configuraiton values from `local/system.conf`, -build the executable, and register/update devices. - -## Configuration - -The `local/system.conf` file should have the following parameters (in `x=y` syntax): -* `gcp_cred`: Defines the target project and [service account](service.md) to use for configuration. -* `site_path`: [Site-specific configuration](site_path.md) for the devices that need to be registered. -* `schema_path`: Path to metadata schema (see the [DAQ PubSub documentation](pubsub.md) for more details/examples). - -The target `gcp_cred` service account will need the _Cloud IoT Provisioner_ and _Pub/Sub Publisher_ roles. -There also needs to be an existing `registrar` topic (or as configured in `cloud_iot_config.json`, below). - -## Theory Of Operation - -* The target set of _expected_ devices is determined from directory entries in -_{site_path}_/devices/. -* Existing devices that are not listed in the site config are blocked (as per -Cloud IoT device setting). -* If a device directory does not have an appropriate key, one will be automaticaly generated. -* Devices not found in the target registry are automatically created. -* Existing device registy entries are unblocked and updated with the appropriate keys. - -## Device Settings - -When registering or updating a device, the Registrar manipulates a few key pieces of device -information: -* Auth keys: Public authentiation keys for the device. -* Metadata: Various information about a device (e.g. site-code, location in the building). - -This information is sourced from a few key files: - -* `{site_dir}/cloud_iot_config.json`: -Cloud project configuration parameters (`registry_id`, `cloud_region`, etc...). -* `{site_dir}/devices/{device_id}/metadata.json`: -Device metadata (e.g. location, key type). -* `{site_dir}/devices/{device_id}/rsa_private.pem`: -Generated private key for device (used on-device). - -## Sample Output - -The produced `registration_summary.json` document provides an overview of the analyzed files, -clearly any errors that should be addressed for full spec compliance. Additionaly, an -`errors.json` - -
    -user@machine:~/daq$ cat local/site/cloud_iot_config.json 
    -{
    -  "cloud_region": "us-central1",
    -  "site_name": "SG-MBC2-B80",
    -  "registry_id": "iotRegistry",
    -  "registrar_topic": "registrar"
    -}
    -user@machine:~/daq$ bin/registrar daq-testing
    -Activating venv
    -Flattening config from local/system.yaml into inst/config/system.conf
    -Note: Some input files use or override a deprecated API.
    -Note: Recompile with -Xlint:deprecation for details.
    -Running tools version 1.5.1-16-g9ed5861
    -Using cloud project bos-daq-testing
    -Using site config dir local/site
    -Using schema root dir schemas/udmi
    -Using device filter
    -Reading Cloud IoT config from /home/user/daq/local/site/cloud_iot_config.json
    -Initializing with default credentials...
    -Jun 12, 2020 1:24:37 PM com.google.auth.oauth2.DefaultCredentialsProvider warnAboutProblematicCredentials
    -WARNING: Your application has authenticated using end user credentials from Google Cloud SDK. We recommend that most server applications use service accounts instead. If your application continues to use end user credentials from Cloud SDK, you might receive a "quota exceeded" or "API not enabled" error. For more information about service accounts, see https://cloud.google.com/docs/authentication/.
    -Created service for project bos-daq-testing
    -Working with project bos-daq-testing registry iotRegistry
    -Loading local device AHU-1-1
    -Loading local device AHU-1-2
    -Fetching remote registry iotRegistry
    -Updated device entry AHU-1-1
    -Sending metadata message for AHU-1-1
    -WARNING: An illegal reflective access operation has occurred
    -WARNING: Illegal reflective access by com.google.protobuf.UnsafeUtil (file:/home/user/daq/validator/build/libs/validator-1.0-SNAPSHOT-all.jar) to field java.nio.Buffer.address
    -WARNING: Please consider reporting this to the maintainers of com.google.protobuf.UnsafeUtil
    -WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
    -WARNING: All illegal access operations will be denied in a future release
    -Updated device entry AHU-1-2
    -Sending metadata message for AHU-1-2
    -Processed 2 devices
    -Updating local/site/devices/AHU-1-1/errors.json
    -Updating local/site/devices/AHU-1-2/errors.json
    -
    -Summary:
    -  Device Envelope: 2
    -  Device Key: 1
    -  Device Validating: 2
    -Out of 2 total.
    -Done with PubSubPusher
    -Registrar complete, exit 0
    -user@machine:~/daq$ cat local/site/registration_summary.json 
    -{
    -  "Envelope" : {
    -    "AHU-1-1" : "java.lang.IllegalStateException: Validating envelope AHU-1-1",
    -    "AHU-1-2" : "java.lang.IllegalStateException: Validating envelope AHU-1-2"
    -  },
    -  "Key" : {
    -    "AHU-1-2" : "java.lang.RuntimeException: Duplicate credentials found for AHU-1-1 & AHU-1-2"
    -  },
    -  "Validating" : {
    -    "AHU-1-1" : "org.everit.json.schema.ValidationException: #: 43 schema violations found",
    -    "AHU-1-2" : "org.everit.json.schema.ValidationException: #: 43 schema violations found"
    -  }
    -}
    -user@machine:~/daq$ head local/site/devices/AHU-1-1/errors.json 
    -Exceptions for AHU-1-1
    -  Validating envelope AHU-1-1
    -    #/deviceId: string [AHU-1-1] does not match pattern ^[A-Z]{2,6}-[1-9][0-9]{0,2}$
    -  #: 43 schema violations found
    -    #/pointset/points: 40 schema violations found
    -      #/pointset/points/chilled_return_water_temperature_sensor/units: °C is not a valid enum value
    -      #/pointset/points/chilled_supply_water_temperature_sensor/units: °C is not a valid enum value
    -      #/pointset/points/chilled_water_valve_percentage_command/units: % is not a valid enum value
    -
    - -## Sequence Diagram - -Expected workflow to configure a registry using Registrar: - -* `Device`: Target IoT Device -* `Local`: Local clone of site configuration repo -* `Registrar`: This utility program -* `Registry`: Target Cloud IoT Core registry -* `Repo`: Remote site configuration repo - -All operations are manaul except those involving the `Registrar` tool. - -
    -+---------+                +-------+                 +-----------+                 +-----------+ +-------+
    -| Device  |                | Local |                 | Registrar |                 | Registry  | | Repo  |
    -+---------+                +-------+                 +-----------+                 +-----------+ +-------+
    -     |                         |                           |                             |           |
    -     |                         |                           |                       Pull repo locally |
    -     |                         |<--------------------------------------------------------------------|
    -     |                         |    ---------------------\ |                             |           |
    -     |                         |    | Run Registrar tool |-|                             |           |
    -     |                         |    |--------------------| |                             |           |
    -     |                         |                           |                             |           |
    -     |                         | Read device configs       |                             |           |
    -     |                         |-------------------------->|                             |           |
    -     |                         |                           |                             |           |
    -     |                         |                           |            Read device list |           |
    -     |                         |                           |<----------------------------|           |
    -     |                         |                           |                             |           |
    -     |                         |           Write auth keys |                             |           |
    -     |                         |<--------------------------|                             |           |
    -     |                         |                           |                             |           |
    -     |                         |                           | Update device entries       |           |
    -     |                         |                           |---------------------------->|           |
    -     |                         |   ----------------------\ |                             |           |
    -     |                         |   | Registrar tool done |-|                             |           |
    -     |                         |   |---------------------| |                             |           |
    -     |                         |                           |                             |           |
    -     |     Install private key |                           |                             |           |
    -     |<------------------------|                           |                             |           |
    -     |                         |                           |                             |           |
    -     |                         | Push changes              |                             |           |
    -     |                         |-------------------------------------------------------------------->|
    -     |                         |                           |                             |           |
    -
    - -### Source - -Use with [ASCII Sequence Diagram Creator](https://textart.io/sequence#) - -
    -object Device Local Registrar Registry Repo
    -Repo -> Local: Pull repo locally
    -note left of Registrar: Run Registrar tool
    -Local -> Registrar: Read device configs
    -Registry -> Registrar: Read device list
    -Registrar -> Local: Write auth keys
    -Registrar -> Registry: Update device entries
    -note left of Registrar: Registrar tool done
    -Local -> Device: Install private key
    -Local -> Repo: Push changes
    -
    diff --git a/docs/validator.md b/docs/validator.md deleted file mode 100644 index 80ab8c4b24..0000000000 --- a/docs/validator.md +++ /dev/null @@ -1,152 +0,0 @@ -# Validator Setup - -The `validator` is a sub-component of DAQ that can be used to validate JSON files or stream against a schema -defined by the standard [JSON Schema](https://json-schema.org/) format. The validator does not itself specify -any policy, i.e. which schema to use when, rather just a mechanism to test and validate. - -The "schema set" is a configurable variable, and the system maps various events to different sub-schemas within -that set. Direct file-based validations run against an explicitly specified sub-schema, while the dynamic PubSub -validator dynamically chooses the sub-schema based off of message parameters. There's currently two schemas -available, defined in the `schemas/` subdirectory: -* `simple`, which is really just there to make sure the system works. -* [`UDMI`](../schemas/udmi/README.md), which is a building-oriented schema for data collection. - -## Validation Mechanisms - -There are several different ways to run the validator depending on the specific objective: -* Local File Validation -* Integration Testing -* PubSub Stream Validation - -### Local File Validation - -Local file validation runs the code against a set of local schemas and inputs. The example below shows -validating one schema file against one specific test input. -Specifying a directory, rather than a specific schema or input, will run against the entire set. -An output file is generated that has details about the schema validation result. - -
    -~/daq$ validator/bin/validate schemas/simple/simple.json schemas/simple/simple.tests/example.json
    -Executing validator schemas/simple/simple.json schemas/simple/simple.tests/example.json...
    -Running schema simple.json in /home/user/daq/schemas/simple
    -Validating example.json against simple.json
    -Validation complete, exit 0
    -~/daq$
    -
    - -### Integration Testing - -The `validator/bin/test` script runs a regression suite of all schemas against all tests. -This must pass before any PR can be approved. If there is any failure, a bunch of diagnostic -information will be included about what exactly went wrong. - -
    -~/daq/validator$ bin/test
    -
    -BUILD SUCCESSFUL in 3s
    -2 actionable tasks: 2 executed
    -
    -BUILD SUCCESSFUL in 3s
    -2 actionable tasks: 2 executed
    -Validating empty.json against config.json
    -Validating errors.json against config.json
    -
    -Validating example.json against state.json
    -Validating error.json against simple.json
    -Validating example.json against simple.json
    -
    -Done with validation.
    -
    - -### PubSub Stream Validation - -Validating a live PubSub stream requires more setup, but ultimately most closely reflects what an -actual system would be doing during operation. The [DAQ PubSub Documentation](pubsub.md) details -how to set this up. It uses the same underlying schema files as the techniques above, but routes -it though a live stream in the cloud. - -Streaming validation validates a stream of messages pulled from a GCP PubSub topic. -There are three configuration values required in the `local/system.yaml` file to make it work: -* `gcp_cred`: The service account credentials, as per the general [DAQ Firebase setup](firebase.md). -* `gcp_topic`: The _PubSub_ (not MQTT) topic name. -* `schema_path`: Indicates which schema to validate against. - -You will need to add full Project Editor permissions for the service account. -E.g., to validate messages on the `projects/gcp-account/topics/telemetry` topic, -there should be something like: - -
    -~/daq$ fgrep gcp_ local/system.conf
    -gcp_cred=local/gcp-project-ce6716521378.json
    -gcp_topic=telemetry
    -schema_path=schemas/abacab/
    -
    - -Running `bin/validate` will parse the configuration file and automatically start -verifying PubSub messages against the indicated schema. -The execution output has a link to a location in the Firestore setup -where schema results will be stored, along with a local directory of results. - -
    -~/daq$ bin/validate
    -Using credentials from /home/user/daq/local/gcp-project-ce6716521378.json
    -
    -BUILD SUCCESSFUL in 3s
    -2 actionable tasks: 2 executed
    -Executing validator /home/user/daq/validator/schemas/abacab/ pubsub:telemetry_topic...
    -Running schema . in /home/user/daq/validator/schemas/abacab
    -Ignoring subfolders []
    -Results will be uploaded to https://console.cloud.google.com/firestore/data/registries/?project=gcp-project
    -Also found in such directories as /home/user/daq/validator/schemas/abacab/out
    -Connecting to pubsub topic telemetry
    -Entering pubsub message loop on projects/gcp-project/subscriptions/daq-validator
    -Success validating out/pointset_FCU_09_INT_NE_07.json
    -Success validating out/pointset_FCU_07_EXT_SW_06.json
    -Error validating out/logentry_TCE01_01_NE_Controls.json: DeviceId TCE01_01_NE_Controls must match pattern ^([a-z][_a-z0-9-]*[a-z0-9]|[A-Z][_A-Z0-9-]*[A-Z0-9])$
    -Success validating out/logentry_FCU_01_NE_08.json
    -Error validating out/pointset_TCE01_01_NE_Controls.json: DeviceId TCE01_01_NE_Controls must match pattern ^([a-z][_a-z0-9-]*[a-z0-9]|[A-Z][_A-Z0-9-]*[A-Z0-9])$
    -Success validating out/logentry_FCU_01_SE_04.json
    -
    -
    - -## Site Validation - -Following on from individual-device validation, it is possible to validate against an entire building model -This is a WIP provisional feature. But, roughly speaking, it looks like this: - -
    -~/daq$ export GOOGLE_APPLICATION_CREDENTIALS=local/essential-monkey.json
    -~/daq$ validator/bin/validate schemas/udmi pubsub:topic dev site_model/
    -
    - -* `schemas/udmi` is the schema to validate against. -* `pubsub:topic` points to the pub-sub topic stream to validate. -* `dev` is an arbitrary designator for running different clients against the same project. -* `site_model/` is a directory containing the requisite building model. - -Output from a site validation run will be in `validations/metadata_report.json`. - -### Types and Topics - -When using the -[GCP Cloud IoT Core MQTT Bridge](https://cloud.google.com/iot/docs/how-tos/mqtt-bridge#publishing_telemetry_events) -there are multiple ways the subschema used during validation is chosen. -* All messages have their attributes validated against the `.../attributes.json` schema. These attributes are -automatically defined server-side by the MQTT Client ID and Topic, and are not explicitly included in any message payload. -* A [device event message](https://cloud.google.com/iot/docs/how-tos/mqtt-bridge#publishing_telemetry_events) -is validated against the sub-schema indicated by the MQTT topic `subFolder`. E.g., the MQTT -topic `/devices/{device-id}/events/pointset` will be validated against `.../pointset.json`. -* [Device state messages](https://cloud.google.com/iot/docs/how-tos/config/getting-state#reporting_device_state) -are validated against the `.../state.json` schema on `/devices/{device-id}/state` MQTT topic. -* (There currently is no stream validation of -[device config messages](https://cloud.google.com/iot/docs/how-tos/config/configuring-devices#mqtt), which are sent on the -`/devices/{device-id}/config` topic.) - -See this handy-dandy table: - -| Type | Category | subFolder | MQTT Topic | Schema File | -|----------|----------|-----------|----------------------------------------|---------------| -| state | state | _n/a_ | `/devices/{device_id}/state` | state.json | -| config | config | _n/a_ | `/devices/{device-id}/config` | config.json | -| pointset | event | pointset | `/devices/{device-id}/events/pointset` | pointset.json | -| logentry | event | logentry | `/devices/{device-id}/events/logentry` | logentry.json | diff --git a/etc/MININET_VERSION b/etc/MININET_VERSION new file mode 100644 index 0000000000..2357edf889 --- /dev/null +++ b/etc/MININET_VERSION @@ -0,0 +1 @@ +2.3.0d6 diff --git a/etc/UDMI_VERSION b/etc/UDMI_VERSION new file mode 100644 index 0000000000..50332690b1 --- /dev/null +++ b/etc/UDMI_VERSION @@ -0,0 +1 @@ +cdd9666f472b1e8be9e103d8f0429e7205689843 diff --git a/firebase/functions/package.json b/firebase/functions/package.json index b4eebe0523..f2d7964c9c 100644 --- a/firebase/functions/package.json +++ b/firebase/functions/package.json @@ -9,7 +9,7 @@ "logs": "firebase functions:log" }, "engines": { - "node": "8" + "node": "10" }, "dependencies": { "@google-cloud/pubsub": "2.1.0", diff --git a/resources/test_site/devices/AHU-1/metadata.json b/resources/test_site/devices/AHU-1/metadata.json index cdee5cc055..09eb5ce94d 100644 --- a/resources/test_site/devices/AHU-1/metadata.json +++ b/resources/test_site/devices/AHU-1/metadata.json @@ -1,13 +1,13 @@ { "pointset": { "points": { - "filter_alarm_pressure_status": { + "faulty_finding": { "units": "Bars" }, - "filter_differential_pressure_sensor": { + "recalcitrant_angle": { "units": "Degrees-Celsius" }, - "filter_differential_pressure_setpoint": { + "superimposition_reading": { "units": "No-units" } } diff --git a/subset/cloud/Dockerfile.test_udmi b/subset/cloud/Dockerfile.test_udmi index 220bd01ba0..e0e78a3a13 100644 --- a/subset/cloud/Dockerfile.test_udmi +++ b/subset/cloud/Dockerfile.test_udmi @@ -9,11 +9,13 @@ FROM daqf/aardvark:latest RUN $AG update && $AG install openjdk-11-jre RUN $AG update && $AG install openjdk-11-jdk git -COPY validator/ validator/ +COPY udmi/validator/ validator/ RUN validator/bin/build -COPY schemas/udmi/ schemas/udmi/ +COPY udmi/schema/ schema/ COPY subset/cloud/test_udmi . +COPY resources/test_site/ local/ + CMD ./test_udmi diff --git a/subset/cloud/test_udmi b/subset/cloud/test_udmi index aa484f5434..2edaaf82ac 100755 --- a/subset/cloud/test_udmi +++ b/subset/cloud/test_udmi @@ -15,7 +15,8 @@ ip addr gcp_cred=/config/inst/gcp_service_account.json gcp_topic=target -schema_path=schemas/udmi +schema_path=schema +subscription=daq-validator-dev message_types="state pointset system" device_id=`jq -r .device_id /config/device/module_config.json` @@ -56,15 +57,14 @@ echo Using credentials from $GOOGLE_APPLICATION_CREDENTIALS echo Extracted project $project_id echo Extracted service $service_id echo Configured topic is $gcp_topic -echo Configured schema is $schema_path echo Target device is $device_id echo -timeout 60 validator/bin/validate $PWD/$schema_path pubsub:$gcp_topic $service_id-$HOSTNAME -- || true +timeout 90 validator/bin/validate $project_id $schema_path pubsub $subscription local/ || true function message_report { message_type=$1 - base=validations/devices/$device_id/$message_type + base=out/devices/$device_id/$message_type ls -l $base* || true if [ -f "$base.out" ]; then diff --git a/testing/test_aux.gcp b/testing/test_aux.gcp index 0f08897abe..05847273db 100644 --- a/testing/test_aux.gcp +++ b/testing/test_aux.gcp @@ -7,16 +7,16 @@ Running testing/test_aux.sh "SNS-4" : "True" } } -inst/test_site/devices/AHU-1/metadata_norm.json: "hash": "ddf813e3" -inst/test_site/devices/AHU-22/metadata_norm.json: "hash": "bf82176c" -inst/test_site/devices/GAT-123/metadata_norm.json: "hash": "030193c8" -inst/test_site/devices/SNS-4/metadata_norm.json: "hash": "f701f900" +inst/test_site/devices/AHU-1/metadata_norm.json: "hash": "175e704a" +inst/test_site/devices/AHU-22/metadata_norm.json: "hash": "bf0ba5fa" +inst/test_site/devices/GAT-123/metadata_norm.json: "hash": "cbcf045e" +inst/test_site/devices/SNS-4/metadata_norm.json: "hash": "879557b4" RESULT skip cloud.udmi.state No device id RESULT skip cloud.udmi.pointset No device id RESULT skip cloud.udmi.system No device id -RESULT fail cloud.udmi.state No result found +RESULT pass cloud.udmi.state Payload successfully validated RESULT pass cloud.udmi.pointset Payload successfully validated RESULT pass cloud.udmi.system Payload successfully validated -RESULT fail cloud.udmi.state No result found -RESULT fail cloud.udmi.pointset #: extraneous key [extraField] is not permitted +RESULT pass cloud.udmi.state Payload successfully validated +RESULT fail cloud.udmi.pointset "Unrecognized field \"extraField\" (class com.google.daq.mqtt.registrar.UdmiSchema$PointsetMessage), not marked as ignorable (3 known properties: \"version\", \"points\", \"timestamp\"])\n at [Source: UNKNOWN; line: -1, column: -1] (through reference chain: com.google.daq.mqtt.registrar.UdmiSchema$PointsetMessage[\"extraField\"])" RESULT pass cloud.udmi.system Payload successfully validated diff --git a/testing/test_aux.sh b/testing/test_aux.sh index edc08f149e..7dc587088d 100755 --- a/testing/test_aux.sh +++ b/testing/test_aux.sh @@ -31,6 +31,7 @@ function make_pubber { "cloudRegion": $cloud_region, "registryId": $registry_id, "extraField": $fail, + "keyFile": "local/rsa_private.pkcs8", "gatewayId": $gateway, "deviceId": "$device" } @@ -84,7 +85,7 @@ if [ -f "$gcp_cred" ]; then make_pubber AHU-1 daq-faux-2 null null make_pubber SNS-4 daq-faux-3 1234 \"GAT-123\" - GOOGLE_APPLICATION_CREDENTIALS=$gcp_cred bin/registrar $project_id + GOOGLE_APPLICATION_CREDENTIALS=$gcp_cred udmi/bin/registrar $project_id inst/test_site cat inst/test_site/registration_summary.json | tee -a $GCP_RESULTS echo | tee -a $GCP_RESULTS fgrep hash inst/test_site/devices/*/metadata_norm.json | tee -a $GCP_RESULTS diff --git a/testing/test_topo.out b/testing/test_topo.out index da2f1ed03b..a2d2414c41 100644 --- a/testing/test_topo.out +++ b/testing/test_topo.out @@ -2,7 +2,6 @@ Running testing/test_topo.sh Topology Tests mudacl tests Mudacl exit code 0 -Validator exit code 0 Running open 3 check_socket 01 02 1 1 check_socket 02 01 1 1 diff --git a/testing/test_topo.sh b/testing/test_topo.sh index 82da4d6000..d802e73483 100755 --- a/testing/test_topo.sh +++ b/testing/test_topo.sh @@ -4,14 +4,9 @@ source testing/test_preamble.sh echo Topology Tests >> $TEST_RESULTS -# Test the mudacl config and the test_schema to make sure they -# make sense for tests that use them - echo mudacl tests | tee -a $TEST_RESULTS mudacl/bin/test.sh echo Mudacl exit code $? | tee -a $TEST_RESULTS -validator/bin/test_schema -echo Validator exit code $? | tee -a $TEST_RESULTS bacnet_file=/tmp/bacnet_result.txt socket_file=/tmp/socket_result.txt From 1a2f90d6b8f7884101aa191722bd9e4942f3ea2d Mon Sep 17 00:00:00 2001 From: Trevor Pering Date: Mon, 20 Jul 2020 09:53:45 -0700 Subject: [PATCH 029/212] Purge UDMI files --- pubber/.idea/codeStyles/codeStyleConfig.xml | 5 - pubber/.idea/dictionaries/peringknife.xml | 7 - pubber/.idea/encodings.xml | 4 - pubber/.idea/gradle.xml | 19 - pubber/.idea/jarRepositories.xml | 30 - .../Gradle__com_bugsnag_bugsnag_3_6_1.xml | 11 - ...ackson_core_jackson_annotations_2_10_3.xml | 11 - ...erxml_jackson_core_jackson_core_2_10_3.xml | 11 - ...l_jackson_core_jackson_databind_2_10_3.xml | 11 - ...radle__com_google_api_api_common_1_1_0.xml | 11 - ...le_api_client_google_api_client_1_22_0.xml | 11 - .../Gradle__com_google_api_gax_1_8_1.xml | 11 - ...Gradle__com_google_api_gax_grpc_0_25_1.xml | 11 - ...c_proto_google_cloud_logging_v2_0_1_20.xml | 11 - ...grpc_proto_google_common_protos_0_1_20.xml | 11 - ...le_api_grpc_proto_google_iam_v1_0_1_20.xml | 11 - ...ervices_cloudiot_v1_rev20170922_1_22_0.xml | 11 - ..._google_auth_library_credentials_0_8_0.xml | 11 - ..._google_auth_library_oauth2_http_0_8_0.xml | 11 - ...__com_google_auto_value_auto_value_1_2.xml | 11 - ...m_google_cloud_google_cloud_core_1_7_0.xml | 11 - ...gle_cloud_google_cloud_core_grpc_1_7_0.xml | 11 - ...oogle_cloud_google_cloud_logging_1_7_0.xml | 11 - ..._com_google_code_findbugs_jsr305_3_0_0.xml | 11 - .../Gradle__com_google_code_gson_gson_2_7.xml | 11 - ...orprone_error_prone_annotations_2_0_19.xml | 11 - .../Gradle__com_google_guava_guava_22_0.xml | 11 - ..._http_client_google_http_client_1_22_0.xml | 11 - ...ent_google_http_client_jackson2_1_22_0.xml | 11 - ...trumentation_instrumentation_api_0_4_3.xml | 11 - ...m_google_j2objc_j2objc_annotations_1_1.xml | 11 - ...auth_client_google_oauth_client_1_22_0.xml | 11 - ...om_google_protobuf_protobuf_java_3_3_1.xml | 11 - ...ogle_protobuf_protobuf_java_util_3_3_1.xml | 11 - .../Gradle__com_hazelcast_hazelcast_3_5_4.xml | 11 - ...com_librato_metrics_librato_java_2_1_0.xml | 11 - ..._librato_metrics_metrics_librato_5_1_0.xml | 11 - ...adle__com_sun_xml_bind_jaxb_impl_2_3_2.xml | 11 - ...adle__commons_codec_commons_codec_1_10.xml | 11 - ..._commons_logging_commons_logging_1_1_1.xml | 11 - ..._dropwizard_metrics_metrics_core_3_2_2.xml | 11 - ...o_dropwizard_metrics_metrics_jvm_3_2_2.xml | 11 - .../Gradle__io_grpc_grpc_auth_1_6_1.xml | 11 - .../Gradle__io_grpc_grpc_context_1_6_1.xml | 11 - .../Gradle__io_grpc_grpc_core_1_6_1.xml | 11 - .../Gradle__io_grpc_grpc_netty_1_6_1.xml | 11 - .../Gradle__io_grpc_grpc_protobuf_1_6_1.xml | 11 - ...adle__io_grpc_grpc_protobuf_lite_1_6_1.xml | 11 - .../Gradle__io_grpc_grpc_stub_1_6_1.xml | 11 - .../Gradle__io_jsonwebtoken_jjwt_0_7_0.xml | 11 - ...adle__io_moquette_moquette_broker_0_10.xml | 9 - ...le__io_netty_netty_buffer_4_1_14_Final.xml | 11 - ...dle__io_netty_netty_codec_4_1_14_Final.xml | 11 - ...o_netty_netty_codec_http2_4_1_14_Final.xml | 11 - ...io_netty_netty_codec_http_4_1_14_Final.xml | 11 - ...io_netty_netty_codec_mqtt_4_1_12_Final.xml | 11 - ...o_netty_netty_codec_socks_4_1_14_Final.xml | 11 - ...le__io_netty_netty_common_4_1_14_Final.xml | 11 - ...e__io_netty_netty_handler_4_1_14_Final.xml | 11 - ...netty_netty_handler_proxy_4_1_14_Final.xml | 11 - ...__io_netty_netty_resolver_4_1_14_Final.xml | 11 - ..._tcnative_boringssl_static_2_0_3_Final.xml | 11 - ..._io_netty_netty_transport_4_1_14_Final.xml | 11 - ...native_epoll_4_1_12_Final_linux_x86_64.xml | 11 - ...nsport_native_unix_common_4_1_12_Final.xml | 11 - ...le__io_opencensus_opencensus_api_0_5_1.xml | 11 - ..._activation_javax_activation_api_1_2_0.xml | 11 - .../Gradle__javax_xml_bind_jaxb_api_2_3_1.xml | 11 - .../Gradle__joda_time_joda_time_2_9_7.xml | 11 - .../libraries/Gradle__junit_junit_4_13.xml | 11 - ...apache_httpcomponents_httpclient_4_0_1.xml | 11 - ...g_apache_httpcomponents_httpcore_4_0_1.xml | 11 - ...s_mojo_animal_sniffer_annotations_1_14.xml | 11 - ...o_org_eclipse_paho_client_mqttv3_1_1_0.xml | 11 - ...Gradle__org_hamcrest_hamcrest_core_1_3.xml | 11 - .../Gradle__org_json_json_20160810.xml | 11 - ...adle__org_mockito_mockito_core_1_10_19.xml | 11 - .../Gradle__org_objenesis_objenesis_2_1.xml | 11 - .../Gradle__org_slf4j_slf4j_api_1_7_25.xml | 11 - .../Gradle__org_slf4j_slf4j_simple_1_7_5.xml | 11 - .../Gradle__org_threeten_threetenbp_1_3_3.xml | 11 - pubber/.idea/misc.xml | 6 - pubber/.idea/modules.xml | 8 - pubber/.idea/modules/datafmt.iml | 21 - pubber/.idea/uiDesigner.xml | 124 - pubber/.idea/vcs.xml | 61 - pubber/bin/build | 11 - pubber/bin/keygen | 21 - pubber/bin/run | 13 - pubber/build.gradle | 54 - pubber/gradle/wrapper/gradle-wrapper.jar | Bin 54329 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 - pubber/gradlew | 172 -- pubber/local | 1 - pubber/pubber.iml | 92 - pubber/settings.gradle | 1 - .../main/java/daq/pubber/AbstractPoint.java | 15 - .../main/java/daq/pubber/Configuration.java | 18 - .../main/java/daq/pubber/GatewayError.java | 14 - .../java/daq/pubber/JwtAuthorization.java | 11 - .../main/java/daq/pubber/MqttPublisher.java | 366 --- pubber/src/main/java/daq/pubber/Pubber.java | 287 --- .../src/main/java/daq/pubber/RandomPoint.java | 42 - pubber/src/main/java/daq/udmi/Entry.java | 26 - pubber/src/main/java/daq/udmi/Message.java | 76 - schemas/simple/simple.json | 27 - schemas/simple/simple.tests/error.json | 6 - schemas/simple/simple.tests/error.out | 4 - schemas/simple/simple.tests/example.json | 6 - schemas/simple/simple.tests/example.out | 0 schemas/simple/simple.tests/simple.json | 27 - schemas/simple/simple.tests/simple.out | 4 - schemas/udmi/README.md | 163 -- schemas/udmi/TECH_STACK.md | 46 - schemas/udmi/config.json | 33 - schemas/udmi/config.tests/empty.json | 2 - schemas/udmi/config.tests/empty.out | 6 - schemas/udmi/config.tests/errors.json | 30 - schemas/udmi/config.tests/errors.out | 16 - schemas/udmi/config.tests/example.json | 18 - schemas/udmi/config.tests/example.out | 0 schemas/udmi/config.tests/fcu.json | 23 - schemas/udmi/config.tests/fcu.out | 6 - schemas/udmi/config.tests/gateway.json | 7 - schemas/udmi/config.tests/gateway.out | 4 - schemas/udmi/config.tests/proxy.json | 23 - schemas/udmi/config.tests/proxy.out | 0 schemas/udmi/config.tests/rotate.json | 16 - schemas/udmi/config.tests/rotate.out | 0 schemas/udmi/config.tests/smartprimus.json | 21 - schemas/udmi/config.tests/smartprimus.out | 0 schemas/udmi/config_gateway.json | 18 - schemas/udmi/config_localnet.json | 27 - schemas/udmi/config_pointset.json | 34 - schemas/udmi/config_system.json | 25 - schemas/udmi/discover.json | 52 - schemas/udmi/discover.tests/empty.json | 2 - schemas/udmi/discover.tests/empty.out | 9 - schemas/udmi/discover.tests/errors.json | 31 - schemas/udmi/discover.tests/errors.out | 15 - schemas/udmi/discover.tests/example.json | 18 - schemas/udmi/discover.tests/example.out | 0 schemas/udmi/docs/gateway.md | 120 - schemas/udmi/envelope.json | 39 - schemas/udmi/envelope.tests/empty.json | 2 - schemas/udmi/envelope.tests/empty.out | 9 - schemas/udmi/envelope.tests/errors1.json | 5 - schemas/udmi/envelope.tests/errors1.out | 9 - schemas/udmi/envelope.tests/errors2.json | 5 - schemas/udmi/envelope.tests/errors2.out | 8 - schemas/udmi/envelope.tests/example.json | 7 - schemas/udmi/envelope.tests/example.out | 0 schemas/udmi/envelope.tests/example2.json | 7 - schemas/udmi/envelope.tests/example2.out | 0 schemas/udmi/envelope.tests/lgtw.json | 7 - schemas/udmi/envelope.tests/lgtw.out | 0 schemas/udmi/metadata.json | 41 - schemas/udmi/metadata.tests/empty.json | 1 - schemas/udmi/metadata.tests/empty.out | 7 - schemas/udmi/metadata.tests/errors.json | 25 - schemas/udmi/metadata.tests/errors.out | 16 - schemas/udmi/metadata.tests/example.json | 31 - schemas/udmi/metadata.tests/example.out | 0 schemas/udmi/metadata.tests/example2.out | 0 schemas/udmi/metadata.tests/gateway.json | 41 - schemas/udmi/metadata.tests/gateway.out | 0 schemas/udmi/metadata.tests/proxy.json | 43 - schemas/udmi/metadata.tests/proxy.out | 0 schemas/udmi/metadata.tests/toomany.json | 2035 ----------------- schemas/udmi/metadata.tests/toomany.out | 6 - schemas/udmi/metadata_cloud.json | 20 - schemas/udmi/metadata_gateway.json | 27 - schemas/udmi/metadata_localnet.json | 27 - schemas/udmi/metadata_pointset.json | 28 - schemas/udmi/metadata_system.json | 86 - schemas/udmi/pointset.json | 47 - schemas/udmi/pointset.tests/empty.json | 2 - schemas/udmi/pointset.tests/empty.out | 7 - schemas/udmi/pointset.tests/errors.json | 37 - schemas/udmi/pointset.tests/errors.out | 22 - schemas/udmi/pointset.tests/example.json | 18 - schemas/udmi/pointset.tests/example.out | 0 schemas/udmi/pointset.tests/fcu.json | 18 - schemas/udmi/pointset.tests/fcu.out | 0 schemas/udmi/pointset.tests/smartprimus.json | 18 - schemas/udmi/pointset.tests/smartprimus.out | 0 schemas/udmi/properties.json | 29 - schemas/udmi/state.json | 31 - schemas/udmi/state.tests/empty.json | 2 - schemas/udmi/state.tests/empty.out | 7 - schemas/udmi/state.tests/errors.json | 43 - schemas/udmi/state.tests/errors.out | 32 - schemas/udmi/state.tests/example.json | 37 - schemas/udmi/state.tests/example.out | 0 schemas/udmi/state.tests/fcu.json | 52 - schemas/udmi/state.tests/fcu.out | 0 schemas/udmi/state.tests/gateway.json | 23 - schemas/udmi/state.tests/gateway.out | 4 - schemas/udmi/state.tests/rotate.json | 37 - schemas/udmi/state.tests/rotate.out | 0 schemas/udmi/state_gateway.json | 18 - schemas/udmi/state_pointset.json | 35 - schemas/udmi/state_system.json | 56 - schemas/udmi/system.json | 62 - schemas/udmi/system.tests/empty.json | 2 - schemas/udmi/system.tests/empty.out | 6 - schemas/udmi/system.tests/errors.json | 12 - schemas/udmi/system.tests/errors.out | 10 - schemas/udmi/system.tests/example.json | 20 - schemas/udmi/system.tests/example.out | 0 schemas/udmi/system.tests/fcu.json | 19 - schemas/udmi/system.tests/fcu.out | 0 schemas/udmi/units.json | 194 -- .../.idea/codeStyles/codeStyleConfig.xml | 5 - validator/.idea/encodings.xml | 4 - validator/.idea/gradle.xml | 20 - .../inspectionProfiles/Project_Default.xml | 9 - validator/.idea/jarRepositories.xml | 25 - ...om_damnhandy_handy_uri_templates_2_1_6.xml | 11 - ...ackson_core_jackson_annotations_2_11_0.xml | 11 - ...erxml_jackson_core_jackson_core_2_11_0.xml | 11 - ...l_jackson_core_jackson_databind_2_11_0.xml | 11 - ...aformat_jackson_dataformat_yaml_2_11_0.xml | 11 - ...on_schema_org_everit_json_schema_1_9_1.xml | 9 - ...radle__com_google_api_api_common_1_7_0.xml | 11 - ...le_api_client_google_api_client_1_27_0.xml | 11 - .../Gradle__com_google_api_gax_1_42_0.xml | 11 - ...Gradle__com_google_api_gax_grpc_1_42_0.xml | 11 - ...rpc_grpc_google_cloud_pubsub_v1_1_48_0.xml | 11 - ...proto_google_cloud_firestore_v1_0_49_0.xml | 11 - ..._google_cloud_firestore_v1beta1_0_49_0.xml | 11 - ...c_proto_google_cloud_logging_v2_0_49_0.xml | 11 - ...pc_proto_google_cloud_pubsub_v1_1_48_0.xml | 11 - ...grpc_proto_google_common_protos_1_14_0.xml | 11 - ...le_api_grpc_proto_google_iam_v1_0_12_0.xml | 11 - ...ervices_cloudiot_v1_rev20181120_1_27_0.xml | 11 - ...google_auth_library_credentials_0_13_0.xml | 11 - ...google_auth_library_oauth2_http_0_13_0.xml | 11 - ..._google_cloud_google_cloud_core_1_66_0.xml | 11 - ...le_cloud_google_cloud_core_grpc_1_66_0.xml | 11 - ...oud_google_cloud_firestore_0_84_0_beta.xml | 11 - ...ogle_cloud_google_cloud_logging_1_66_0.xml | 11 - ...oogle_cloud_google_cloud_pubsub_1_66_0.xml | 11 - ..._com_google_code_findbugs_jsr305_3_0_2.xml | 11 - .../Gradle__com_google_code_gson_gson_2_7.xml | 11 - ...rorprone_error_prone_annotations_2_2_0.xml | 11 - ...e__com_google_guava_guava_26_0_android.xml | 11 - ..._http_client_google_http_client_1_28_0.xml | 11 - ...ent_google_http_client_jackson2_1_28_0.xml | 11 - ...m_google_j2objc_j2objc_annotations_1_1.xml | 11 - ...auth_client_google_oauth_client_1_27_0.xml | 11 - ...om_google_protobuf_protobuf_java_3_6_1.xml | 11 - ...ogle_protobuf_protobuf_java_util_3_6_1.xml | 11 - .../Gradle__com_google_re2j_re2j_1_1.xml | 11 - ...mons_beanutils_commons_beanutils_1_9_2.xml | 11 - ..._collections_commons_collections_3_2_2.xml | 11 - ...ommons_digester_commons_digester_1_8_1.xml | 11 - .../Gradle__commons_io_commons_io_2_5.xml | 11 - ...e__commons_logging_commons_logging_1_2.xml | 11 - ...ommons_validator_commons_validator_1_6.xml | 11 - .../Gradle__io_grpc_grpc_alts_1_18_0.xml | 11 - .../Gradle__io_grpc_grpc_auth_1_18_0.xml | 11 - .../Gradle__io_grpc_grpc_context_1_18_0.xml | 11 - .../Gradle__io_grpc_grpc_core_1_18_0.xml | 11 - .../Gradle__io_grpc_grpc_grpclb_1_18_0.xml | 11 - ...adle__io_grpc_grpc_netty_shaded_1_18_0.xml | 11 - .../Gradle__io_grpc_grpc_protobuf_1_18_0.xml | 11 - ...dle__io_grpc_grpc_protobuf_lite_1_18_0.xml | 11 - .../Gradle__io_grpc_grpc_stub_1_18_0.xml | 11 - ...e__io_opencensus_opencensus_api_0_18_0.xml | 11 - ...opencensus_contrib_grpc_metrics_0_18_0.xml | 11 - ...us_opencensus_contrib_grpc_util_0_18_0.xml | 11 - ...us_opencensus_contrib_http_util_0_18_0.xml | 11 - ..._annotation_javax_annotation_api_1_3_2.xml | 11 - .../Gradle__joda_time_joda_time_2_9_4.xml | 11 - .../libraries/Gradle__junit_junit_4_13.xml | 11 - ...__org_apache_commons_commons_lang3_3_5.xml | 11 - ...kerframework_checker_compat_qual_2_5_2.xml | 11 - ...s_mojo_animal_sniffer_annotations_1_17.xml | 11 - ...Gradle__org_hamcrest_hamcrest_core_1_3.xml | 11 - .../Gradle__org_json_json_20180130.xml | 11 - .../Gradle__org_threeten_threetenbp_1_3_3.xml | 11 - .../Gradle__org_yaml_snakeyaml_1_26.xml | 11 - ...l_jackson_core_jackson_databind_2_10_2.xml | 12 - validator/.idea/misc.xml | 6 - validator/.idea/modules.xml | 8 - .../.idea/modules/daq-validator.validator.iml | 82 - validator/.idea/uiDesigner.xml | 124 - validator/.idea/validator.iml | 9 - validator/.idea/vcs.xml | 80 - validator/bin/build | 11 - validator/bin/config | 36 - validator/bin/keygen | 21 - validator/bin/registrar | 34 - validator/bin/test_schema | 81 - validator/bin/validate | 37 - validator/build.gradle | 51 - validator/gradle/wrapper/gradle-wrapper.jar | Bin 54329 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 - validator/gradlew | 172 -- validator/gradlew.bat | 84 - validator/settings.gradle | 2 - .../daq/mqtt/registrar/LocalDevice.java | 415 ---- .../google/daq/mqtt/registrar/Registrar.java | 344 --- .../google/daq/mqtt/registrar/UdmiSchema.java | 102 - .../daq/mqtt/util/CloudDeviceSettings.java | 12 - .../google/daq/mqtt/util/CloudIotConfig.java | 8 - .../google/daq/mqtt/util/CloudIotManager.java | 264 --- .../com/google/daq/mqtt/util/ConfigUtil.java | 32 - .../google/daq/mqtt/util/ExceptionMap.java | 109 - .../daq/mqtt/util/FirestoreDataSink.java | 83 - .../google/daq/mqtt/util/PubSubClient.java | 166 -- .../google/daq/mqtt/util/PubSubPusher.java | 66 - .../util/RetryHttpInitializerWrapper.java | 87 - .../daq/mqtt/validator/ReportingDevice.java | 101 - .../google/daq/mqtt/validator/Validator.java | 463 ---- 316 files changed, 10499 deletions(-) delete mode 100644 pubber/.idea/codeStyles/codeStyleConfig.xml delete mode 100644 pubber/.idea/dictionaries/peringknife.xml delete mode 100644 pubber/.idea/encodings.xml delete mode 100644 pubber/.idea/gradle.xml delete mode 100644 pubber/.idea/jarRepositories.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_bugsnag_bugsnag_3_6_1.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_annotations_2_10_3.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_core_2_10_3.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_databind_2_10_3.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_google_api_api_common_1_1_0.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_google_api_client_google_api_client_1_22_0.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_google_api_gax_1_8_1.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_google_api_gax_grpc_0_25_1.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_google_api_grpc_proto_google_cloud_logging_v2_0_1_20.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_google_api_grpc_proto_google_common_protos_0_1_20.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_google_api_grpc_proto_google_iam_v1_0_1_20.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_google_apis_google_api_services_cloudiot_v1_rev20170922_1_22_0.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_google_auth_google_auth_library_credentials_0_8_0.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_google_auth_google_auth_library_oauth2_http_0_8_0.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_google_auto_value_auto_value_1_2.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_google_cloud_google_cloud_core_1_7_0.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_google_cloud_google_cloud_core_grpc_1_7_0.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_google_cloud_google_cloud_logging_1_7_0.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_google_code_findbugs_jsr305_3_0_0.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_google_code_gson_gson_2_7.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_google_errorprone_error_prone_annotations_2_0_19.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_google_guava_guava_22_0.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_google_http_client_google_http_client_1_22_0.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_google_http_client_google_http_client_jackson2_1_22_0.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_google_instrumentation_instrumentation_api_0_4_3.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_google_j2objc_j2objc_annotations_1_1.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_google_oauth_client_google_oauth_client_1_22_0.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_google_protobuf_protobuf_java_3_3_1.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_google_protobuf_protobuf_java_util_3_3_1.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_hazelcast_hazelcast_3_5_4.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_librato_metrics_librato_java_2_1_0.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_librato_metrics_metrics_librato_5_1_0.xml delete mode 100644 pubber/.idea/libraries/Gradle__com_sun_xml_bind_jaxb_impl_2_3_2.xml delete mode 100644 pubber/.idea/libraries/Gradle__commons_codec_commons_codec_1_10.xml delete mode 100644 pubber/.idea/libraries/Gradle__commons_logging_commons_logging_1_1_1.xml delete mode 100644 pubber/.idea/libraries/Gradle__io_dropwizard_metrics_metrics_core_3_2_2.xml delete mode 100644 pubber/.idea/libraries/Gradle__io_dropwizard_metrics_metrics_jvm_3_2_2.xml delete mode 100644 pubber/.idea/libraries/Gradle__io_grpc_grpc_auth_1_6_1.xml delete mode 100644 pubber/.idea/libraries/Gradle__io_grpc_grpc_context_1_6_1.xml delete mode 100644 pubber/.idea/libraries/Gradle__io_grpc_grpc_core_1_6_1.xml delete mode 100644 pubber/.idea/libraries/Gradle__io_grpc_grpc_netty_1_6_1.xml delete mode 100644 pubber/.idea/libraries/Gradle__io_grpc_grpc_protobuf_1_6_1.xml delete mode 100644 pubber/.idea/libraries/Gradle__io_grpc_grpc_protobuf_lite_1_6_1.xml delete mode 100644 pubber/.idea/libraries/Gradle__io_grpc_grpc_stub_1_6_1.xml delete mode 100644 pubber/.idea/libraries/Gradle__io_jsonwebtoken_jjwt_0_7_0.xml delete mode 100644 pubber/.idea/libraries/Gradle__io_moquette_moquette_broker_0_10.xml delete mode 100644 pubber/.idea/libraries/Gradle__io_netty_netty_buffer_4_1_14_Final.xml delete mode 100644 pubber/.idea/libraries/Gradle__io_netty_netty_codec_4_1_14_Final.xml delete mode 100644 pubber/.idea/libraries/Gradle__io_netty_netty_codec_http2_4_1_14_Final.xml delete mode 100644 pubber/.idea/libraries/Gradle__io_netty_netty_codec_http_4_1_14_Final.xml delete mode 100644 pubber/.idea/libraries/Gradle__io_netty_netty_codec_mqtt_4_1_12_Final.xml delete mode 100644 pubber/.idea/libraries/Gradle__io_netty_netty_codec_socks_4_1_14_Final.xml delete mode 100644 pubber/.idea/libraries/Gradle__io_netty_netty_common_4_1_14_Final.xml delete mode 100644 pubber/.idea/libraries/Gradle__io_netty_netty_handler_4_1_14_Final.xml delete mode 100644 pubber/.idea/libraries/Gradle__io_netty_netty_handler_proxy_4_1_14_Final.xml delete mode 100644 pubber/.idea/libraries/Gradle__io_netty_netty_resolver_4_1_14_Final.xml delete mode 100644 pubber/.idea/libraries/Gradle__io_netty_netty_tcnative_boringssl_static_2_0_3_Final.xml delete mode 100644 pubber/.idea/libraries/Gradle__io_netty_netty_transport_4_1_14_Final.xml delete mode 100644 pubber/.idea/libraries/Gradle__io_netty_netty_transport_native_epoll_4_1_12_Final_linux_x86_64.xml delete mode 100644 pubber/.idea/libraries/Gradle__io_netty_netty_transport_native_unix_common_4_1_12_Final.xml delete mode 100644 pubber/.idea/libraries/Gradle__io_opencensus_opencensus_api_0_5_1.xml delete mode 100644 pubber/.idea/libraries/Gradle__javax_activation_javax_activation_api_1_2_0.xml delete mode 100644 pubber/.idea/libraries/Gradle__javax_xml_bind_jaxb_api_2_3_1.xml delete mode 100644 pubber/.idea/libraries/Gradle__joda_time_joda_time_2_9_7.xml delete mode 100644 pubber/.idea/libraries/Gradle__junit_junit_4_13.xml delete mode 100644 pubber/.idea/libraries/Gradle__org_apache_httpcomponents_httpclient_4_0_1.xml delete mode 100644 pubber/.idea/libraries/Gradle__org_apache_httpcomponents_httpcore_4_0_1.xml delete mode 100644 pubber/.idea/libraries/Gradle__org_codehaus_mojo_animal_sniffer_annotations_1_14.xml delete mode 100644 pubber/.idea/libraries/Gradle__org_eclipse_paho_org_eclipse_paho_client_mqttv3_1_1_0.xml delete mode 100644 pubber/.idea/libraries/Gradle__org_hamcrest_hamcrest_core_1_3.xml delete mode 100644 pubber/.idea/libraries/Gradle__org_json_json_20160810.xml delete mode 100644 pubber/.idea/libraries/Gradle__org_mockito_mockito_core_1_10_19.xml delete mode 100644 pubber/.idea/libraries/Gradle__org_objenesis_objenesis_2_1.xml delete mode 100644 pubber/.idea/libraries/Gradle__org_slf4j_slf4j_api_1_7_25.xml delete mode 100644 pubber/.idea/libraries/Gradle__org_slf4j_slf4j_simple_1_7_5.xml delete mode 100644 pubber/.idea/libraries/Gradle__org_threeten_threetenbp_1_3_3.xml delete mode 100644 pubber/.idea/misc.xml delete mode 100644 pubber/.idea/modules.xml delete mode 100644 pubber/.idea/modules/datafmt.iml delete mode 100644 pubber/.idea/uiDesigner.xml delete mode 100644 pubber/.idea/vcs.xml delete mode 100755 pubber/bin/build delete mode 100755 pubber/bin/keygen delete mode 100755 pubber/bin/run delete mode 100644 pubber/build.gradle delete mode 100644 pubber/gradle/wrapper/gradle-wrapper.jar delete mode 100644 pubber/gradle/wrapper/gradle-wrapper.properties delete mode 100755 pubber/gradlew delete mode 120000 pubber/local delete mode 100644 pubber/pubber.iml delete mode 100644 pubber/settings.gradle delete mode 100644 pubber/src/main/java/daq/pubber/AbstractPoint.java delete mode 100644 pubber/src/main/java/daq/pubber/Configuration.java delete mode 100644 pubber/src/main/java/daq/pubber/GatewayError.java delete mode 100644 pubber/src/main/java/daq/pubber/JwtAuthorization.java delete mode 100644 pubber/src/main/java/daq/pubber/MqttPublisher.java delete mode 100644 pubber/src/main/java/daq/pubber/Pubber.java delete mode 100644 pubber/src/main/java/daq/pubber/RandomPoint.java delete mode 100644 pubber/src/main/java/daq/udmi/Entry.java delete mode 100644 pubber/src/main/java/daq/udmi/Message.java delete mode 100644 schemas/simple/simple.json delete mode 100644 schemas/simple/simple.tests/error.json delete mode 100644 schemas/simple/simple.tests/error.out delete mode 100644 schemas/simple/simple.tests/example.json delete mode 100644 schemas/simple/simple.tests/example.out delete mode 100644 schemas/simple/simple.tests/simple.json delete mode 100644 schemas/simple/simple.tests/simple.out delete mode 100644 schemas/udmi/README.md delete mode 100644 schemas/udmi/TECH_STACK.md delete mode 100644 schemas/udmi/config.json delete mode 100644 schemas/udmi/config.tests/empty.json delete mode 100644 schemas/udmi/config.tests/empty.out delete mode 100644 schemas/udmi/config.tests/errors.json delete mode 100644 schemas/udmi/config.tests/errors.out delete mode 100644 schemas/udmi/config.tests/example.json delete mode 100644 schemas/udmi/config.tests/example.out delete mode 100644 schemas/udmi/config.tests/fcu.json delete mode 100644 schemas/udmi/config.tests/fcu.out delete mode 100644 schemas/udmi/config.tests/gateway.json delete mode 100644 schemas/udmi/config.tests/gateway.out delete mode 100644 schemas/udmi/config.tests/proxy.json delete mode 100644 schemas/udmi/config.tests/proxy.out delete mode 100644 schemas/udmi/config.tests/rotate.json delete mode 100644 schemas/udmi/config.tests/rotate.out delete mode 100644 schemas/udmi/config.tests/smartprimus.json delete mode 100644 schemas/udmi/config.tests/smartprimus.out delete mode 100644 schemas/udmi/config_gateway.json delete mode 100644 schemas/udmi/config_localnet.json delete mode 100644 schemas/udmi/config_pointset.json delete mode 100644 schemas/udmi/config_system.json delete mode 100644 schemas/udmi/discover.json delete mode 100644 schemas/udmi/discover.tests/empty.json delete mode 100644 schemas/udmi/discover.tests/empty.out delete mode 100644 schemas/udmi/discover.tests/errors.json delete mode 100644 schemas/udmi/discover.tests/errors.out delete mode 100644 schemas/udmi/discover.tests/example.json delete mode 100644 schemas/udmi/discover.tests/example.out delete mode 100644 schemas/udmi/docs/gateway.md delete mode 100644 schemas/udmi/envelope.json delete mode 100644 schemas/udmi/envelope.tests/empty.json delete mode 100644 schemas/udmi/envelope.tests/empty.out delete mode 100644 schemas/udmi/envelope.tests/errors1.json delete mode 100644 schemas/udmi/envelope.tests/errors1.out delete mode 100644 schemas/udmi/envelope.tests/errors2.json delete mode 100644 schemas/udmi/envelope.tests/errors2.out delete mode 100644 schemas/udmi/envelope.tests/example.json delete mode 100644 schemas/udmi/envelope.tests/example.out delete mode 100644 schemas/udmi/envelope.tests/example2.json delete mode 100644 schemas/udmi/envelope.tests/example2.out delete mode 100644 schemas/udmi/envelope.tests/lgtw.json delete mode 100644 schemas/udmi/envelope.tests/lgtw.out delete mode 100644 schemas/udmi/metadata.json delete mode 100644 schemas/udmi/metadata.tests/empty.json delete mode 100644 schemas/udmi/metadata.tests/empty.out delete mode 100644 schemas/udmi/metadata.tests/errors.json delete mode 100644 schemas/udmi/metadata.tests/errors.out delete mode 100644 schemas/udmi/metadata.tests/example.json delete mode 100644 schemas/udmi/metadata.tests/example.out delete mode 100644 schemas/udmi/metadata.tests/example2.out delete mode 100644 schemas/udmi/metadata.tests/gateway.json delete mode 100644 schemas/udmi/metadata.tests/gateway.out delete mode 100644 schemas/udmi/metadata.tests/proxy.json delete mode 100644 schemas/udmi/metadata.tests/proxy.out delete mode 100644 schemas/udmi/metadata.tests/toomany.json delete mode 100644 schemas/udmi/metadata.tests/toomany.out delete mode 100644 schemas/udmi/metadata_cloud.json delete mode 100644 schemas/udmi/metadata_gateway.json delete mode 100644 schemas/udmi/metadata_localnet.json delete mode 100644 schemas/udmi/metadata_pointset.json delete mode 100644 schemas/udmi/metadata_system.json delete mode 100644 schemas/udmi/pointset.json delete mode 100644 schemas/udmi/pointset.tests/empty.json delete mode 100644 schemas/udmi/pointset.tests/empty.out delete mode 100644 schemas/udmi/pointset.tests/errors.json delete mode 100644 schemas/udmi/pointset.tests/errors.out delete mode 100644 schemas/udmi/pointset.tests/example.json delete mode 100644 schemas/udmi/pointset.tests/example.out delete mode 100644 schemas/udmi/pointset.tests/fcu.json delete mode 100644 schemas/udmi/pointset.tests/fcu.out delete mode 100644 schemas/udmi/pointset.tests/smartprimus.json delete mode 100644 schemas/udmi/pointset.tests/smartprimus.out delete mode 100644 schemas/udmi/properties.json delete mode 100644 schemas/udmi/state.json delete mode 100644 schemas/udmi/state.tests/empty.json delete mode 100644 schemas/udmi/state.tests/empty.out delete mode 100644 schemas/udmi/state.tests/errors.json delete mode 100644 schemas/udmi/state.tests/errors.out delete mode 100644 schemas/udmi/state.tests/example.json delete mode 100644 schemas/udmi/state.tests/example.out delete mode 100644 schemas/udmi/state.tests/fcu.json delete mode 100644 schemas/udmi/state.tests/fcu.out delete mode 100644 schemas/udmi/state.tests/gateway.json delete mode 100644 schemas/udmi/state.tests/gateway.out delete mode 100644 schemas/udmi/state.tests/rotate.json delete mode 100644 schemas/udmi/state.tests/rotate.out delete mode 100644 schemas/udmi/state_gateway.json delete mode 100644 schemas/udmi/state_pointset.json delete mode 100644 schemas/udmi/state_system.json delete mode 100644 schemas/udmi/system.json delete mode 100644 schemas/udmi/system.tests/empty.json delete mode 100644 schemas/udmi/system.tests/empty.out delete mode 100644 schemas/udmi/system.tests/errors.json delete mode 100644 schemas/udmi/system.tests/errors.out delete mode 100644 schemas/udmi/system.tests/example.json delete mode 100644 schemas/udmi/system.tests/example.out delete mode 100644 schemas/udmi/system.tests/fcu.json delete mode 100644 schemas/udmi/system.tests/fcu.out delete mode 100644 schemas/udmi/units.json delete mode 100644 validator/.idea/codeStyles/codeStyleConfig.xml delete mode 100644 validator/.idea/encodings.xml delete mode 100644 validator/.idea/gradle.xml delete mode 100644 validator/.idea/inspectionProfiles/Project_Default.xml delete mode 100644 validator/.idea/jarRepositories.xml delete mode 100644 validator/.idea/libraries/Gradle__com_damnhandy_handy_uri_templates_2_1_6.xml delete mode 100644 validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_annotations_2_11_0.xml delete mode 100644 validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_core_2_11_0.xml delete mode 100644 validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_databind_2_11_0.xml delete mode 100644 validator/.idea/libraries/Gradle__com_fasterxml_jackson_dataformat_jackson_dataformat_yaml_2_11_0.xml delete mode 100644 validator/.idea/libraries/Gradle__com_github_everit_org_json_schema_org_everit_json_schema_1_9_1.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_api_api_common_1_7_0.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_api_client_google_api_client_1_27_0.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_api_gax_1_42_0.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_api_gax_grpc_1_42_0.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_api_grpc_grpc_google_cloud_pubsub_v1_1_48_0.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_api_grpc_proto_google_cloud_firestore_v1_0_49_0.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_api_grpc_proto_google_cloud_firestore_v1beta1_0_49_0.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_api_grpc_proto_google_cloud_logging_v2_0_49_0.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_api_grpc_proto_google_cloud_pubsub_v1_1_48_0.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_api_grpc_proto_google_common_protos_1_14_0.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_api_grpc_proto_google_iam_v1_0_12_0.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_apis_google_api_services_cloudiot_v1_rev20181120_1_27_0.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_auth_google_auth_library_credentials_0_13_0.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_auth_google_auth_library_oauth2_http_0_13_0.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_cloud_google_cloud_core_1_66_0.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_cloud_google_cloud_core_grpc_1_66_0.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_cloud_google_cloud_firestore_0_84_0_beta.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_cloud_google_cloud_logging_1_66_0.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_cloud_google_cloud_pubsub_1_66_0.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_code_findbugs_jsr305_3_0_2.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_code_gson_gson_2_7.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_errorprone_error_prone_annotations_2_2_0.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_guava_guava_26_0_android.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_http_client_google_http_client_1_28_0.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_http_client_google_http_client_jackson2_1_28_0.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_j2objc_j2objc_annotations_1_1.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_oauth_client_google_oauth_client_1_27_0.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_protobuf_protobuf_java_3_6_1.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_protobuf_protobuf_java_util_3_6_1.xml delete mode 100644 validator/.idea/libraries/Gradle__com_google_re2j_re2j_1_1.xml delete mode 100644 validator/.idea/libraries/Gradle__commons_beanutils_commons_beanutils_1_9_2.xml delete mode 100644 validator/.idea/libraries/Gradle__commons_collections_commons_collections_3_2_2.xml delete mode 100644 validator/.idea/libraries/Gradle__commons_digester_commons_digester_1_8_1.xml delete mode 100644 validator/.idea/libraries/Gradle__commons_io_commons_io_2_5.xml delete mode 100644 validator/.idea/libraries/Gradle__commons_logging_commons_logging_1_2.xml delete mode 100644 validator/.idea/libraries/Gradle__commons_validator_commons_validator_1_6.xml delete mode 100644 validator/.idea/libraries/Gradle__io_grpc_grpc_alts_1_18_0.xml delete mode 100644 validator/.idea/libraries/Gradle__io_grpc_grpc_auth_1_18_0.xml delete mode 100644 validator/.idea/libraries/Gradle__io_grpc_grpc_context_1_18_0.xml delete mode 100644 validator/.idea/libraries/Gradle__io_grpc_grpc_core_1_18_0.xml delete mode 100644 validator/.idea/libraries/Gradle__io_grpc_grpc_grpclb_1_18_0.xml delete mode 100644 validator/.idea/libraries/Gradle__io_grpc_grpc_netty_shaded_1_18_0.xml delete mode 100644 validator/.idea/libraries/Gradle__io_grpc_grpc_protobuf_1_18_0.xml delete mode 100644 validator/.idea/libraries/Gradle__io_grpc_grpc_protobuf_lite_1_18_0.xml delete mode 100644 validator/.idea/libraries/Gradle__io_grpc_grpc_stub_1_18_0.xml delete mode 100644 validator/.idea/libraries/Gradle__io_opencensus_opencensus_api_0_18_0.xml delete mode 100644 validator/.idea/libraries/Gradle__io_opencensus_opencensus_contrib_grpc_metrics_0_18_0.xml delete mode 100644 validator/.idea/libraries/Gradle__io_opencensus_opencensus_contrib_grpc_util_0_18_0.xml delete mode 100644 validator/.idea/libraries/Gradle__io_opencensus_opencensus_contrib_http_util_0_18_0.xml delete mode 100644 validator/.idea/libraries/Gradle__javax_annotation_javax_annotation_api_1_3_2.xml delete mode 100644 validator/.idea/libraries/Gradle__joda_time_joda_time_2_9_4.xml delete mode 100644 validator/.idea/libraries/Gradle__junit_junit_4_13.xml delete mode 100644 validator/.idea/libraries/Gradle__org_apache_commons_commons_lang3_3_5.xml delete mode 100644 validator/.idea/libraries/Gradle__org_checkerframework_checker_compat_qual_2_5_2.xml delete mode 100644 validator/.idea/libraries/Gradle__org_codehaus_mojo_animal_sniffer_annotations_1_17.xml delete mode 100644 validator/.idea/libraries/Gradle__org_hamcrest_hamcrest_core_1_3.xml delete mode 100644 validator/.idea/libraries/Gradle__org_json_json_20180130.xml delete mode 100644 validator/.idea/libraries/Gradle__org_threeten_threetenbp_1_3_3.xml delete mode 100644 validator/.idea/libraries/Gradle__org_yaml_snakeyaml_1_26.xml delete mode 100644 validator/.idea/libraries/com_fasterxml_jackson_core_jackson_databind_2_10_2.xml delete mode 100644 validator/.idea/misc.xml delete mode 100644 validator/.idea/modules.xml delete mode 100644 validator/.idea/modules/daq-validator.validator.iml delete mode 100644 validator/.idea/uiDesigner.xml delete mode 100644 validator/.idea/validator.iml delete mode 100644 validator/.idea/vcs.xml delete mode 100755 validator/bin/build delete mode 100755 validator/bin/config delete mode 100755 validator/bin/keygen delete mode 100755 validator/bin/registrar delete mode 100755 validator/bin/test_schema delete mode 100755 validator/bin/validate delete mode 100644 validator/build.gradle delete mode 100644 validator/gradle/wrapper/gradle-wrapper.jar delete mode 100644 validator/gradle/wrapper/gradle-wrapper.properties delete mode 100755 validator/gradlew delete mode 100644 validator/gradlew.bat delete mode 100644 validator/settings.gradle delete mode 100644 validator/src/main/java/com/google/daq/mqtt/registrar/LocalDevice.java delete mode 100644 validator/src/main/java/com/google/daq/mqtt/registrar/Registrar.java delete mode 100644 validator/src/main/java/com/google/daq/mqtt/registrar/UdmiSchema.java delete mode 100644 validator/src/main/java/com/google/daq/mqtt/util/CloudDeviceSettings.java delete mode 100644 validator/src/main/java/com/google/daq/mqtt/util/CloudIotConfig.java delete mode 100644 validator/src/main/java/com/google/daq/mqtt/util/CloudIotManager.java delete mode 100644 validator/src/main/java/com/google/daq/mqtt/util/ConfigUtil.java delete mode 100644 validator/src/main/java/com/google/daq/mqtt/util/ExceptionMap.java delete mode 100644 validator/src/main/java/com/google/daq/mqtt/util/FirestoreDataSink.java delete mode 100644 validator/src/main/java/com/google/daq/mqtt/util/PubSubClient.java delete mode 100644 validator/src/main/java/com/google/daq/mqtt/util/PubSubPusher.java delete mode 100644 validator/src/main/java/com/google/daq/mqtt/util/RetryHttpInitializerWrapper.java delete mode 100644 validator/src/main/java/com/google/daq/mqtt/validator/ReportingDevice.java delete mode 100644 validator/src/main/java/com/google/daq/mqtt/validator/Validator.java diff --git a/pubber/.idea/codeStyles/codeStyleConfig.xml b/pubber/.idea/codeStyles/codeStyleConfig.xml deleted file mode 100644 index c79f34ced8..0000000000 --- a/pubber/.idea/codeStyles/codeStyleConfig.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/pubber/.idea/dictionaries/peringknife.xml b/pubber/.idea/dictionaries/peringknife.xml deleted file mode 100644 index 1f2f3fc05a..0000000000 --- a/pubber/.idea/dictionaries/peringknife.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - pubber - - - \ No newline at end of file diff --git a/pubber/.idea/encodings.xml b/pubber/.idea/encodings.xml deleted file mode 100644 index 15a15b218a..0000000000 --- a/pubber/.idea/encodings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/pubber/.idea/gradle.xml b/pubber/.idea/gradle.xml deleted file mode 100644 index a931762ec9..0000000000 --- a/pubber/.idea/gradle.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/jarRepositories.xml b/pubber/.idea/jarRepositories.xml deleted file mode 100644 index 6f70f42344..0000000000 --- a/pubber/.idea/jarRepositories.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_bugsnag_bugsnag_3_6_1.xml b/pubber/.idea/libraries/Gradle__com_bugsnag_bugsnag_3_6_1.xml deleted file mode 100644 index a61dc7e59a..0000000000 --- a/pubber/.idea/libraries/Gradle__com_bugsnag_bugsnag_3_6_1.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_annotations_2_10_3.xml b/pubber/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_annotations_2_10_3.xml deleted file mode 100644 index 940abc9cd6..0000000000 --- a/pubber/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_annotations_2_10_3.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_core_2_10_3.xml b/pubber/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_core_2_10_3.xml deleted file mode 100644 index c39a1aad89..0000000000 --- a/pubber/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_core_2_10_3.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_databind_2_10_3.xml b/pubber/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_databind_2_10_3.xml deleted file mode 100644 index 401e4470cc..0000000000 --- a/pubber/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_databind_2_10_3.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_google_api_api_common_1_1_0.xml b/pubber/.idea/libraries/Gradle__com_google_api_api_common_1_1_0.xml deleted file mode 100644 index 6a37163770..0000000000 --- a/pubber/.idea/libraries/Gradle__com_google_api_api_common_1_1_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_google_api_client_google_api_client_1_22_0.xml b/pubber/.idea/libraries/Gradle__com_google_api_client_google_api_client_1_22_0.xml deleted file mode 100644 index f7052b657f..0000000000 --- a/pubber/.idea/libraries/Gradle__com_google_api_client_google_api_client_1_22_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_google_api_gax_1_8_1.xml b/pubber/.idea/libraries/Gradle__com_google_api_gax_1_8_1.xml deleted file mode 100644 index 5afd4e53b5..0000000000 --- a/pubber/.idea/libraries/Gradle__com_google_api_gax_1_8_1.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_google_api_gax_grpc_0_25_1.xml b/pubber/.idea/libraries/Gradle__com_google_api_gax_grpc_0_25_1.xml deleted file mode 100644 index 7dd2f70770..0000000000 --- a/pubber/.idea/libraries/Gradle__com_google_api_gax_grpc_0_25_1.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_google_api_grpc_proto_google_cloud_logging_v2_0_1_20.xml b/pubber/.idea/libraries/Gradle__com_google_api_grpc_proto_google_cloud_logging_v2_0_1_20.xml deleted file mode 100644 index f653b75d6a..0000000000 --- a/pubber/.idea/libraries/Gradle__com_google_api_grpc_proto_google_cloud_logging_v2_0_1_20.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_google_api_grpc_proto_google_common_protos_0_1_20.xml b/pubber/.idea/libraries/Gradle__com_google_api_grpc_proto_google_common_protos_0_1_20.xml deleted file mode 100644 index 3ab192cf7d..0000000000 --- a/pubber/.idea/libraries/Gradle__com_google_api_grpc_proto_google_common_protos_0_1_20.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_google_api_grpc_proto_google_iam_v1_0_1_20.xml b/pubber/.idea/libraries/Gradle__com_google_api_grpc_proto_google_iam_v1_0_1_20.xml deleted file mode 100644 index 831f72e025..0000000000 --- a/pubber/.idea/libraries/Gradle__com_google_api_grpc_proto_google_iam_v1_0_1_20.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_google_apis_google_api_services_cloudiot_v1_rev20170922_1_22_0.xml b/pubber/.idea/libraries/Gradle__com_google_apis_google_api_services_cloudiot_v1_rev20170922_1_22_0.xml deleted file mode 100644 index 409ca08042..0000000000 --- a/pubber/.idea/libraries/Gradle__com_google_apis_google_api_services_cloudiot_v1_rev20170922_1_22_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_google_auth_google_auth_library_credentials_0_8_0.xml b/pubber/.idea/libraries/Gradle__com_google_auth_google_auth_library_credentials_0_8_0.xml deleted file mode 100644 index 19f8e9622f..0000000000 --- a/pubber/.idea/libraries/Gradle__com_google_auth_google_auth_library_credentials_0_8_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_google_auth_google_auth_library_oauth2_http_0_8_0.xml b/pubber/.idea/libraries/Gradle__com_google_auth_google_auth_library_oauth2_http_0_8_0.xml deleted file mode 100644 index a9aba07437..0000000000 --- a/pubber/.idea/libraries/Gradle__com_google_auth_google_auth_library_oauth2_http_0_8_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_google_auto_value_auto_value_1_2.xml b/pubber/.idea/libraries/Gradle__com_google_auto_value_auto_value_1_2.xml deleted file mode 100644 index aeea865ae3..0000000000 --- a/pubber/.idea/libraries/Gradle__com_google_auto_value_auto_value_1_2.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_google_cloud_google_cloud_core_1_7_0.xml b/pubber/.idea/libraries/Gradle__com_google_cloud_google_cloud_core_1_7_0.xml deleted file mode 100644 index 49ddf929e7..0000000000 --- a/pubber/.idea/libraries/Gradle__com_google_cloud_google_cloud_core_1_7_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_google_cloud_google_cloud_core_grpc_1_7_0.xml b/pubber/.idea/libraries/Gradle__com_google_cloud_google_cloud_core_grpc_1_7_0.xml deleted file mode 100644 index f09079becb..0000000000 --- a/pubber/.idea/libraries/Gradle__com_google_cloud_google_cloud_core_grpc_1_7_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_google_cloud_google_cloud_logging_1_7_0.xml b/pubber/.idea/libraries/Gradle__com_google_cloud_google_cloud_logging_1_7_0.xml deleted file mode 100644 index 42054ea1de..0000000000 --- a/pubber/.idea/libraries/Gradle__com_google_cloud_google_cloud_logging_1_7_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_google_code_findbugs_jsr305_3_0_0.xml b/pubber/.idea/libraries/Gradle__com_google_code_findbugs_jsr305_3_0_0.xml deleted file mode 100644 index c6616f41e4..0000000000 --- a/pubber/.idea/libraries/Gradle__com_google_code_findbugs_jsr305_3_0_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_google_code_gson_gson_2_7.xml b/pubber/.idea/libraries/Gradle__com_google_code_gson_gson_2_7.xml deleted file mode 100644 index cbe1b3266b..0000000000 --- a/pubber/.idea/libraries/Gradle__com_google_code_gson_gson_2_7.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_google_errorprone_error_prone_annotations_2_0_19.xml b/pubber/.idea/libraries/Gradle__com_google_errorprone_error_prone_annotations_2_0_19.xml deleted file mode 100644 index b4cd21969d..0000000000 --- a/pubber/.idea/libraries/Gradle__com_google_errorprone_error_prone_annotations_2_0_19.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_google_guava_guava_22_0.xml b/pubber/.idea/libraries/Gradle__com_google_guava_guava_22_0.xml deleted file mode 100644 index 4c947ec6df..0000000000 --- a/pubber/.idea/libraries/Gradle__com_google_guava_guava_22_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_google_http_client_google_http_client_1_22_0.xml b/pubber/.idea/libraries/Gradle__com_google_http_client_google_http_client_1_22_0.xml deleted file mode 100644 index 6c259c21e1..0000000000 --- a/pubber/.idea/libraries/Gradle__com_google_http_client_google_http_client_1_22_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_google_http_client_google_http_client_jackson2_1_22_0.xml b/pubber/.idea/libraries/Gradle__com_google_http_client_google_http_client_jackson2_1_22_0.xml deleted file mode 100644 index b4ec53cbea..0000000000 --- a/pubber/.idea/libraries/Gradle__com_google_http_client_google_http_client_jackson2_1_22_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_google_instrumentation_instrumentation_api_0_4_3.xml b/pubber/.idea/libraries/Gradle__com_google_instrumentation_instrumentation_api_0_4_3.xml deleted file mode 100644 index 07c6748fa9..0000000000 --- a/pubber/.idea/libraries/Gradle__com_google_instrumentation_instrumentation_api_0_4_3.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_google_j2objc_j2objc_annotations_1_1.xml b/pubber/.idea/libraries/Gradle__com_google_j2objc_j2objc_annotations_1_1.xml deleted file mode 100644 index ab45264c2d..0000000000 --- a/pubber/.idea/libraries/Gradle__com_google_j2objc_j2objc_annotations_1_1.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_google_oauth_client_google_oauth_client_1_22_0.xml b/pubber/.idea/libraries/Gradle__com_google_oauth_client_google_oauth_client_1_22_0.xml deleted file mode 100644 index 8549a6371c..0000000000 --- a/pubber/.idea/libraries/Gradle__com_google_oauth_client_google_oauth_client_1_22_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_google_protobuf_protobuf_java_3_3_1.xml b/pubber/.idea/libraries/Gradle__com_google_protobuf_protobuf_java_3_3_1.xml deleted file mode 100644 index e294c29fa5..0000000000 --- a/pubber/.idea/libraries/Gradle__com_google_protobuf_protobuf_java_3_3_1.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_google_protobuf_protobuf_java_util_3_3_1.xml b/pubber/.idea/libraries/Gradle__com_google_protobuf_protobuf_java_util_3_3_1.xml deleted file mode 100644 index 6866f74bf0..0000000000 --- a/pubber/.idea/libraries/Gradle__com_google_protobuf_protobuf_java_util_3_3_1.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_hazelcast_hazelcast_3_5_4.xml b/pubber/.idea/libraries/Gradle__com_hazelcast_hazelcast_3_5_4.xml deleted file mode 100644 index 6b097056b4..0000000000 --- a/pubber/.idea/libraries/Gradle__com_hazelcast_hazelcast_3_5_4.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_librato_metrics_librato_java_2_1_0.xml b/pubber/.idea/libraries/Gradle__com_librato_metrics_librato_java_2_1_0.xml deleted file mode 100644 index d3ab2fa027..0000000000 --- a/pubber/.idea/libraries/Gradle__com_librato_metrics_librato_java_2_1_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_librato_metrics_metrics_librato_5_1_0.xml b/pubber/.idea/libraries/Gradle__com_librato_metrics_metrics_librato_5_1_0.xml deleted file mode 100644 index c588bf6754..0000000000 --- a/pubber/.idea/libraries/Gradle__com_librato_metrics_metrics_librato_5_1_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__com_sun_xml_bind_jaxb_impl_2_3_2.xml b/pubber/.idea/libraries/Gradle__com_sun_xml_bind_jaxb_impl_2_3_2.xml deleted file mode 100644 index 35a975da46..0000000000 --- a/pubber/.idea/libraries/Gradle__com_sun_xml_bind_jaxb_impl_2_3_2.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__commons_codec_commons_codec_1_10.xml b/pubber/.idea/libraries/Gradle__commons_codec_commons_codec_1_10.xml deleted file mode 100644 index c84796132f..0000000000 --- a/pubber/.idea/libraries/Gradle__commons_codec_commons_codec_1_10.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__commons_logging_commons_logging_1_1_1.xml b/pubber/.idea/libraries/Gradle__commons_logging_commons_logging_1_1_1.xml deleted file mode 100644 index b9fb75155c..0000000000 --- a/pubber/.idea/libraries/Gradle__commons_logging_commons_logging_1_1_1.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__io_dropwizard_metrics_metrics_core_3_2_2.xml b/pubber/.idea/libraries/Gradle__io_dropwizard_metrics_metrics_core_3_2_2.xml deleted file mode 100644 index f2223bcf6b..0000000000 --- a/pubber/.idea/libraries/Gradle__io_dropwizard_metrics_metrics_core_3_2_2.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__io_dropwizard_metrics_metrics_jvm_3_2_2.xml b/pubber/.idea/libraries/Gradle__io_dropwizard_metrics_metrics_jvm_3_2_2.xml deleted file mode 100644 index a4fb7c1897..0000000000 --- a/pubber/.idea/libraries/Gradle__io_dropwizard_metrics_metrics_jvm_3_2_2.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__io_grpc_grpc_auth_1_6_1.xml b/pubber/.idea/libraries/Gradle__io_grpc_grpc_auth_1_6_1.xml deleted file mode 100644 index 8308d1661d..0000000000 --- a/pubber/.idea/libraries/Gradle__io_grpc_grpc_auth_1_6_1.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__io_grpc_grpc_context_1_6_1.xml b/pubber/.idea/libraries/Gradle__io_grpc_grpc_context_1_6_1.xml deleted file mode 100644 index 42b3336f05..0000000000 --- a/pubber/.idea/libraries/Gradle__io_grpc_grpc_context_1_6_1.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__io_grpc_grpc_core_1_6_1.xml b/pubber/.idea/libraries/Gradle__io_grpc_grpc_core_1_6_1.xml deleted file mode 100644 index f4249256ab..0000000000 --- a/pubber/.idea/libraries/Gradle__io_grpc_grpc_core_1_6_1.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__io_grpc_grpc_netty_1_6_1.xml b/pubber/.idea/libraries/Gradle__io_grpc_grpc_netty_1_6_1.xml deleted file mode 100644 index 3b8ead556e..0000000000 --- a/pubber/.idea/libraries/Gradle__io_grpc_grpc_netty_1_6_1.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__io_grpc_grpc_protobuf_1_6_1.xml b/pubber/.idea/libraries/Gradle__io_grpc_grpc_protobuf_1_6_1.xml deleted file mode 100644 index 95d433c45d..0000000000 --- a/pubber/.idea/libraries/Gradle__io_grpc_grpc_protobuf_1_6_1.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__io_grpc_grpc_protobuf_lite_1_6_1.xml b/pubber/.idea/libraries/Gradle__io_grpc_grpc_protobuf_lite_1_6_1.xml deleted file mode 100644 index 9a3dd1b89b..0000000000 --- a/pubber/.idea/libraries/Gradle__io_grpc_grpc_protobuf_lite_1_6_1.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__io_grpc_grpc_stub_1_6_1.xml b/pubber/.idea/libraries/Gradle__io_grpc_grpc_stub_1_6_1.xml deleted file mode 100644 index f282c5df26..0000000000 --- a/pubber/.idea/libraries/Gradle__io_grpc_grpc_stub_1_6_1.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__io_jsonwebtoken_jjwt_0_7_0.xml b/pubber/.idea/libraries/Gradle__io_jsonwebtoken_jjwt_0_7_0.xml deleted file mode 100644 index c255c18f27..0000000000 --- a/pubber/.idea/libraries/Gradle__io_jsonwebtoken_jjwt_0_7_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__io_moquette_moquette_broker_0_10.xml b/pubber/.idea/libraries/Gradle__io_moquette_moquette_broker_0_10.xml deleted file mode 100644 index 0751597837..0000000000 --- a/pubber/.idea/libraries/Gradle__io_moquette_moquette_broker_0_10.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__io_netty_netty_buffer_4_1_14_Final.xml b/pubber/.idea/libraries/Gradle__io_netty_netty_buffer_4_1_14_Final.xml deleted file mode 100644 index 30fb818235..0000000000 --- a/pubber/.idea/libraries/Gradle__io_netty_netty_buffer_4_1_14_Final.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__io_netty_netty_codec_4_1_14_Final.xml b/pubber/.idea/libraries/Gradle__io_netty_netty_codec_4_1_14_Final.xml deleted file mode 100644 index 97cd8c9cb9..0000000000 --- a/pubber/.idea/libraries/Gradle__io_netty_netty_codec_4_1_14_Final.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__io_netty_netty_codec_http2_4_1_14_Final.xml b/pubber/.idea/libraries/Gradle__io_netty_netty_codec_http2_4_1_14_Final.xml deleted file mode 100644 index 54abbbe3aa..0000000000 --- a/pubber/.idea/libraries/Gradle__io_netty_netty_codec_http2_4_1_14_Final.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__io_netty_netty_codec_http_4_1_14_Final.xml b/pubber/.idea/libraries/Gradle__io_netty_netty_codec_http_4_1_14_Final.xml deleted file mode 100644 index 58ac06ba5b..0000000000 --- a/pubber/.idea/libraries/Gradle__io_netty_netty_codec_http_4_1_14_Final.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__io_netty_netty_codec_mqtt_4_1_12_Final.xml b/pubber/.idea/libraries/Gradle__io_netty_netty_codec_mqtt_4_1_12_Final.xml deleted file mode 100644 index 68118cd002..0000000000 --- a/pubber/.idea/libraries/Gradle__io_netty_netty_codec_mqtt_4_1_12_Final.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__io_netty_netty_codec_socks_4_1_14_Final.xml b/pubber/.idea/libraries/Gradle__io_netty_netty_codec_socks_4_1_14_Final.xml deleted file mode 100644 index 614e913e87..0000000000 --- a/pubber/.idea/libraries/Gradle__io_netty_netty_codec_socks_4_1_14_Final.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__io_netty_netty_common_4_1_14_Final.xml b/pubber/.idea/libraries/Gradle__io_netty_netty_common_4_1_14_Final.xml deleted file mode 100644 index 1a98e17a91..0000000000 --- a/pubber/.idea/libraries/Gradle__io_netty_netty_common_4_1_14_Final.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__io_netty_netty_handler_4_1_14_Final.xml b/pubber/.idea/libraries/Gradle__io_netty_netty_handler_4_1_14_Final.xml deleted file mode 100644 index 9298ca6e14..0000000000 --- a/pubber/.idea/libraries/Gradle__io_netty_netty_handler_4_1_14_Final.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__io_netty_netty_handler_proxy_4_1_14_Final.xml b/pubber/.idea/libraries/Gradle__io_netty_netty_handler_proxy_4_1_14_Final.xml deleted file mode 100644 index ca38677084..0000000000 --- a/pubber/.idea/libraries/Gradle__io_netty_netty_handler_proxy_4_1_14_Final.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__io_netty_netty_resolver_4_1_14_Final.xml b/pubber/.idea/libraries/Gradle__io_netty_netty_resolver_4_1_14_Final.xml deleted file mode 100644 index b70942e76b..0000000000 --- a/pubber/.idea/libraries/Gradle__io_netty_netty_resolver_4_1_14_Final.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__io_netty_netty_tcnative_boringssl_static_2_0_3_Final.xml b/pubber/.idea/libraries/Gradle__io_netty_netty_tcnative_boringssl_static_2_0_3_Final.xml deleted file mode 100644 index e00975f2d7..0000000000 --- a/pubber/.idea/libraries/Gradle__io_netty_netty_tcnative_boringssl_static_2_0_3_Final.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__io_netty_netty_transport_4_1_14_Final.xml b/pubber/.idea/libraries/Gradle__io_netty_netty_transport_4_1_14_Final.xml deleted file mode 100644 index f055031276..0000000000 --- a/pubber/.idea/libraries/Gradle__io_netty_netty_transport_4_1_14_Final.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__io_netty_netty_transport_native_epoll_4_1_12_Final_linux_x86_64.xml b/pubber/.idea/libraries/Gradle__io_netty_netty_transport_native_epoll_4_1_12_Final_linux_x86_64.xml deleted file mode 100644 index 467269eee3..0000000000 --- a/pubber/.idea/libraries/Gradle__io_netty_netty_transport_native_epoll_4_1_12_Final_linux_x86_64.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__io_netty_netty_transport_native_unix_common_4_1_12_Final.xml b/pubber/.idea/libraries/Gradle__io_netty_netty_transport_native_unix_common_4_1_12_Final.xml deleted file mode 100644 index a3b889ee62..0000000000 --- a/pubber/.idea/libraries/Gradle__io_netty_netty_transport_native_unix_common_4_1_12_Final.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__io_opencensus_opencensus_api_0_5_1.xml b/pubber/.idea/libraries/Gradle__io_opencensus_opencensus_api_0_5_1.xml deleted file mode 100644 index 5cdfe84133..0000000000 --- a/pubber/.idea/libraries/Gradle__io_opencensus_opencensus_api_0_5_1.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__javax_activation_javax_activation_api_1_2_0.xml b/pubber/.idea/libraries/Gradle__javax_activation_javax_activation_api_1_2_0.xml deleted file mode 100644 index f480add6e2..0000000000 --- a/pubber/.idea/libraries/Gradle__javax_activation_javax_activation_api_1_2_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__javax_xml_bind_jaxb_api_2_3_1.xml b/pubber/.idea/libraries/Gradle__javax_xml_bind_jaxb_api_2_3_1.xml deleted file mode 100644 index 434a174d24..0000000000 --- a/pubber/.idea/libraries/Gradle__javax_xml_bind_jaxb_api_2_3_1.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__joda_time_joda_time_2_9_7.xml b/pubber/.idea/libraries/Gradle__joda_time_joda_time_2_9_7.xml deleted file mode 100644 index f45e0d77bd..0000000000 --- a/pubber/.idea/libraries/Gradle__joda_time_joda_time_2_9_7.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__junit_junit_4_13.xml b/pubber/.idea/libraries/Gradle__junit_junit_4_13.xml deleted file mode 100644 index 0cef6bc81e..0000000000 --- a/pubber/.idea/libraries/Gradle__junit_junit_4_13.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__org_apache_httpcomponents_httpclient_4_0_1.xml b/pubber/.idea/libraries/Gradle__org_apache_httpcomponents_httpclient_4_0_1.xml deleted file mode 100644 index 80d562c2fb..0000000000 --- a/pubber/.idea/libraries/Gradle__org_apache_httpcomponents_httpclient_4_0_1.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__org_apache_httpcomponents_httpcore_4_0_1.xml b/pubber/.idea/libraries/Gradle__org_apache_httpcomponents_httpcore_4_0_1.xml deleted file mode 100644 index e203c6b668..0000000000 --- a/pubber/.idea/libraries/Gradle__org_apache_httpcomponents_httpcore_4_0_1.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__org_codehaus_mojo_animal_sniffer_annotations_1_14.xml b/pubber/.idea/libraries/Gradle__org_codehaus_mojo_animal_sniffer_annotations_1_14.xml deleted file mode 100644 index 72ee118d97..0000000000 --- a/pubber/.idea/libraries/Gradle__org_codehaus_mojo_animal_sniffer_annotations_1_14.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__org_eclipse_paho_org_eclipse_paho_client_mqttv3_1_1_0.xml b/pubber/.idea/libraries/Gradle__org_eclipse_paho_org_eclipse_paho_client_mqttv3_1_1_0.xml deleted file mode 100644 index 01970270a7..0000000000 --- a/pubber/.idea/libraries/Gradle__org_eclipse_paho_org_eclipse_paho_client_mqttv3_1_1_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__org_hamcrest_hamcrest_core_1_3.xml b/pubber/.idea/libraries/Gradle__org_hamcrest_hamcrest_core_1_3.xml deleted file mode 100644 index 8262f729c2..0000000000 --- a/pubber/.idea/libraries/Gradle__org_hamcrest_hamcrest_core_1_3.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__org_json_json_20160810.xml b/pubber/.idea/libraries/Gradle__org_json_json_20160810.xml deleted file mode 100644 index 64dc62f3d4..0000000000 --- a/pubber/.idea/libraries/Gradle__org_json_json_20160810.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__org_mockito_mockito_core_1_10_19.xml b/pubber/.idea/libraries/Gradle__org_mockito_mockito_core_1_10_19.xml deleted file mode 100644 index 6aa377ef4f..0000000000 --- a/pubber/.idea/libraries/Gradle__org_mockito_mockito_core_1_10_19.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__org_objenesis_objenesis_2_1.xml b/pubber/.idea/libraries/Gradle__org_objenesis_objenesis_2_1.xml deleted file mode 100644 index e6b52ad30d..0000000000 --- a/pubber/.idea/libraries/Gradle__org_objenesis_objenesis_2_1.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__org_slf4j_slf4j_api_1_7_25.xml b/pubber/.idea/libraries/Gradle__org_slf4j_slf4j_api_1_7_25.xml deleted file mode 100644 index dd23f3e0c1..0000000000 --- a/pubber/.idea/libraries/Gradle__org_slf4j_slf4j_api_1_7_25.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__org_slf4j_slf4j_simple_1_7_5.xml b/pubber/.idea/libraries/Gradle__org_slf4j_slf4j_simple_1_7_5.xml deleted file mode 100644 index 586ac1e599..0000000000 --- a/pubber/.idea/libraries/Gradle__org_slf4j_slf4j_simple_1_7_5.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/libraries/Gradle__org_threeten_threetenbp_1_3_3.xml b/pubber/.idea/libraries/Gradle__org_threeten_threetenbp_1_3_3.xml deleted file mode 100644 index 0fcafe29d0..0000000000 --- a/pubber/.idea/libraries/Gradle__org_threeten_threetenbp_1_3_3.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/misc.xml b/pubber/.idea/misc.xml deleted file mode 100644 index 012255a52d..0000000000 --- a/pubber/.idea/misc.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/pubber/.idea/modules.xml b/pubber/.idea/modules.xml deleted file mode 100644 index f4ca1e7a1b..0000000000 --- a/pubber/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/modules/datafmt.iml b/pubber/.idea/modules/datafmt.iml deleted file mode 100644 index baed4f134d..0000000000 --- a/pubber/.idea/modules/datafmt.iml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/uiDesigner.xml b/pubber/.idea/uiDesigner.xml deleted file mode 100644 index e96534fb27..0000000000 --- a/pubber/.idea/uiDesigner.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/.idea/vcs.xml b/pubber/.idea/vcs.xml deleted file mode 100644 index 26b269dd99..0000000000 --- a/pubber/.idea/vcs.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/pubber/bin/build b/pubber/bin/build deleted file mode 100755 index a2bd6be40a..0000000000 --- a/pubber/bin/build +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash -e - -rundir=$(dirname $0) -cd $rundir/.. - -echo Running in $PWD - -rm -rf build - -./gradlew build -./gradlew shadow diff --git a/pubber/bin/keygen b/pubber/bin/keygen deleted file mode 100755 index 5ee3166d16..0000000000 --- a/pubber/bin/keygen +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash -e - -if [ "$#" != 2 ]; then - echo $0 [type] [out_dir] - false -fi - -type=$1 -cd $2 - -if [ $type == RS256 ]; then - openssl genrsa -out rsa_private.pem 2048 - openssl rsa -in rsa_private.pem -pubout -out rsa_public.pem -elif [ $type == RS256_X509 ]; then - openssl req -x509 -nodes -newkey rsa:2048 -keyout rsa_private.pem -days 1000000 -out rsa_cert.pem -subj "/CN=unused" -else - echo Unknown key type $type. Try one of { RS256, RS256_X509 } - false -fi - -openssl pkcs8 -topk8 -inform PEM -outform DER -in rsa_private.pem -nocrypt > rsa_private.pkcs8 diff --git a/pubber/bin/run b/pubber/bin/run deleted file mode 100755 index ee14f351aa..0000000000 --- a/pubber/bin/run +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash -e - -ROOT=$(realpath $(dirname $0)/../..) -cd $ROOT - -conf_file=local/pubber.json - -if [ ! -f $conf_file ]; then - echo Pubber config file not found: $(realpath $conf_file) - false -fi - -java -jar pubber/build/libs/pubber-1.0-SNAPSHOT-all.jar $conf_file diff --git a/pubber/build.gradle b/pubber/build.gradle deleted file mode 100644 index 1bdfb151a3..0000000000 --- a/pubber/build.gradle +++ /dev/null @@ -1,54 +0,0 @@ -buildscript { - repositories { - maven { - url "https://plugins.gradle.org/m2/" - } - } - dependencies { - classpath "com.github.jengelman.gradle.plugins:shadow:5.2.0" - } -} - -plugins { - id 'com.github.johnrengelman.shadow' version '5.2.0' - id 'java' - id 'maven' -} - -group 'daq-pubber' -version '1.0-SNAPSHOT' - -sourceCompatibility = 1.8 - -jar { - manifest { - attributes 'Main-Class': 'daq.pubber.Pubber' - } -} - -repositories { - mavenCentral() - mavenLocal() - jcenter() -} - -dependencies { - compile group: 'org.slf4j', name: 'slf4j-simple', version:'1.7.5' - compile 'io.jsonwebtoken:jjwt:0.7.0' - compile 'javax.xml.bind:jaxb-api:2.3.1' - compile 'com.sun.xml.bind:jaxb-impl:2.3.2' - compile 'com.google.guava:guava:22.0' - compile 'com.google.cloud:google-cloud-logging:1.7.0' - compile('com.google.api-client:google-api-client:1.22.0') { - exclude group: 'com.google.guava', module: 'guava-jdk5' - } - compile 'com.fasterxml.jackson.core:jackson-databind:2.11.0' - compile('com.google.apis:google-api-services-cloudiot:v1-rev20170922-1.22.0') { - exclude group: 'com.google.guava', module: 'guava-jdk5' - } - compile 'joda-time:joda-time:2.9.7' - compile 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0' - compile 'io.moquette:moquette-broker:0.10' - testCompile group: 'junit', name: 'junit', version: '4.13' - testCompile 'org.mockito:mockito-core:1.10.19' -} diff --git a/pubber/gradle/wrapper/gradle-wrapper.jar b/pubber/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 01b8bf6b1f99cad9213fc495b33ad5bbab8efd20..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54329 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

    <5G2M1WZP5 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 \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn ( ) { - echo "$*" -} - -die ( ) { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save ( ) { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - -exec "$JAVACMD" "$@" diff --git a/pubber/local b/pubber/local deleted file mode 120000 index 0a4de1e828..0000000000 --- a/pubber/local +++ /dev/null @@ -1 +0,0 @@ -../local/ \ No newline at end of file diff --git a/pubber/pubber.iml b/pubber/pubber.iml deleted file mode 100644 index e0065ccd31..0000000000 --- a/pubber/pubber.iml +++ /dev/null @@ -1,92 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/pubber/settings.gradle b/pubber/settings.gradle deleted file mode 100644 index 8b13789179..0000000000 --- a/pubber/settings.gradle +++ /dev/null @@ -1 +0,0 @@ - diff --git a/pubber/src/main/java/daq/pubber/AbstractPoint.java b/pubber/src/main/java/daq/pubber/AbstractPoint.java deleted file mode 100644 index 44bd581c68..0000000000 --- a/pubber/src/main/java/daq/pubber/AbstractPoint.java +++ /dev/null @@ -1,15 +0,0 @@ -package daq.pubber; - -import daq.udmi.Message.PointData; -import daq.udmi.Message.PointState; - -public interface AbstractPoint { - - String getName(); - - PointData getData(); - - void updateData(); - - PointState getState(); -} diff --git a/pubber/src/main/java/daq/pubber/Configuration.java b/pubber/src/main/java/daq/pubber/Configuration.java deleted file mode 100644 index e72d6919d2..0000000000 --- a/pubber/src/main/java/daq/pubber/Configuration.java +++ /dev/null @@ -1,18 +0,0 @@ -package daq.pubber; - -/** - */ -public class Configuration { - public String bridgeHostname = "mqtt.googleapis.com"; - public String bridgePort = "443"; - public String projectId; - public String cloudRegion; - public String registryId; - public String gatewayId; - public String deviceId; - public String sitePath; - public String keyFile = "local/rsa_private.pkcs8"; - public byte[] keyBytes; - public String algorithm = "RS256"; - public Object extraField; -} diff --git a/pubber/src/main/java/daq/pubber/GatewayError.java b/pubber/src/main/java/daq/pubber/GatewayError.java deleted file mode 100644 index fcbc4954c9..0000000000 --- a/pubber/src/main/java/daq/pubber/GatewayError.java +++ /dev/null @@ -1,14 +0,0 @@ -package daq.pubber; - -public class GatewayError { - public String error_type; - public String description; - public String device_id; - public MqttMessageInfo mqtt_message_info; - - public static class MqttMessageInfo { - public String message_type; - public String topic; - public String packet_id; - } -} diff --git a/pubber/src/main/java/daq/pubber/JwtAuthorization.java b/pubber/src/main/java/daq/pubber/JwtAuthorization.java deleted file mode 100644 index cd17be9ba7..0000000000 --- a/pubber/src/main/java/daq/pubber/JwtAuthorization.java +++ /dev/null @@ -1,11 +0,0 @@ -package daq.pubber; - -import java.util.Arrays; - -public class JwtAuthorization { - public String authorization; - - public JwtAuthorization(String jwtToken) { - authorization = jwtToken; - } -} diff --git a/pubber/src/main/java/daq/pubber/MqttPublisher.java b/pubber/src/main/java/daq/pubber/MqttPublisher.java deleted file mode 100644 index ea32788d30..0000000000 --- a/pubber/src/main/java/daq/pubber/MqttPublisher.java +++ /dev/null @@ -1,366 +0,0 @@ -package daq.pubber; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.databind.util.ISO8601DateFormat; -import com.google.common.base.Preconditions; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.RemovalNotification; -import io.jsonwebtoken.JwtBuilder; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.SignatureAlgorithm; -import org.eclipse.paho.client.mqttv3.*; -import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; -import org.joda.time.DateTime; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.nio.charset.StandardCharsets; -import java.security.KeyFactory; -import java.security.PrivateKey; -import java.security.spec.PKCS8EncodedKeySpec; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; - -import static com.google.common.base.Preconditions.checkNotNull; - -/** - * Handle publishing sensor data to a Cloud IoT MQTT endpoint. - */ -public class MqttPublisher { - - private static final Logger LOG = LoggerFactory.getLogger(MqttPublisher.class); - - private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper() - .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) - .setDateFormat(new ISO8601DateFormat()) - .setSerializationInclusion(JsonInclude.Include.NON_NULL); - - // Indicate if this message should be a MQTT 'retained' message. - private static final boolean SHOULD_RETAIN = false; - - private static final int MQTT_QOS = 1; - private static final String CONFIG_UPDATE_TOPIC_FMT = "/devices/%s/config"; - private static final String ERRORS_TOPIC_FMT = "/devices/%s/errors"; - private static final String UNUSED_ACCOUNT_NAME = "unused"; - private static final int INITIALIZE_TIME_MS = 20000; - - private static final String MESSAGE_TOPIC_FORMAT = "/devices/%s/%s"; - private static final String BROKER_URL_FORMAT = "ssl://%s:%s"; - private static final String CLIENT_ID_FORMAT = "projects/%s/locations/%s/registries/%s/devices/%s"; - private static final int PUBLISH_THREAD_COUNT = 10; - private static final String HANDLER_KEY_FORMAT = "%s/%s"; - - private final Semaphore connectionLock = new Semaphore(1); - - private final Map mqttClients = new ConcurrentHashMap<>(); - - private final ExecutorService publisherExecutor = - Executors.newFixedThreadPool(PUBLISH_THREAD_COUNT); - - private final Configuration configuration; - private final String registryId; - - private final AtomicInteger publishCounter = new AtomicInteger(0); - private final AtomicInteger errorCounter = new AtomicInteger(0); - private final AtomicInteger expiredCounter = new AtomicInteger(0); - private final Map> handlers = new ConcurrentHashMap<>(); - private final Map> handlersType = new ConcurrentHashMap<>(); - private final Consumer onError; - - MqttPublisher(Configuration configuration, Consumer onError) { - this.configuration = configuration; - this.registryId = configuration.registryId; - this.onError = onError; - validateCloudIoTOptions(); - } - - void publish(String deviceId, String topic, Object data) { - Preconditions.checkNotNull(deviceId, "publish deviceId"); - LOG.debug("Publishing in background " + registryId + "/" + deviceId); - publisherExecutor.submit(() -> publishCore(deviceId, topic, data)); - } - - private void publishCore(String deviceId, String topic, Object data) { - try { - String payload = OBJECT_MAPPER.writeValueAsString(data); - sendMessage(deviceId, getMessageTopic(deviceId, topic), payload.getBytes()); - LOG.debug("Publishing complete " + registryId + "/" + deviceId); - } catch (Exception e) { - errorCounter.incrementAndGet(); - LOG.warn(String.format("Publish failed for %s: %s", deviceId, e)); - if (configuration.gatewayId == null) { - closeDeviceClient(deviceId); - } else { - close(); - } - } - } - - private void closeDeviceClient(String deviceId) { - MqttClient removed = mqttClients.remove(deviceId); - if (removed != null) { - try { - removed.close(); - } catch (Exception e) { - LOG.error("Error closing MQTT client: " + e.toString()); - } - } - } - - void close() { - Set clients = mqttClients.keySet(); - for (String client : clients) { - closeDeviceClient(client); - } - } - - long clientCount() { - return mqttClients.size(); - } - - private void validateCloudIoTOptions() { - try { - checkNotNull(configuration.bridgeHostname, "bridgeHostname"); - checkNotNull(configuration.bridgePort, "bridgePort"); - checkNotNull(configuration.projectId, "projectId"); - checkNotNull(configuration.cloudRegion, "cloudRegion"); - checkNotNull(configuration.keyBytes, "keyBytes"); - checkNotNull(configuration.algorithm, "algorithm"); - } catch (Exception e) { - throw new IllegalStateException("Invalid Cloud IoT Options", e); - } - } - - private MqttClient newBoundClient(String deviceId) { - try { - String gatewayId = configuration.gatewayId; - LOG.debug("Connecting through gateway " + gatewayId); - MqttClient mqttClient = getConnectedClient(gatewayId); - String topic = String.format("/devices/%s/attach", deviceId); - String payload = ""; - LOG.info("Publishing attach message to topic " + topic); - mqttClient.publish(topic, payload.getBytes(StandardCharsets.UTF_8.name()), MQTT_QOS, SHOULD_RETAIN); - return mqttClient; - } catch (Exception e) { - throw new RuntimeException("While binding client " + deviceId, e); - } - } - - private MqttClient newMqttClient(String deviceId) { - try { - Preconditions.checkNotNull(registryId, "registryId is null"); - Preconditions.checkNotNull(deviceId, "deviceId is null"); - String clientId = getClientId(deviceId); - LOG.info("Creating new mqtt client for " + clientId); - MqttClient mqttClient = new MqttClient(getBrokerUrl(), clientId, - new MemoryPersistence()); - return mqttClient; - } catch (Exception e) { - errorCounter.incrementAndGet(); - throw new RuntimeException("Creating new MQTT client " + deviceId, e); - } - } - - private MqttClient connectMqttClient(String deviceId) { - try { - if (!connectionLock.tryAcquire(INITIALIZE_TIME_MS, TimeUnit.MILLISECONDS)) { - throw new RuntimeException("Timeout waiting for connection lock"); - } - MqttClient mqttClient = newMqttClient(deviceId); - if (mqttClient.isConnected()) { - return mqttClient; - } - LOG.info("Attempting connection to " + registryId + ":" + deviceId); - - mqttClient.setCallback(new MqttCallbackHandler(deviceId)); - mqttClient.setTimeToWait(INITIALIZE_TIME_MS); - - MqttConnectOptions options = new MqttConnectOptions(); - options.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1); - options.setUserName(UNUSED_ACCOUNT_NAME); - options.setMaxInflight(PUBLISH_THREAD_COUNT * 2); - options.setConnectionTimeout(INITIALIZE_TIME_MS); - - options.setPassword(createJwt()); - - mqttClient.connect(options); - - subscribeToUpdates(mqttClient, deviceId); - return mqttClient; - } catch (Exception e) { - throw new RuntimeException("While connecting mqtt client " + deviceId, e); - } finally { - connectionLock.release(); - } - } - - private char[] createJwt() throws Exception { - return createJwt(configuration.projectId, configuration.keyBytes, configuration.algorithm) - .toCharArray(); - } - - private String getClientId(String deviceId) { - // Create our MQTT client. The mqttClientId is a unique string that identifies this device. For - // Google Cloud IoT, it must be in the format below. - return String.format(CLIENT_ID_FORMAT, configuration.projectId, configuration.cloudRegion, - registryId, deviceId); - } - - private String getBrokerUrl() { - // Build the connection string for Google's Cloud IoT MQTT server. Only SSL connections are - // accepted. For server authentication, the JVM's root certificates are used. - return String.format(BROKER_URL_FORMAT, configuration.bridgeHostname, configuration.bridgePort); - } - - private String getMessageTopic(String deviceId, String topic) { - return String.format(MESSAGE_TOPIC_FORMAT, deviceId, topic); - } - - private void subscribeToUpdates(MqttClient client, String deviceId) { - subscribeTopic(client, String.format(CONFIG_UPDATE_TOPIC_FMT, deviceId)); - subscribeTopic(client, String.format(ERRORS_TOPIC_FMT, deviceId)); - } - - private void subscribeTopic(MqttClient client, String updateTopic) { - try { - client.subscribe(updateTopic); - } catch (MqttException e) { - throw new RuntimeException("While subscribing to MQTT topic " + updateTopic, e); - } - } - - public PublisherStats getStatistics() { - return new PublisherStats(); - } - - @SuppressWarnings("unchecked") - public void registerHandler(String deviceId, String mqttTopic, - Consumer handler, Class messageType) { - String key = getHandlerKey(getMessageTopic(deviceId, mqttTopic)); - if (handler == null) { - handlers.remove(key); - handlersType.remove(key); - } else if (handlers.put(key, (Consumer) handler) == null) { - handlersType.put(key, (Class) messageType); - } else { - throw new IllegalStateException("Overwriting existing handler for " + key); - } - } - - private String getHandlerKey(String configTopic) { - return String.format(HANDLER_KEY_FORMAT, registryId, configTopic); - } - - public void connect(String deviceId) { - getConnectedClient(deviceId); - } - - private class MqttCallbackHandler implements MqttCallback { - - private final String deviceId; - - MqttCallbackHandler(String deviceId) { - this.deviceId = deviceId; - } - - /** - * @see MqttCallback#connectionLost(Throwable) - */ - public void connectionLost(Throwable cause) { - LOG.warn("MQTT Connection Lost", cause); - } - - /** - * @see MqttCallback#deliveryComplete(IMqttDeliveryToken) - */ - public void deliveryComplete(IMqttDeliveryToken token) { - } - - /** - * @see MqttCallback#messageArrived(String, MqttMessage) - */ - public void messageArrived(String topic, MqttMessage message) { - String handlerKey = getHandlerKey(topic); - Consumer handler = handlers.get(handlerKey); - Class type = handlersType.get(handlerKey); - if (handler == null) { - onError.accept(new RuntimeException("No registered handler for " + handlerKey)); - } else if (message.toString().length() == 0) { - LOG.warn("Received message is empty for " + handlerKey); - handler.accept(null); - } else { - try { - handler.accept(OBJECT_MAPPER.readValue(message.toString(), type)); - } catch (Exception e) { - onError.accept(e); - } - } - } - } - - private void sendMessage(String deviceId, String mqttTopic, - byte[] mqttMessage) throws Exception { - LOG.debug("Sending message to " + mqttTopic); - getConnectedClient(deviceId).publish(mqttTopic, mqttMessage, MQTT_QOS, SHOULD_RETAIN); - publishCounter.incrementAndGet(); - } - - private MqttClient getConnectedClient(String deviceId) { - try { - String gatewayId = configuration.gatewayId; - if (gatewayId != null && !gatewayId.equals(deviceId)) { - return mqttClients.computeIfAbsent(deviceId, this::newBoundClient); - } - return mqttClients.computeIfAbsent(deviceId, this::connectMqttClient); - } catch (Exception e) { - throw new RuntimeException("While getting mqtt client " + deviceId + ": " + e.toString(), e); - } - } - - /** Load a PKCS8 encoded keyfile from the given path. */ - private PrivateKey loadKeyBytes(byte[] keyBytes, String algorithm) throws Exception { - try { - PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes); - KeyFactory kf = KeyFactory.getInstance(algorithm); - return kf.generatePrivate(spec); - } catch (Exception e) { - throw new IllegalArgumentException("Loading key bytes", e); - } - } - - /** Create a Cloud IoT JWT for the given project id, signed with the given private key */ - protected String createJwt(String projectId, byte[] privateKeyBytes, String algorithm) - throws Exception { - DateTime now = new DateTime(); - // Create a JWT to authenticate this device. The device will be disconnected after the token - // expires, and will have to reconnect with a new token. The audience field should always be set - // to the GCP project id. - JwtBuilder jwtBuilder = - Jwts.builder() - .setIssuedAt(now.toDate()) - .setExpiration(now.plusMinutes(60).toDate()) - .setAudience(projectId); - - if (algorithm.equals("RS256")) { - PrivateKey privateKey = loadKeyBytes(privateKeyBytes, "RSA"); - return jwtBuilder.signWith(SignatureAlgorithm.RS256, privateKey).compact(); - } else if (algorithm.equals("ES256")) { - PrivateKey privateKey = loadKeyBytes(privateKeyBytes, "EC"); - return jwtBuilder.signWith(SignatureAlgorithm.ES256, privateKey).compact(); - } else { - throw new IllegalArgumentException( - "Invalid algorithm " + algorithm + ". Should be one of 'RS256' or 'ES256'."); - } - } - - public class PublisherStats { - public long clientCount = mqttClients.size(); - public int publishCount = publishCounter.getAndSet(0); - public int errorCount = errorCounter.getAndSet(0); - } -} diff --git a/pubber/src/main/java/daq/pubber/Pubber.java b/pubber/src/main/java/daq/pubber/Pubber.java deleted file mode 100644 index 1265b65e53..0000000000 --- a/pubber/src/main/java/daq/pubber/Pubber.java +++ /dev/null @@ -1,287 +0,0 @@ -package daq.pubber; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.base.Preconditions; -import daq.udmi.Entry; -import daq.udmi.Message; -import daq.udmi.Message.Pointset; -import daq.udmi.Message.PointsetState; -import daq.udmi.Message.State; -import java.io.File; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Date; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class Pubber { - - private static final Logger LOG = LoggerFactory.getLogger(Pubber.class); - private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper() - .setSerializationInclusion(JsonInclude.Include.NON_NULL); - - private static final String POINTSET_TOPIC = "events/pointset"; - private static final String SYSTEM_TOPIC = "events/system"; - private static final String STATE_TOPIC = "state"; - private static final String CONFIG_TOPIC = "config"; - private static final String ERROR_TOPIC = "errors"; - - private static final int MIN_REPORT_MS = 200; - private static final int DEFAULT_REPORT_MS = 5000; - private static final int CONFIG_WAIT_TIME_MS = 10000; - private static final int STATE_THROTTLE_MS = 2000; - private static final String CONFIG_ERROR_STATUS_KEY = "config_error"; - private static final int LOGGING_MOD_COUNT = 10; - public static final String KEY_SITE_PATH_FORMAT = "%s/devices/%s/rsa_private.pkcs8"; - - private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); - - private final Configuration configuration; - private final AtomicInteger messageDelayMs = new AtomicInteger(DEFAULT_REPORT_MS); - private final CountDownLatch configLatch = new CountDownLatch(1); - - private final State deviceState = new State(); - private final Pointset devicePoints = new Pointset(); - private final Set allPoints = new HashSet<>(); - - private MqttPublisher mqttPublisher; - private ScheduledFuture scheduledFuture; - private long lastStateTimeMs; - private int sendCount; - - public static void main(String[] args) throws Exception { - if (args.length != 1) { - throw new IllegalArgumentException("Expected [configPath] as argument"); - } - Pubber pubber = new Pubber(args[0]); - pubber.initialize(); - pubber.startConnection(); - LOG.info("Done with main"); - } - - private Pubber(String configFile) { - File configurationFile = new File(configFile); - LOG.info("Reading configuration from " + configurationFile.getAbsolutePath()); - try { - configuration = OBJECT_MAPPER.readValue(configurationFile, Configuration.class); - } catch (Exception e) { - throw new RuntimeException("While reading configuration file " + configurationFile.getAbsolutePath(), e); - } - info(String.format("Starting instance for project %s registry %s", - configuration.projectId, configuration.registryId)); - - initializeDevice(); - addPoint(new RandomPoint("superimposition_reading", 0, 100, "Celsius")); - addPoint(new RandomPoint("recalcitrant_angle", 0, 360, "deg" )); - addPoint(new RandomPoint("faulty_finding", 1, 1, "truth")); - } - - private void initializeDevice() { - deviceState.system.make_model = "DAQ_pubber"; - deviceState.system.firmware.version = "v1"; - deviceState.pointset = new PointsetState(); - devicePoints.extraField = configuration.extraField; - } - - private synchronized void maybeRestartExecutor(int intervalMs) { - if (scheduledFuture == null || intervalMs != messageDelayMs.get()) { - cancelExecutor(); - messageDelayMs.set(intervalMs); - startExecutor(); - } - } - - private synchronized void startExecutor() { - Preconditions.checkState(scheduledFuture == null); - int delay = messageDelayMs.get(); - LOG.info("Starting executor with send message delay " + delay); - scheduledFuture = executor - .scheduleAtFixedRate(this::sendMessages, delay, delay, TimeUnit.MILLISECONDS); - } - - private synchronized void cancelExecutor() { - if (scheduledFuture != null) { - scheduledFuture.cancel(false); - scheduledFuture = null; - } - } - - private void sendMessages() { - try { - sendDeviceMessage(configuration.deviceId); - updatePoints(); - if (sendCount % LOGGING_MOD_COUNT == 0) { - publishLogMessage(configuration.deviceId,"Sent " + sendCount + " messages"); - } - sendCount++; - } catch (Exception e) { - LOG.error("Fatal error during execution", e); - terminate(); - } - } - - private void updatePoints() { - allPoints.forEach(AbstractPoint::updateData); - } - - private void terminate() { - try { - info("Terminating"); - mqttPublisher.close(); - cancelExecutor(); - } catch (Exception e) { - info("Error terminating: " + e.getMessage()); - } - } - - private void startConnection() throws InterruptedException { - connect(); - boolean result = configLatch.await(CONFIG_WAIT_TIME_MS, TimeUnit.MILLISECONDS); - LOG.info("synchronized start config result " + result); - if (!result) { - mqttPublisher.close(); - } - } - - private void addPoint(AbstractPoint point) { - String pointName = point.getName(); - if (devicePoints.points.put(pointName, point.getData()) != null) { - throw new IllegalStateException("Duplicate pointName " + pointName); - } - deviceState.pointset.points.put(pointName, point.getState()); - allPoints.add(point); - } - - private void initialize() { - Preconditions.checkNotNull(configuration.deviceId, "configuration deviceId not defined"); - if (configuration.sitePath != null) { - configuration.keyFile = String.format(KEY_SITE_PATH_FORMAT, configuration.sitePath, - configuration.deviceId); - } - Preconditions.checkState(mqttPublisher == null, "mqttPublisher already defined"); - Preconditions.checkNotNull(configuration.keyFile, "configuration keyFile not defined"); - System.err.println("Loading device key file from " + configuration.keyFile); - configuration.keyBytes = getFileBytes(configuration.keyFile); - mqttPublisher = new MqttPublisher(configuration, this::reportError); - if (configuration.gatewayId != null) { - mqttPublisher.registerHandler(configuration.gatewayId, CONFIG_TOPIC, - this::configHandler, Message.Config.class); - mqttPublisher.registerHandler(configuration.gatewayId, ERROR_TOPIC, - this::errorHandler, GatewayError.class); - } - mqttPublisher.registerHandler(configuration.deviceId, CONFIG_TOPIC, - this::configHandler, Message.Config.class); - } - - private void connect() { - try { - mqttPublisher.connect(configuration.deviceId); - LOG.info("Connection complete."); - } catch (Exception e) { - LOG.error("Connection error", e); - LOG.error("Forcing termination"); - System.exit(-1); - } - } - - private void reportError(Exception toReport) { - if (toReport != null) { - LOG.error("Error receiving message: " + toReport); - Entry report = new Entry(toReport); - deviceState.system.statuses.put(CONFIG_ERROR_STATUS_KEY, report); - publishStateMessage(configuration.deviceId); - } else { - Entry previous = deviceState.system.statuses.remove(CONFIG_ERROR_STATUS_KEY); - if (previous != null) { - publishStateMessage(configuration.deviceId); - } - } - } - - private void info(String msg) { - LOG.info(msg); - } - - private void configHandler(Message.Config config) { - try { - info("Received new config " + config); - final int actualInterval; - if (config != null) { - Integer reportInterval = config.system == null ? null : config.system.report_interval_ms; - actualInterval = Integer.max(MIN_REPORT_MS, - reportInterval == null ? DEFAULT_REPORT_MS : reportInterval); - deviceState.system.last_config = config.timestamp; - } else { - actualInterval = DEFAULT_REPORT_MS; - } - maybeRestartExecutor(actualInterval); - configLatch.countDown(); - publishStateMessage(configuration.deviceId); - reportError(null); - } catch (Exception e) { - reportError(e); - } - } - - private void errorHandler(GatewayError error) { - // TODO: Handle error and give up on device. - info(String.format("%s for %s: %s", - error.error_type, error.device_id, error.description)); - } - - private byte[] getFileBytes(String dataFile) { - Path dataPath = Paths.get(dataFile); - try { - return Files.readAllBytes(dataPath); - } catch (Exception e) { - throw new RuntimeException("While getting data from " + dataPath.toAbsolutePath(), e); - } - } - - private void sendDeviceMessage(String deviceId) { - if (mqttPublisher.clientCount() == 0) { - LOG.error("No connected clients, exiting."); - System.exit(-2); - } - info(String.format("Sending test message for %s/%s", configuration.registryId, deviceId)); - devicePoints.timestamp = new Date(); - mqttPublisher.publish(deviceId, POINTSET_TOPIC, devicePoints); - } - - private void publishLogMessage(String deviceId, String logMessage) { - info(String.format("Sending log message for %s/%s", configuration.registryId, deviceId)); - Message.SystemEvent systemEvent = new Message.SystemEvent(); - systemEvent.logentries.add(new Entry(logMessage)); - mqttPublisher.publish(deviceId, SYSTEM_TOPIC, systemEvent); - } - - private void publishStateMessage(String deviceId) { - lastStateTimeMs = sleepUntil(lastStateTimeMs + STATE_THROTTLE_MS); - deviceState.timestamp = new Date(); - info("Sending state message for device " + deviceId + " at " + deviceState.timestamp); - mqttPublisher.publish(deviceId, STATE_TOPIC, deviceState); - } - - private long sleepUntil(long targetTimeMs) { - long currentTime = System.currentTimeMillis(); - long delay = targetTimeMs - currentTime; - try { - if (delay > 0) { - Thread.sleep(delay); - } - return System.currentTimeMillis(); - } catch (Exception e) { - throw new RuntimeException("While sleeping for " + delay, e); - } - } -} diff --git a/pubber/src/main/java/daq/pubber/RandomPoint.java b/pubber/src/main/java/daq/pubber/RandomPoint.java deleted file mode 100644 index dcf0ff0a03..0000000000 --- a/pubber/src/main/java/daq/pubber/RandomPoint.java +++ /dev/null @@ -1,42 +0,0 @@ -package daq.pubber; - -import daq.udmi.Message.PointData; -import daq.udmi.Message.PointState; - -public class RandomPoint implements AbstractPoint { - - private final String name; - private final double min; - private final double max; - private final PointData data = new PointData(); - private final PointState state = new PointState(); - - public RandomPoint(String name, double min, double max, String units) { - this.name = name; - this.min = min; - this.max = max; - this.state.fault = max == min; - this.state.units = units; - updateData(); - } - - @Override - public void updateData() { - data.present_value = Math.round(Math.random() * (max - min) + min); - } - - @Override - public PointState getState() { - return state; - } - - @Override - public String getName() { - return name; - } - - @Override - public PointData getData() { - return data; - } -} diff --git a/pubber/src/main/java/daq/udmi/Entry.java b/pubber/src/main/java/daq/udmi/Entry.java deleted file mode 100644 index 25201edc72..0000000000 --- a/pubber/src/main/java/daq/udmi/Entry.java +++ /dev/null @@ -1,26 +0,0 @@ -package daq.udmi; - -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; -import java.util.Date; - -public class Entry { - public String message; - public String detail; - public String category = "com.acme.pubber"; - public Integer level = 500; - public Date timestamp = new Date(); - - public Entry(String message) { - this.message = message; - } - - public Entry(Exception e) { - message = e.toString(); - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - e.printStackTrace(new PrintStream(outputStream)); - detail = outputStream.toString(); - category = e.getStackTrace()[0].getClassName(); - level = 800; - } -} diff --git a/pubber/src/main/java/daq/udmi/Message.java b/pubber/src/main/java/daq/udmi/Message.java deleted file mode 100644 index c15f9c842c..0000000000 --- a/pubber/src/main/java/daq/udmi/Message.java +++ /dev/null @@ -1,76 +0,0 @@ -package daq.udmi; - -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -@SuppressWarnings("unused") -public class Message { - - public static class State extends UdmiBase { - public SystemState system = new SystemState(); - public PointsetState pointset; - } - - public static class Config extends UdmiBase { - public SystemConfig system; - public PointsetConfig pointset; - public GatewayConfig gateway; - } - - public static class Pointset extends UdmiBase { - public Map points = new HashMap<>(); - public Object extraField; - } - - public static class SystemEvent extends UdmiBase { - public List logentries = new ArrayList<>(); - } - - public static class PointsetState { - public Map points = new HashMap<>(); - } - - public static class PointsetConfig { - public Map points = new HashMap<>(); - } - - public static class PointConfig { - } - - public static class GatewayConfig { - public List proxy_ids; - } - - public static class SystemState { - public String make_model; - public Bundle firmware = new Bundle(); - public boolean operational; - public Date last_config; - public Map statuses = new HashMap<>(); - } - - public static class SystemConfig { - public Integer report_interval_ms; - } - - public static class PointData { - public Object present_value; - } - - public static class PointState { - public String units; - public Boolean fault; - } - - public static class Bundle { - public String version; - } - - public static class UdmiBase { - public Integer version = 1; - public Date timestamp = new Date(); - } -} diff --git a/schemas/simple/simple.json b/schemas/simple/simple.json deleted file mode 100644 index fa31b8e8d0..0000000000 --- a/schemas/simple/simple.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "type" : "object", - "$schema": "http://json-schema.org/draft-07/schema#", - "properties" : { - "rectangle" : {"$ref" : "#/definitions/Rectangle" } - }, - "required": [ - "rectangle" - ], - "definitions" : { - "size" : { - "type" : "number", - "minimum" : 0 - }, - "Rectangle" : { - "type" : "object", - "required": [ - "a", - "b" - ], - "properties" : { - "a" : {"$ref" : "#/definitions/size"}, - "b" : {"$ref" : "#/definitions/size"} - } - } - } -} \ No newline at end of file diff --git a/schemas/simple/simple.tests/error.json b/schemas/simple/simple.tests/error.json deleted file mode 100644 index 361ce8baae..0000000000 --- a/schemas/simple/simple.tests/error.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "rectangle" : { - "a" : -4, - "b" : 5 - } -} diff --git a/schemas/simple/simple.tests/error.out b/schemas/simple/simple.tests/error.out deleted file mode 100644 index d5320ed8a3..0000000000 --- a/schemas/simple/simple.tests/error.out +++ /dev/null @@ -1,4 +0,0 @@ -Validating 1 schemas - Validating 1 files against simple.json - Against input simple.tests/error.json - #/rectangle/a: -4 is not greater or equal to 0 diff --git a/schemas/simple/simple.tests/example.json b/schemas/simple/simple.tests/example.json deleted file mode 100644 index e6751b6099..0000000000 --- a/schemas/simple/simple.tests/example.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "rectangle" : { - "a" : 4, - "b" : 5 - } -} diff --git a/schemas/simple/simple.tests/example.out b/schemas/simple/simple.tests/example.out deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/schemas/simple/simple.tests/simple.json b/schemas/simple/simple.tests/simple.json deleted file mode 100644 index fa31b8e8d0..0000000000 --- a/schemas/simple/simple.tests/simple.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "type" : "object", - "$schema": "http://json-schema.org/draft-07/schema#", - "properties" : { - "rectangle" : {"$ref" : "#/definitions/Rectangle" } - }, - "required": [ - "rectangle" - ], - "definitions" : { - "size" : { - "type" : "number", - "minimum" : 0 - }, - "Rectangle" : { - "type" : "object", - "required": [ - "a", - "b" - ], - "properties" : { - "a" : {"$ref" : "#/definitions/size"}, - "b" : {"$ref" : "#/definitions/size"} - } - } - } -} \ No newline at end of file diff --git a/schemas/simple/simple.tests/simple.out b/schemas/simple/simple.tests/simple.out deleted file mode 100644 index 85d5807ab3..0000000000 --- a/schemas/simple/simple.tests/simple.out +++ /dev/null @@ -1,4 +0,0 @@ -Validating 1 schemas - Validating 1 files against simple.json - Against input simple.tests/simple.json - #: required key [rectangle] not found diff --git a/schemas/udmi/README.md b/schemas/udmi/README.md deleted file mode 100644 index b0c450fa94..0000000000 --- a/schemas/udmi/README.md +++ /dev/null @@ -1,163 +0,0 @@ -# UDMI Schema - -The Universal Device Management Interface (UDMI) provides a high-level specification for the -management and operation of physical IoT systems. This data is typically exchanged -with a cloud entity that can maintain a "digital twin" or "shadow device" in the cloud. -Nominally meant for use with [Googe's Cloud IoT Core](https://cloud.google.com/iot/docs/), -as a schema it can be applied to any set of data or hosting setup. Additionally, the schema -has provisions for basic telemetry ingestion, such as datapoint streaming from an IoT device. - -By deisgn, this schema is intended to be: -* Universal: Apply to all subsystems in a building, not a singular vertical solution. -* Device: Operations on an IoT _device_, a managed entity in physical space. -* Management: Focus on device _management_, rather than command & control. -* Interface: Define an interface specification, rather than a client-library or -RPC mechanism. - -See the associated [UDMI Tech Stack](TECH_STACK.md) for details about transport mechanism -outside of the core schema definition. For questions and discussion pertaining to this topic, -please join/monitor the -[daq-users@googlegroups.com](https://groups.google.com/forum/#!forum/daq-users) email list - -## Use Cases - -The essence behind UDMI is an automated mechanism for IoT system management. Many current -systems require direct-to-device access, such as through a web browser or telnet/ssh session. -These techniques do not scale to robust managed ecosystems since they rely too heavily on -manual operation (aren't automated), and increase the security exposure of the system -(since they need to expose these management ports). - -UDMI is intended to support a few primary use-cases: -* _Telemetry Ingestion_: Ingest device data points in a standardized format. -* [_Gateway Proxy_](docs/gateway.md): Proxy data/connection for non-UDMI devices, -allowing adaptation to legacy systems. -* _On-Prem Actuation_: Ability to effect on-prem device behavior. -* _Device Testability_: e.g. Trigger a fake alarm to test reporting mechanims. -* _Commissioning Tools_: Streamline complete system setup and install. -* _Operational Diagnostics_: Make it easy for system operators to diagnoe basic faults. -* _Status and Logging_: Report system operational metrics to hosting infrastructure. -* _Key Rotation_: Manage encryption keys and certificates in accordance with best practice. -* _Credential Exchange_: Bootstrap higher-layer authentication to restricted resources. -* _Firmware Updates_: Initiate, monitor, and track firmware updates across an entire fleet -of devices. -* _On-Prem Discovery_: Enumerate and on-prem devices to aid setup or anomaly detection. - -All these situations are conceptually about _management_ of devices, which is conceptually -different than the _control_ or _operation_. These concepts are similar to the _management_, -_control_, and _data_ planes of -[Software Defined Networks](https://queue.acm.org/detail.cfm?id=2560327). -Once operational, the system should be able to operate completely autonomoulsy from the -management capabilities, which are only required to diagnose or tweak system behavior. - -## Design Philiosphy - -In order to provide for management automation, UDMI strives for the following principles: -* Secure and Authenticated: Requires a propertly secure and authenticated channel -from the device to managing infrastructure. -* Declarative Specification: The schema describes the _desired_ state of the system, -relying on the underlying mechanisms to match actual state with desired state. This is -conceptually similar to Kubernetes-style configuraiton files. -* Minimal Elegant Design: Initially underspecified, with an eye towards making it easy to -add new capabilities in the future. It is easier to add something than it is to remove it. -* Reduced Choices: In the long run, choice leads to more work -to implement, and more ambiguity. Strive towards having only _one_ way of doing each thing. -* Structure and Clarity: This is not a "compressed" format and not designed for -very large structures or high-bandwidth streams. -* Property Names:Uses snake_case convention for property names. -* Resource Names: Overall structure (when flattened to paths), follows the -[API Resource Names guidline](https://cloud.google.com/apis/design/resource_names). - -## Schema Structure - -Schemas are broken down into several top-level sub-schemas that are invoked for -different aspects of device management: -* Device _state_ ([example](state.tests/example.json)), sent from device to cloud, -defined by [state.json](state.json). There is one current _state_ per device, -which is considered sticky until a new state message is sent. -is comprised of several subsections (e.g. _system_ or _pointset_) that describe the -relevant sub-state components. -* Device _config_ ([example](config.tests/example.json)), passed from cloud to device, -defined by [config.json](config.json). There is one active _config_ per device, -which is considered current until a new config is recevied. -* Message _envelope_ ([example](envelope.tests/example.json)) for server-side -attributes of received messages, defined by [envelope.json](envelope.json). This is -automatically generated by the transport layer and is then available for server-side -processing. -* Device _metadata_ ([example](metadata.tests/example.json)) stored in the cloud about a device, -but not directly available to or on the device, defined by [metadata.json](metadata.json). -This is essentially a specification about how the device should be configured or -expectations about what the device should be doing. -* Streaming device telemetry, which can take on several different forms, depending on the intended -use, e.g.: - * Streaming _pointset_ ([example](pointset.tests/example.json)) from device to cloud, - defined by [pointset.json](pointset.json). _pointset_ is used for delivering a - set of data point telemetry. - * Core _system_ messages ([example](system.tests/example.json)) from devices, such as log - entries and access logs, defined by [system.json](system.json). - * Local _discover_ messages ([example](discover.tests/example.json)) that show the - results of local scans or probes to determine which devices are on the local network, - defined by [discover.json](discover.json). - -A device client implementation will typically only be aware of the _state_, _config_, and -one or more telemetry messages (e.g. _pointset_), while all others are meant for the supporting -infrastructure. Additionally, the _state_ and _config_ parts are comprised of several distinct -subsections (e.g. _system_, _pointset_, or _gateway_) that relate to various bits of functionality. - -## Validation - -To verify correct operation of a real system, follow the instructions outlined in the -[validator subsystem docs](../../docs/validator.md), which provides for a suitable -communication channel. Additional sample messages are easy to include in the regression -suite if there are new cases to test. - -## Message Detail Notes - -### State Message - -* See notes below about 'State status' fields. -* There is an implicit minimum update interval of _one second_ applied to state updates, and it -is considered an error to update device state more often than that. -* `last_config` should be the timestamp _from_ the `timestamp` field of the last successfully -parsed `config` message. - -### Config Message - -* `sample_rate_sec`: Sampling rate for the system, which should proactively send an -update (e.g. _pointset_, _logentry_, _discover_ message) at this interval. -* `sample_limit_sec`: Minimum time between sample updates. Updates that happen faster than this time -(e.g. due to _cov_ events) should be coalesced so that only the most recent update is sent. -* `fix_value`: Fix a value to be used during diagnostics and operational use. Should -override any operational values, but not override alarm conditions. -* `min_loglevel`: Indicates the minimum loglevel for reporting log messages below which log entries -should not be sent. See note below for a description of the level value. - -### Logentry Message - -* See notes below about 'logentry entries' fields. - -### State status and logentry entries fields - -The State and System/logentry messages both have `status` and `entries` sub-fields, respectivly, that -follow the same structure. -* State `status` entries represent 'sticky' conditions that persist until the situation is cleared, -e.g. "device disconnected". -* A `statuses` entry is a map of 'sticky' conditions that are keyed on a value that can be -used to manage updates by a particular (device dependent) subsystem. -* Logentry `entries` fields are transitory event that happen, e.g. "connection failed". -* The log `entries` field is an array that can be used to collaesce multiple log updates into -one message. -* Config parse errors should be represented as a system-level device state `status` entry. -* The `message` field sould be a one-line representation of the triggering condition. -* The `detail` field can be multi-line and include more detail, e.g. a complete program -stack-trace. -* The `category` field is a device-specific representation of which sub-system the message comes -from. In a Java environment, for example, it would be the fully qualified path name of the Class -triggering the message. -* A `status` or `statuses` `timestamp` field should be the timestamp the condition was triggered, -or most recently updated. It might be different than the top-level message `timestamp` if the -condition is not checked often or is sticky until it's cleared. -* A logentry `entries` `timestamp` field is the time that the event occured, which is potentially -different than the top-level `timestamp` field (which is when the log was sent). -* The status `level` should conform to the numerical -[Stackdriver LogEntry](https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#logseverity) -levels. The `DEFAULT` value of 0 is not allowed (lowest value is 100, maximum 800). diff --git a/schemas/udmi/TECH_STACK.md b/schemas/udmi/TECH_STACK.md deleted file mode 100644 index 86d3c0ab4e..0000000000 --- a/schemas/udmi/TECH_STACK.md +++ /dev/null @@ -1,46 +0,0 @@ -# UDMI Technology Stack - -The complete UDMI specificaiton (super set of the base schema), specifies a complete -technology stack for compliant IoT devices. - -# Core Requirements - -* [Google Cloud's MQTT Protocol Bridge](https://cloud.google.com/iot/docs/how-tos/mqtt-bridge). - * This is _not_ the same as a generic MQTT Broker, but it is compatible with standard client-side libraries. - * Other transports (non-Google MQTT, CoAP, etc...) are acceptable with prior approval. - * Connected to a specific Cloud IoT Registry designated for each site-specific project. -* Utilizes the MQTT Topic table listed below. -* JSON encoding following the core [UDMI Schema](README.md), specifying the semantic structure of the data. -* Passes the [DAQ Validation Tool](../../docs/validator.md) for all requirements. - -# MQTT Topic Table - -| Type | Category | subFolder | MQTT Topic | Schema File | -|----------|----------|-----------|----------------------------------------|---------------| -| state | state | _n/a_ | `/devices/{device_id}/state` | state.json | -| config | config | _n/a_ | `/devices/{device-id}/config` | config.json | -| pointset | event | pointset | `/devices/{device-id}/events/pointset` | pointset.json | -| system | event | system | `/devices/{device-id}/events/system` | system.json | - -# Backend Systems - -Any backend system (in a GCP project) should adhere to the following guidelines: -* All messages to/from the devices should conform to the UDMI schema payloads (pass validation). -* All exchanges with the devices should go through a PubSub topic: - * The _state_ and _event_ messages are published to a topic configured through the IoT Core registry. - * If necessary, any _config_ or _command_ messages should go through a PubSub topic, and then converted to the requisite Cloud IoT - config write using a simple cloud function. -* To make data persistent, it can be written to a back-end database, e.g. Firestore. See the `device_telemetry` and - `device_state` [example cloud functions](../../firebase/functions/index.js) for details. -* A similar function called `device_config` shows how PubSub can be used to update the Cloud IoT configuration. - -A config push can be tested with something like: - -``` -gcloud pubsub topics publish target \ - --attribute subFolder=config,deviceId=AHU-1,projectId=bos-daq-testing,cloudRegion=us-central1,deviceRegistryId=registrar_test \ - --message '{"version": 1, "timestamp": "2019-01-17T14:02:29.364Z"}' -``` - -The reason for the redirection of any data through a PubSub topic is so that the Cloud IoT registry, if necessary, -can be housed in a different cloud project from the backend applications. diff --git a/schemas/udmi/config.json b/schemas/udmi/config.json deleted file mode 100644 index 73f19b0b4b..0000000000 --- a/schemas/udmi/config.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "title": "Device Config Schema", - "type": "object", - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false, - "required": [ - "timestamp", - "version" - ], - "properties": { - "timestamp": { - "type": "string", - "format": "date-time" - }, - "version": { - "enum": [ - 1 - ] - }, - "system": { - "$ref": "file:config_system.json#" - }, - "gateway": { - "$ref": "file:config_gateway.json#" - }, - "localnet": { - "$ref": "file:config_localnet.json#" - }, - "pointset": { - "$ref": "file:config_pointset.json#" - } - } -} diff --git a/schemas/udmi/config.tests/empty.json b/schemas/udmi/config.tests/empty.json deleted file mode 100644 index 2c63c08510..0000000000 --- a/schemas/udmi/config.tests/empty.json +++ /dev/null @@ -1,2 +0,0 @@ -{ -} diff --git a/schemas/udmi/config.tests/empty.out b/schemas/udmi/config.tests/empty.out deleted file mode 100644 index c9aa2803fc..0000000000 --- a/schemas/udmi/config.tests/empty.out +++ /dev/null @@ -1,6 +0,0 @@ -Validating 1 schemas - Validating 1 files against config.json - Against input config.tests/empty.json - #: 2 schema violations found - #: required key [timestamp] not found - #: required key [version] not found diff --git a/schemas/udmi/config.tests/errors.json b/schemas/udmi/config.tests/errors.json deleted file mode 100644 index 407a7c9eb0..0000000000 --- a/schemas/udmi/config.tests/errors.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "version": 1, - "timestamp": "2018-08-26T21:39:29.364Z", - "properties": { - "make_model": "com.yoyodine.flux_capacitor", - "whoowhoo": true, - "release": "231_rev_8" - }, - "type": "config", - "system": { - }, - "points": { - }, - "pointset": { - "sample_rate_sec": "5", - "version": 1, - "id": "miXeD_CaSE", - "timestamp": "2018-08-26T21:39:29.364Z", - "properties": { - "device_id": "33895507", - "object_name": "UK-BRH-XX_AHU-001", - }, - "points": { - "return_air_temperature_sensor": { - "object_type": "analog_input", - "units": "Degrees Celsius" - } - } - } -} diff --git a/schemas/udmi/config.tests/errors.out b/schemas/udmi/config.tests/errors.out deleted file mode 100644 index 80edaa341f..0000000000 --- a/schemas/udmi/config.tests/errors.out +++ /dev/null @@ -1,16 +0,0 @@ -Validating 1 schemas - Validating 1 files against config.json - Against input config.tests/errors.json - #: 10 schema violations found - #/pointset: 7 schema violations found - #/pointset/points/return_air_temperature_sensor: 2 schema violations found - #/pointset/points/return_air_temperature_sensor: extraneous key [object_type] is not permitted - #/pointset/points/return_air_temperature_sensor: extraneous key [units] is not permitted - #/pointset/sample_rate_sec: expected type: Number, found: String - #/pointset: extraneous key [id] is not permitted - #/pointset: extraneous key [properties] is not permitted - #/pointset: extraneous key [timestamp] is not permitted - #/pointset: extraneous key [version] is not permitted - #: extraneous key [points] is not permitted - #: extraneous key [properties] is not permitted - #: extraneous key [type] is not permitted diff --git a/schemas/udmi/config.tests/example.json b/schemas/udmi/config.tests/example.json deleted file mode 100644 index 164fb358b2..0000000000 --- a/schemas/udmi/config.tests/example.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "version": 1, - "timestamp": "2018-08-26T21:39:29.364Z", - "system": { - "min_loglevel": 500 - }, - "pointset": { - "sample_limit_sec": 2, - "sample_rate_sec": 500, - "points": { - "return_air_temperature_sensor": { - }, - "nexus_sensor": { - "fix_value": 21.1 - } - } - } -} diff --git a/schemas/udmi/config.tests/example.out b/schemas/udmi/config.tests/example.out deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/schemas/udmi/config.tests/fcu.json b/schemas/udmi/config.tests/fcu.json deleted file mode 100644 index 03380428c8..0000000000 --- a/schemas/udmi/config.tests/fcu.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "version": 1, - "timestamp": "2019-01-17T14:02:29.364Z", - "system": { - "max_update_ms": 50000, - "min_loglevel": 500 - }, - "pointset": { - "points": { - "space_temperature_sensor": { - }, - "fan_run_status": { - "fix_value": true - }, - "fan_run_enable": { - "fix_value": false - }, - "chilled_water_valve_percentage_command": { - "min_update_ms": 1000 - } - } - } -} diff --git a/schemas/udmi/config.tests/fcu.out b/schemas/udmi/config.tests/fcu.out deleted file mode 100644 index f81283bace..0000000000 --- a/schemas/udmi/config.tests/fcu.out +++ /dev/null @@ -1,6 +0,0 @@ -Validating 1 schemas - Validating 1 files against config.json - Against input config.tests/fcu.json - #: 2 schema violations found - #/pointset/points/chilled_water_valve_percentage_command: extraneous key [min_update_ms] is not permitted - #/system: extraneous key [max_update_ms] is not permitted diff --git a/schemas/udmi/config.tests/gateway.json b/schemas/udmi/config.tests/gateway.json deleted file mode 100644 index 294aabb2ce..0000000000 --- a/schemas/udmi/config.tests/gateway.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 1, - "timestamp": "2018-08-26T21:39:29.364Z", - "gateway": { - "proxy_ids": [ "AHU-123", "SMS-81", "991" ] - } -} diff --git a/schemas/udmi/config.tests/gateway.out b/schemas/udmi/config.tests/gateway.out deleted file mode 100644 index 1f85426706..0000000000 --- a/schemas/udmi/config.tests/gateway.out +++ /dev/null @@ -1,4 +0,0 @@ -Validating 1 schemas - Validating 1 files against config.json - Against input config.tests/gateway.json - #/gateway/proxy_ids/2: string [991] does not match pattern ^[A-Z]{3}-[1-9][0-9]{0,2}$ diff --git a/schemas/udmi/config.tests/proxy.json b/schemas/udmi/config.tests/proxy.json deleted file mode 100644 index 6f56202964..0000000000 --- a/schemas/udmi/config.tests/proxy.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "version": 1, - "timestamp": "2018-08-26T21:39:29.364Z", - "system": { - "min_loglevel": 500 - }, - "localnet": { - "subsystem": { - "bacnet": { - "local_id": "0x78ce1900" - } - } - }, - "pointset": { - "sample_limit_sec": 2, - "sample_rate_sec": 500, - "points": { - "return_air_temperature_sensor": { - "ref": "BV23.present_value" - } - } - } -} diff --git a/schemas/udmi/config.tests/proxy.out b/schemas/udmi/config.tests/proxy.out deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/schemas/udmi/config.tests/rotate.json b/schemas/udmi/config.tests/rotate.json deleted file mode 100644 index 652a698ba0..0000000000 --- a/schemas/udmi/config.tests/rotate.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "version": 1, - "timestamp": "2018-08-26T21:39:29.364Z", - "system": { - "auth_key": { - "private": "pkcs8:MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQD2PpibhV7vs1ZqGXsV3bCW2p1+WScg6QUNQQb1Ua8pjwIrOQzPfTROpAlxuBAlSbC+aDIz/NrAF0E7tNJx5N8Zk0ekIoqCEVGx/0XuJtyvSYESBclCD7bD3d6KUHcVOK/7hVo7nVnrEjjmihdsz1TSqxmIiNcSe55xboqtJBJLMb9yE646Y/P/kRKCOurR73h3a1N5ipVgpflyMVEW0z/B6GPTc4FRMCAv/6+Mp7v9kjZ/rJa7VwgSMLl/AJ1xyiH3ScQN2dBTCxeGlOu2Ed4v8Rse3OKbOyIbiXQqPeOdys7+CdAtng7qgDLQzinA1r+1YDeSgpLIEHnsnXHBBz1zAgMBAAECggEACm8ilkxzdmK6AarsvUN0jR/cVpM+hjV5glNEETcR3gfyRpSXR199zOtEfy4WeQ4DUD4oCm3ncwZJPFdwJ2VUUsgb3AeeqN5FAO7ZLrs01LSfpHzcR1FVJD2NhXzdXufVBSpkZWxIeB6AjLxDO9gZNwgK/+8UdfMJBrNxat7Ba7AtrYCaAcqh8ewsoGNJte9OC1ubLSvw5p/88XaBYyhN2MLrrOvv7hezsxVakUquPK0xCekV+ScK+6ezrtZVIkvg2ozlF2cffHRoQEjBDju/qQD3dsBAkqol7Lw25KntrM+wBSyCwD04eFzICeDYUBER20SeKEzYRCOek5TgKIeb8QKBgQD/syGWNfE7ZnlswdXYTaHCgCEgQg4N4wwqUva81agAuJbXYXPiBLq0qDiieyyPIT7qU/uCF+R25OJAl/228cVbkhyXa4TAjM5EAAuHeyOwJi+ZBE+c2Mo4Z4mJoXjLzNSvF+ytRQjoAXiErZ4+Kl6wI7zgeIA+SsA0Yy2qStJSKwKBgQD2iJ9bL0FtC/HkkgiCOblLJ1nSiMiTbDAcm9KbeeRDRVpbsYzdVkOoq1s5z6M6MdWVFIqmXL1ROlVyfesG5Dk3AbssbBt0qiF5ZXEF7N33Bqft/LW2U3mdwLVfQLJwtRZ/Uu+yGJ0y7tCEIdCsuaYRkNtZmSIU+ZcwUMr5ks5F2QKBgQC8R6mmkqfDhmxIod4VvOwsbO53c0wn+5RcoeRfHa/sf/9KLs8GkVbtaaTyN2KTLfbG0voyS+eFiHn0+DXw/MvG5qq48Im6wrOrLKFQrGKV9Tg9IwiARL16lPqYZlatMnE1UJeM6nVpaJPWloUb31UDu/z7CJ/dvmsS6Cia6Sc/KwKBgQC3LK/qmmPsV/G0uORljeok8uoESeltz/a3avfC2YBGk2MdugBF/HBtBFTV0XcgKCLfj9Gs5j8r+UG/vdtA1ZXFTx35VaHYvwf8IOknU+VgQ6vGYfvJqqA0HBkm2vU6VPKQS9kY5Lz4OQTpCA76Jz5C0vSH0AXIu+If3gfSA8gLkQKBgGcnKKp2lgIWh76ed4fpHD1dLH9naSF9GvxBEVAxfhfndMSx/hpkmbkO+78FPSDGqPLL5pc72davdrJfRg8aGi5+e2qb67y0Kd0+vlnUY/xv970/LEKDZmNhQreLTDo/wPpOSW75B6GjPhfNdc5znDUUibn6RMqyYcVOm8bLpqkZ" - } - }, - "pointset": { - "points": { - "return_air_temperature_sensor": { - "fix_value": 21.1 - } - } - } -} diff --git a/schemas/udmi/config.tests/rotate.out b/schemas/udmi/config.tests/rotate.out deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/schemas/udmi/config.tests/smartprimus.json b/schemas/udmi/config.tests/smartprimus.json deleted file mode 100644 index 971290d1d5..0000000000 --- a/schemas/udmi/config.tests/smartprimus.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "version": 1, - "timestamp": "2019-01-17T14:02:29.364Z", - "system": { - }, - "pointset": { - "sample_rate_sec": 2, - "points": { - "space_temperature_sensor": { - }, - "fan_run_status": { - "fix_value": true - }, - "fan_run_enable": { - "fix_value": false - }, - "chilled_water_valve_percentage_command": { - } - } - } -} diff --git a/schemas/udmi/config.tests/smartprimus.out b/schemas/udmi/config.tests/smartprimus.out deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/schemas/udmi/config_gateway.json b/schemas/udmi/config_gateway.json deleted file mode 100644 index be0ba44063..0000000000 --- a/schemas/udmi/config_gateway.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "title": "Gateway Config Snippet", - "type": "object", - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false, - "required": [ - "proxy_ids" - ], - "properties": { - "proxy_ids": { - "type": "array", - "items": { - "type": "string", - "pattern": "^[A-Z]{3}-[1-9][0-9]{0,2}$" - } - } - } -} diff --git a/schemas/udmi/config_localnet.json b/schemas/udmi/config_localnet.json deleted file mode 100644 index 4177f240d6..0000000000 --- a/schemas/udmi/config_localnet.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "title": "Proxy Device Config Snippet", - "type": "object", - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false, - "properties": { - "subsystem": { - "type": "object", - "patternProperties": { - "^[a-z0-9-]+$": { - "additionalProperties": false, - "properties": { - "local_id": { - "type": "string" - } - }, - "required": [ - "local_id" - ] - } - } - } - }, - "required": [ - "subsystem" - ] -} diff --git a/schemas/udmi/config_pointset.json b/schemas/udmi/config_pointset.json deleted file mode 100644 index a7ec32f936..0000000000 --- a/schemas/udmi/config_pointset.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "title": "pointset config snippet", - "type": "object", - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false, - "properties": { - "sample_limit_sec": { - "type": "number", - "minimum": 1, - "maximum": 86400 - }, - "sample_rate_sec": { - "type": "number", - "minimum": 1, - "maximum": 86400 - }, - "points": { - "additionalProperties": false, - "patternProperties": { - "^[a-z][a-z0-9]*(_[a-z0-9]+)*$": { - "additionalProperties": false, - "properties": { - "ref": { - "type": "string" - }, - "fix_value": { - "type": ["number", "string", "boolean"] - } - } - } - } - } - } -} diff --git a/schemas/udmi/config_system.json b/schemas/udmi/config_system.json deleted file mode 100644 index 10a3da3ba2..0000000000 --- a/schemas/udmi/config_system.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "title": "System Config snippet", - "type": "object", - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false, - "properties": { - "min_loglevel": { - "type": "number", - "minimum": 100, - "maximum": 800 - }, - "auth_key": { - "type": "object", - "additionalProperties": false, - "properties": { - "private": { - "type": "string" - } - }, - "required": [ - "private" - ] - } - } -} diff --git a/schemas/udmi/discover.json b/schemas/udmi/discover.json deleted file mode 100644 index 8abd70e24c..0000000000 --- a/schemas/udmi/discover.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "title": "Device discover schema", - "type": "object", - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false, - "properties": { - "timestamp": { - "type": "string", - "format": "date-time" - }, - "version": { - "enum": [ - 1 - ] - }, - "protocol": { - "type": "string" - }, - "local_id": { - "type": "string" - }, - "points": { - "additionalProperties": false, - "patternProperties": { - "^[a-z][a-z0-9]*(_[a-z0-9]+)*$": { - "$ref": "#/definitions/point_property_names" - } - } - } - }, - "required": [ - "timestamp", - "version", - "protocol", - "local_id", - "points" - ], - "definitions": { - "point_property_names": { - "propertyNames": { - "oneOf": [ - { - "enum": [ - "units", - "present_value" - ] - } - ] - } - } - } -} diff --git a/schemas/udmi/discover.tests/empty.json b/schemas/udmi/discover.tests/empty.json deleted file mode 100644 index 2c63c08510..0000000000 --- a/schemas/udmi/discover.tests/empty.json +++ /dev/null @@ -1,2 +0,0 @@ -{ -} diff --git a/schemas/udmi/discover.tests/empty.out b/schemas/udmi/discover.tests/empty.out deleted file mode 100644 index f9fdc0c692..0000000000 --- a/schemas/udmi/discover.tests/empty.out +++ /dev/null @@ -1,9 +0,0 @@ -Validating 1 schemas - Validating 1 files against discover.json - Against input discover.tests/empty.json - #: 5 schema violations found - #: required key [local_id] not found - #: required key [points] not found - #: required key [protocol] not found - #: required key [timestamp] not found - #: required key [version] not found diff --git a/schemas/udmi/discover.tests/errors.json b/schemas/udmi/discover.tests/errors.json deleted file mode 100644 index aa3540a596..0000000000 --- a/schemas/udmi/discover.tests/errors.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "version": 1, - "timestamp": "2018-08-26T21:39:29.364Z", - "id": "sneakyCASE", - "properties": { - "$comment": "Common error cases for target telemetry." - }, - "points": { - "bad_entity_name_": { - "present_value": 21.30108642578125 - }, - "yoyo_motion_sensor": { - "bad_property_name": true - }, - "bad___sensor": { - "present_value": 21.30108642578125 - }, - "missing_present_value": { - }, - "old_properties": { - "properties": { - "present_value": true - } - }, - "magic_voice_recognizer": { - "present_value": { - "present_value": true - } - } - } -} diff --git a/schemas/udmi/discover.tests/errors.out b/schemas/udmi/discover.tests/errors.out deleted file mode 100644 index 2a972276f9..0000000000 --- a/schemas/udmi/discover.tests/errors.out +++ /dev/null @@ -1,15 +0,0 @@ -Validating 1 schemas - Validating 1 files against discover.json - Against input discover.tests/errors.json - #: 8 schema violations found - #/points: 4 schema violations found - #/points/old_properties/properties: #: 0 subschemas matched instead of one - #/points/old_properties/properties: properties is not a valid enum value - #/points/yoyo_motion_sensor/bad_property_name: #: 0 subschemas matched instead of one - #/points/yoyo_motion_sensor/bad_property_name: bad_property_name is not a valid enum value - #/points: extraneous key [bad___sensor] is not permitted - #/points: extraneous key [bad_entity_name_] is not permitted - #: extraneous key [id] is not permitted - #: extraneous key [properties] is not permitted - #: required key [local_id] not found - #: required key [protocol] not found diff --git a/schemas/udmi/discover.tests/example.json b/schemas/udmi/discover.tests/example.json deleted file mode 100644 index 9852ad3818..0000000000 --- a/schemas/udmi/discover.tests/example.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "version": 1, - "timestamp": "2018-08-26T21:39:29.364Z", - "local_id": "92EA09", - "protocol": "bacnet", - "points": { - "reading_value": { - "units": "C", - "present_value": 21.30108642578125 - }, - "yoyo_motion_sensor": { - "present_value": true - }, - "enum_value": { - "present_value": "hello" - } - } -} diff --git a/schemas/udmi/discover.tests/example.out b/schemas/udmi/discover.tests/example.out deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/schemas/udmi/docs/gateway.md b/schemas/udmi/docs/gateway.md deleted file mode 100644 index 33f31a0152..0000000000 --- a/schemas/udmi/docs/gateway.md +++ /dev/null @@ -1,120 +0,0 @@ -# Device Gateway - -The _gateway_ functionality is used for systems that have legacy, heritage, -or traditional devices that do not communicate directly to the cloud using -the [UDMI specification](../README.md). For example, an older BacNET based -system could use a gateway to translate on-prem communications into UDMI. - -The -[Google Clout IoT Core Gateway Documentation](https://cloud.google.com/iot/docs/how-tos/gateways) -for an overview of the cloud-side implementation of a gateway. UDMI, then, -specifies an additional layer of specification around the associated -message formats. - -Conceptually, there are two types of -entities involved: the _gateway device_, and the _proxied device_. Both of -these are 'devices' in the sense that they have an entry in a cloud registry -and have device-level UDMI data, but they have fundamentally different roles. - -The process of _discovery_, which is where something discovers other devices -on the local network, is conceptually related but functionally distinct and -separate than a gateway. - -## Gateway Operation - -There are two modes for gateway operation: _static_ and _dynamic_. In the -_dynamic_ mode, the gateway functionality if configured dynamically through -gateway _config_ messages, which tell it the local devices it should proxy -for. In a _static_ gateway configuraiton, the gateway will be statically -configured to proxy a set of devices, essentally ignoring any information -in the associated _config_ block. - -The general sequence of events for gateway operation is: -1. Optional metadata specifies configuration paramaters that should be used -at install time to properly (manually) setup the device. -2. (_dynamic_ only) On startup, the gateway connects to the cloud and receives a configuration -block that details which _proxy devices_ the gateway should proxy for. -4. Gateway 'attaches' (Cloud IoT terminology) to the proxied devices, -receiving a configuration block for each proxied device. Any attch errors are -indicated in the gateway _status_ block and sent along as a _logentry_ event. -5. (_dynamic_ only) The proxied device's _config_ block specifies any local connection -parameters for the proxied device, e.g. the BacNET device id. -6. The gateway proxies communication to/from the device, translating between -native (e.g. BacNET) communications and UDMI-based messages. - -### config - -The [gateway config block](../config.tests/gateway.json) -simply specifies the list of target proxy devices. -On a config update, the gateway is responsible for handling any change in -this list (added or removed devices). The details of proxied devices are -kept to a minimum here (IDs only) to avoid overflowing the allowed block -size in cases where there are a large number of devices. - -### state - -Any attach errors, e.g. the gateway can not successfully attach to the target -device, should be reported in the [gateway state](../state.tests/gateway.json) -and a _logentry_ message used to detail the -nature of the problem. If the gateway can attach successfully, any other -errors, e.g. the inability to communicate with the device over the local -network, should be indicated as part of the proxy device status block. - -### telemetry - -Telemety from the gateway would primarily consist of standard -[_logentry_](../logentry.tests/logentry.json) messages, which -provide a running comentary about gateway operation. Specificaly, if there -is an error attaching, then there should be appropriate logging to help -diagnose the problem. - -### metadata - -The gateway [metadata block](../metadata.tests/gateway.json) specifies -any information necessary either for the -initial (manual) configuration of the device or ongoing validation of -operation. E.g., if a gateway device has a unique MAC address used for -local communications, it would be indicated here. - -## Proxy Device Operation - -Proxy devices are those that have a logical cloud device entry (in a registry), -and are associated (bound) to a particular gateway. On-prem, the device -itself talks a local protocol (e.g. BacNET), but does not have a direct -cloud connection. - -### config - -[Proxy device config blocks](../config.tests/proxy.json) contain a special -_localnet_ section that -specifies information required by the gateway to contact the local device. -E.g., the fact that a device is 'BacNET' and also the device's BacNET object -ID. Based on this, the gateway can communicate with the target device and proxy -all other messages. - -Additionally, the gateway is responsible for proxying all other supported -operations of the config bundle. E.g., if a _pointset_ 'force_value" parameter -is specified, the gateway would need to convert that into the local protocol -and trigger the required functionality. - -### state - -There is no gateway-specific _state_ information, but similarly to _config_ the -gateway is responsible for proxying all relevant state from the local device -into the proxied device's state block. E.g., if the device is in an alarm -state, then the gateway would have to transform that from the local format -into the appropriate UDMI message. - -### telemetry - -Telemetry is handled similarly, with the gateway responsible for proxying data -from local devices through to UDMI. In many cases, this would be translating -specific device points into a [_pointset_ message](../pointset.tests/example.json). - -### metadata - -A [proxy device metadata section](../metadata.tests/proxy.json) describes -_localnet_ with the presence of the -device on a local network. This can/should be used for initial programming -and configuration of the device, or to validate proper device configuration. -The gateway implementation itself would not directly deal with this block. diff --git a/schemas/udmi/envelope.json b/schemas/udmi/envelope.json deleted file mode 100644 index 9458e08ba5..0000000000 --- a/schemas/udmi/envelope.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "title": "Message envelope schema", - "additionalProperties": true, - "properties": { - "deviceId": { - "type": "string", - "pattern": "^[A-Z]{2,6}-[0-9]{1,6}$" - }, - "deviceNumId": { - "type": "string", - "pattern": "^[0-9]+$" - }, - "deviceRegistryId": { - "type": "string", - "pattern": "^[a-zA-Z][-a-zA-Z0-9._+~%]*[a-zA-Z0-9]$" - }, - "projectId": { - "type": "string", - "pattern": "^([.a-z]+:)?[a-z][-a-z0-9]*[a-z0-9]$" - }, - "subFolder": { - "enum": [ - "config", - "discover", - "system", - "metadata", - "pointset", - "state" - ] - } - }, - "required": [ - "projectId", - "deviceRegistryId", - "deviceNumId", - "deviceId", - "subFolder" - ] -} diff --git a/schemas/udmi/envelope.tests/empty.json b/schemas/udmi/envelope.tests/empty.json deleted file mode 100644 index 2c63c08510..0000000000 --- a/schemas/udmi/envelope.tests/empty.json +++ /dev/null @@ -1,2 +0,0 @@ -{ -} diff --git a/schemas/udmi/envelope.tests/empty.out b/schemas/udmi/envelope.tests/empty.out deleted file mode 100644 index d4d84fce5c..0000000000 --- a/schemas/udmi/envelope.tests/empty.out +++ /dev/null @@ -1,9 +0,0 @@ -Validating 1 schemas - Validating 1 files against envelope.json - Against input envelope.tests/empty.json - #: 5 schema violations found - #: required key [deviceId] not found - #: required key [deviceNumId] not found - #: required key [deviceRegistryId] not found - #: required key [projectId] not found - #: required key [subFolder] not found diff --git a/schemas/udmi/envelope.tests/errors1.json b/schemas/udmi/envelope.tests/errors1.json deleted file mode 100644 index ff059c78e0..0000000000 --- a/schemas/udmi/envelope.tests/errors1.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "deviceRegistryId": "test/registry", - "deviceNumId": "921302198324X", - "deviceId": "fcu-1" -} diff --git a/schemas/udmi/envelope.tests/errors1.out b/schemas/udmi/envelope.tests/errors1.out deleted file mode 100644 index 601887a26a..0000000000 --- a/schemas/udmi/envelope.tests/errors1.out +++ /dev/null @@ -1,9 +0,0 @@ -Validating 1 schemas - Validating 1 files against envelope.json - Against input envelope.tests/errors1.json - #: 5 schema violations found - #/deviceId: string [fcu-1] does not match pattern ^[A-Z]{2,6}-[0-9]{1,6}$ - #/deviceNumId: string [921302198324X] does not match pattern ^[0-9]+$ - #/deviceRegistryId: string [test/registry] does not match pattern ^[a-zA-Z][-a-zA-Z0-9._+~%]*[a-zA-Z0-9]$ - #: required key [projectId] not found - #: required key [subFolder] not found diff --git a/schemas/udmi/envelope.tests/errors2.json b/schemas/udmi/envelope.tests/errors2.json deleted file mode 100644 index 9cbb163ade..0000000000 --- a/schemas/udmi/envelope.tests/errors2.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "deviceRegistryId": "test-registry", - "deviceNumId": "-9213923812", - "deviceId": "FCUs_02_NW_12" -} diff --git a/schemas/udmi/envelope.tests/errors2.out b/schemas/udmi/envelope.tests/errors2.out deleted file mode 100644 index 0c02908e03..0000000000 --- a/schemas/udmi/envelope.tests/errors2.out +++ /dev/null @@ -1,8 +0,0 @@ -Validating 1 schemas - Validating 1 files against envelope.json - Against input envelope.tests/errors2.json - #: 4 schema violations found - #/deviceId: string [FCUs_02_NW_12] does not match pattern ^[A-Z]{2,6}-[0-9]{1,6}$ - #/deviceNumId: string [-9213923812] does not match pattern ^[0-9]+$ - #: required key [projectId] not found - #: required key [subFolder] not found diff --git a/schemas/udmi/envelope.tests/example.json b/schemas/udmi/envelope.tests/example.json deleted file mode 100644 index b48f45a49a..0000000000 --- a/schemas/udmi/envelope.tests/example.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "projectId": "daq-test-suite", - "deviceRegistryId": "test_registry", - "deviceNumId": "921302198324", - "deviceId": "FCU-2", - "subFolder": "pointset" -} diff --git a/schemas/udmi/envelope.tests/example.out b/schemas/udmi/envelope.tests/example.out deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/schemas/udmi/envelope.tests/example2.json b/schemas/udmi/envelope.tests/example2.json deleted file mode 100644 index 572406ce32..0000000000 --- a/schemas/udmi/envelope.tests/example2.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "projectId": "daq-test-suite", - "deviceRegistryId": "test-registry", - "deviceNumId": "23812", - "deviceId": "FCU-002", - "subFolder": "system", -} diff --git a/schemas/udmi/envelope.tests/example2.out b/schemas/udmi/envelope.tests/example2.out deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/schemas/udmi/envelope.tests/lgtw.json b/schemas/udmi/envelope.tests/lgtw.json deleted file mode 100644 index 8e7b88cbd9..0000000000 --- a/schemas/udmi/envelope.tests/lgtw.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "projectId": "daq-test-suite", - "deviceRegistryId": "test_registry", - "deviceNumId": "921302198324", - "deviceId": "LGTW-2", - "subFolder": "discover" -} diff --git a/schemas/udmi/envelope.tests/lgtw.out b/schemas/udmi/envelope.tests/lgtw.out deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/schemas/udmi/metadata.json b/schemas/udmi/metadata.json deleted file mode 100644 index e01dbe16cc..0000000000 --- a/schemas/udmi/metadata.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "title": "Device metadata schema", - "type": "object", - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false, - "required": [ - "timestamp", - "version", - "system" - ], - "properties": { - "timestamp": { - "type": "string", - "format": "date-time" - }, - "version": { - "enum": [ - 1 - ] - }, - "hash": { - "type": "string", - "pattern": "^[0-9a-z]{8}$" - }, - "cloud": { - "$ref": "file:metadata_cloud.json#" - }, - "system": { - "$ref": "file:metadata_system.json#" - }, - "gateway": { - "$ref": "file:metadata_gateway.json#" - }, - "localnet": { - "$ref": "file:metadata_localnet.json#" - }, - "pointset": { - "$ref": "file:metadata_pointset.json#" - } - } -} diff --git a/schemas/udmi/metadata.tests/empty.json b/schemas/udmi/metadata.tests/empty.json deleted file mode 100644 index 0967ef424b..0000000000 --- a/schemas/udmi/metadata.tests/empty.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/schemas/udmi/metadata.tests/empty.out b/schemas/udmi/metadata.tests/empty.out deleted file mode 100644 index 159f05c268..0000000000 --- a/schemas/udmi/metadata.tests/empty.out +++ /dev/null @@ -1,7 +0,0 @@ -Validating 1 schemas - Validating 1 files against metadata.json - Against input metadata.tests/empty.json - #: 3 schema violations found - #: required key [system] not found - #: required key [timestamp] not found - #: required key [version] not found diff --git a/schemas/udmi/metadata.tests/errors.json b/schemas/udmi/metadata.tests/errors.json deleted file mode 100644 index 395b19e45f..0000000000 --- a/schemas/udmi/metadata.tests/errors.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "version": 1, - "timestamp": "2018-08-26T21:39:29.364Z", - "system": { - "guid": "bim://04aEp5ymD_$u5IxhJN2aGi", - "location": { - "site": "New Zealand" - }, - "physical_tag": { - "asset": { - "site": "US-SFO-XYY_Noope!", - "name": "AHU-A01_extension11-option" - } - } - }, - "pointset": { - "rabbits": true, - "points": { - "return_air_temperature_sensor": { - "units": "Celsius", - "monkeys": "elephants" - } - } - } -} diff --git a/schemas/udmi/metadata.tests/errors.out b/schemas/udmi/metadata.tests/errors.out deleted file mode 100644 index c315c2fd40..0000000000 --- a/schemas/udmi/metadata.tests/errors.out +++ /dev/null @@ -1,16 +0,0 @@ -Validating 1 schemas - Validating 1 files against metadata.json - Against input metadata.tests/errors.json - #: 8 schema violations found - #/pointset: 3 schema violations found - #/pointset/points/return_air_temperature_sensor: 2 schema violations found - #/pointset/points/return_air_temperature_sensor/units: Celsius is not a valid enum value - #/pointset/points/return_air_temperature_sensor: extraneous key [monkeys] is not permitted - #/pointset: extraneous key [rabbits] is not permitted - #/system: 5 schema violations found - #/system/location/site: string [New Zealand] does not match pattern ^[A-Z]{2}-[A-Z]{3}-[A-Z0-9]{2,9}$ - #/system/physical_tag/asset: 3 schema violations found - #/system/physical_tag/asset/name: string [AHU-A01_extension11-option] does not match pattern ^[A-Z]{2,6}-[0-9]{1,6}$ - #/system/physical_tag/asset/site: string [US-SFO-XYY_Noope!] does not match pattern ^[A-Z]{2}-[A-Z]{3}-[A-Z0-9]{2,9}$ - #/system/physical_tag/asset: required key [guid] not found - #/system: extraneous key [guid] is not permitted diff --git a/schemas/udmi/metadata.tests/example.json b/schemas/udmi/metadata.tests/example.json deleted file mode 100644 index 4f1df64175..0000000000 --- a/schemas/udmi/metadata.tests/example.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "version": 1, - "timestamp": "2018-08-26T21:39:29.364Z", - "system": { - "location": { - "site": "US-SFO-XYY", - "section": "NW-2F", - "position": { - "x": 10, - "y": 20 - } - }, - "physical_tag": { - "asset": { - "guid": "bim://04aEp5ymD_$u5IxhJN2aGi", - "site": "US-SFO-XYY", - "name": "AHU-1" - } - }, - "aux": { - "suffix": "extention11-optional", - } - }, - "pointset": { - "points": { - "return_air_temperature_sensor": { - "units": "Degrees-Celsius" - } - } - } -} diff --git a/schemas/udmi/metadata.tests/example.out b/schemas/udmi/metadata.tests/example.out deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/schemas/udmi/metadata.tests/example2.out b/schemas/udmi/metadata.tests/example2.out deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/schemas/udmi/metadata.tests/gateway.json b/schemas/udmi/metadata.tests/gateway.json deleted file mode 100644 index 2da945023e..0000000000 --- a/schemas/udmi/metadata.tests/gateway.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "version": 1, - "timestamp": "2018-08-26T21:39:29.364Z", - "system": { - "location": { - "site": "US-SFO-XYY", - "section": "NW-2F", - "position": { - "x": 10, - "y": 20 - } - }, - "physical_tag": { - "asset": { - "guid": "bim://04aEp5ymD_$u5IxhJN2aGi", - "site": "US-SFO-XYY", - "name": "AHU-01" - } - } - }, - "cloud": { - "auth_type": "RS256", - }, - "gateway": { - "proxy_ids": ["AHU-22"] - }, - "pointset": { - "points": { - "return_air_temperature_sensor": { - "units": "Degrees-Celsius" - } - } - }, - "localnet": { - "subsystem": { - "bacnet": { - "local_id": "0x991132ec" - } - } - } -} diff --git a/schemas/udmi/metadata.tests/gateway.out b/schemas/udmi/metadata.tests/gateway.out deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/schemas/udmi/metadata.tests/proxy.json b/schemas/udmi/metadata.tests/proxy.json deleted file mode 100644 index bbc522af3c..0000000000 --- a/schemas/udmi/metadata.tests/proxy.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "version": 1, - "timestamp": "2018-08-26T21:39:29.364Z", - "system": { - "location": { - "site": "US-SFO-XYY", - "section": "NW-2F", - "position": { - "x": 10, - "y": 20 - } - }, - "physical_tag": { - "asset": { - "guid": "bim://04aEp5ymD_$u5IxhJN2aGi", - "site": "US-SFO-XYY", - "name": "AHU-1", - } - }, - "aux": { - "suffix": "extention11-optional" - } - }, - "localnet": { - "subsystem": { - "bacnet": { - "local_id": "0x82eecd" - } - } - }, - "pointset": { - "points": { - "return_air_temperature_sensor": { - "units": "Degrees-Celsius", - "ref": "BV23.present_value" - } - } - }, - "gateway": { - "subsystem": "bacnet", - "gateway_id": "GAT-123" - } -} diff --git a/schemas/udmi/metadata.tests/proxy.out b/schemas/udmi/metadata.tests/proxy.out deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/schemas/udmi/metadata.tests/toomany.json b/schemas/udmi/metadata.tests/toomany.json deleted file mode 100644 index 6c5b9671e0..0000000000 --- a/schemas/udmi/metadata.tests/toomany.json +++ /dev/null @@ -1,2035 +0,0 @@ -{ - "system": { - "location": { - "site": "UK-LON-S2" - }, - "physical_tag": { - "asset": { - "name": "UK-LON-S2_LTGW-3", - "guid": "ifc://27UivR75r3481CVsBDvlfl" - } - } - }, - "pointset": { - "points": { - "bw4_group_brightness12": { - "units": "Percent" - }, - "bw4_group_brightness13": { - "units": "Percent" - }, - "bw4_group_brightness10": { - "units": "Percent" - }, - "bw4_group_brightness11": { - "units": "Percent" - }, - "bw4_group_brightness16": { - "units": "Percent" - }, - "bw4_group_brightness14": { - "units": "Percent" - }, - "bw4_group_brightness15": { - "units": "Percent" - }, - "bw4_light_level1": { - "units": "Luxes" - }, - "bw4_light_level2": { - "units": "Luxes" - }, - "bw4_light_level7": { - "units": "Luxes" - }, - "bw4_light_level8": { - "units": "Luxes" - }, - "bw4_light_level9": { - "units": "Luxes" - }, - "bw4_light_level3": { - "units": "Luxes" - }, - "bw4_light_level4": { - "units": "Luxes" - }, - "bw4_light_level5": { - "units": "Luxes" - }, - "bw4_light_level6": { - "units": "Luxes" - }, - "bw5_lamp_brightness61": { - "units": "Percent" - }, - "bw5_lamp_brightness62": { - "units": "Percent" - }, - "bw5_lamp_brightness63": { - "units": "Percent" - }, - "bw5_lamp_brightness64": { - "units": "Percent" - }, - "bw5_lamp_brightness60": { - "units": "Percent" - }, - "bw6_lamp_brightness63": { - "units": "Percent" - }, - "bw6_lamp_brightness62": { - "units": "Percent" - }, - "bw6_lamp_brightness61": { - "units": "Percent" - }, - "bw6_lamp_brightness60": { - "units": "Percent" - }, - "bw6_lamp_brightness64": { - "units": "Percent" - }, - "bw4_lamp_brightness60": { - "units": "Percent" - }, - "bw4_occupancy5": { - "units": "No-units" - }, - "bw5_lamp_brightness58": { - "units": "Percent" - }, - "bw4_lamp_brightness61": { - "units": "Percent" - }, - "bw4_occupancy6": { - "units": "No-units" - }, - "bw5_lamp_brightness59": { - "units": "Percent" - }, - "bw4_occupancy7": { - "units": "No-units" - }, - "bw4_occupancy8": { - "units": "No-units" - }, - "bw4_lamp_brightness64": { - "units": "Percent" - }, - "bw4_occupancy9": { - "units": "No-units" - }, - "bw5_lamp_brightness54": { - "units": "Percent" - }, - "bw5_lamp_brightness55": { - "units": "Percent" - }, - "bw4_lamp_brightness62": { - "units": "Percent" - }, - "bw5_lamp_brightness56": { - "units": "Percent" - }, - "bw4_lamp_brightness63": { - "units": "Percent" - }, - "bw5_lamp_brightness57": { - "units": "Percent" - }, - "bw5_lamp_brightness50": { - "units": "Percent" - }, - "bw5_lamp_brightness51": { - "units": "Percent" - }, - "bw5_lamp_brightness52": { - "units": "Percent" - }, - "bw5_lamp_brightness53": { - "units": "Percent" - }, - "bw4_occupancy1": { - "units": "No-units" - }, - "bw4_occupancy2": { - "units": "No-units" - }, - "bw4_occupancy3": { - "units": "No-units" - }, - "bw4_occupancy4": { - "units": "No-units" - }, - "bw1_group_brightness16": { - "units": "Percent" - }, - "bw1_group_brightness15": { - "units": "Percent" - }, - "bw1_group_brightness12": { - "units": "Percent" - }, - "bw1_group_brightness11": { - "units": "Percent" - }, - "bw1_group_brightness14": { - "units": "Percent" - }, - "bw1_group_brightness13": { - "units": "Percent" - }, - "bw1_group_brightness10": { - "units": "Percent" - }, - "bw5_lamp_brightness47": { - "units": "Percent" - }, - "bw5_lamp_brightness48": { - "units": "Percent" - }, - "bw5_lamp_brightness9": { - "units": "Percent" - }, - "bw5_lamp_brightness49": { - "units": "Percent" - }, - "bw5_lamp_brightness43": { - "units": "Percent" - }, - "bw6_occupancy7": { - "units": "No-units" - }, - "bw5_lamp_brightness44": { - "units": "Percent" - }, - "bw6_occupancy8": { - "units": "No-units" - }, - "bw5_lamp_brightness45": { - "units": "Percent" - }, - "bw6_occupancy9": { - "units": "No-units" - }, - "bw5_lamp_brightness46": { - "units": "Percent" - }, - "bw6_occupancy3": { - "units": "No-units" - }, - "bw2_lamp_brightness64": { - "units": "Percent" - }, - "bw5_lamp_brightness40": { - "units": "Percent" - }, - "bw6_occupancy4": { - "units": "No-units" - }, - "bw5_lamp_brightness41": { - "units": "Percent" - }, - "bw6_occupancy5": { - "units": "No-units" - }, - "bw5_lamp_brightness42": { - "units": "Percent" - }, - "bw6_occupancy6": { - "units": "No-units" - }, - "bw2_lamp_brightness61": { - "units": "Percent" - }, - "bw2_lamp_brightness60": { - "units": "Percent" - }, - "bw2_lamp_brightness63": { - "units": "Percent" - }, - "bw6_occupancy1": { - "units": "No-units" - }, - "bw2_lamp_brightness62": { - "units": "Percent" - }, - "bw6_occupancy2": { - "units": "No-units" - }, - "bw3_lamp_brightness6": { - "units": "Percent" - }, - "bw5_lamp_brightness36": { - "units": "Percent" - }, - "bw3_lamp_brightness5": { - "units": "Percent" - }, - "bw5_lamp_brightness37": { - "units": "Percent" - }, - "bw3_lamp_brightness4": { - "units": "Percent" - }, - "bw5_lamp_brightness38": { - "units": "Percent" - }, - "bw3_lamp_brightness3": { - "units": "Percent" - }, - "bw5_lamp_brightness39": { - "units": "Percent" - }, - "bw2_lamp_brightness58": { - "units": "Percent" - }, - "bw3_lamp_brightness2": { - "units": "Percent" - }, - "bw5_lamp_brightness32": { - "units": "Percent" - }, - "bw2_lamp_brightness57": { - "units": "Percent" - }, - "bw3_lamp_brightness1": { - "units": "Percent" - }, - "bw5_lamp_brightness33": { - "units": "Percent" - }, - "bw5_lamp_brightness34": { - "units": "Percent" - }, - "bw6_lamp_brightness29": { - "units": "Percent" - }, - "bw2_lamp_brightness59": { - "units": "Percent" - }, - "bw5_lamp_brightness35": { - "units": "Percent" - }, - "bw6_lamp_brightness28": { - "units": "Percent" - }, - "bw2_lamp_brightness54": { - "units": "Percent" - }, - "bw2_lamp_brightness53": { - "units": "Percent" - }, - "bw2_lamp_brightness56": { - "units": "Percent" - }, - "bw5_lamp_brightness30": { - "units": "Percent" - }, - "bw2_lamp_brightness55": { - "units": "Percent" - }, - "bw5_lamp_brightness31": { - "units": "Percent" - }, - "bw2_lamp_brightness50": { - "units": "Percent" - }, - "bw2_lamp_brightness52": { - "units": "Percent" - }, - "bw2_lamp_brightness51": { - "units": "Percent" - }, - "bw2_light_level1": { - "units": "Luxes" - }, - "bw3_lamp_brightness55": { - "units": "Percent" - }, - "bw6_lamp_brightness30": { - "units": "Percent" - }, - "bw2_light_level2": { - "units": "Luxes" - }, - "bw3_lamp_brightness54": { - "units": "Percent" - }, - "bw2_light_level3": { - "units": "Luxes" - }, - "bw3_lamp_brightness53": { - "units": "Percent" - }, - "bw2_light_level4": { - "units": "Luxes" - }, - "bw3_lamp_brightness52": { - "units": "Percent" - }, - "bw2_light_level5": { - "units": "Luxes" - }, - "bw3_lamp_brightness51": { - "units": "Percent" - }, - "bw6_light_level1": { - "units": "Luxes" - }, - "bw2_light_level6": { - "units": "Luxes" - }, - "bw3_lamp_brightness50": { - "units": "Percent" - }, - "bw6_light_level2": { - "units": "Luxes" - }, - "bw2_light_level7": { - "units": "Luxes" - }, - "bw6_light_level3": { - "units": "Luxes" - }, - "bw2_light_level8": { - "units": "Luxes" - }, - "bw6_light_level4": { - "units": "Luxes" - }, - "bw6_lamp_brightness38": { - "units": "Percent" - }, - "bw6_light_level5": { - "units": "Luxes" - }, - "bw6_lamp_brightness37": { - "units": "Percent" - }, - "bw6_light_level6": { - "units": "Luxes" - }, - "bw6_lamp_brightness36": { - "units": "Percent" - }, - "bw6_light_level7": { - "units": "Luxes" - }, - "bw6_lamp_brightness35": { - "units": "Percent" - }, - "bw6_light_level8": { - "units": "Luxes" - }, - "bw3_lamp_brightness59": { - "units": "Percent" - }, - "bw5_lamp_brightness29": { - "units": "Percent" - }, - "bw6_lamp_brightness34": { - "units": "Percent" - }, - "bw6_light_level9": { - "units": "Luxes" - }, - "bw3_lamp_brightness58": { - "units": "Percent" - }, - "bw6_lamp_brightness33": { - "units": "Percent" - }, - "bw3_lamp_brightness57": { - "units": "Percent" - }, - "bw6_lamp_brightness32": { - "units": "Percent" - }, - "bw3_lamp_brightness56": { - "units": "Percent" - }, - "bw6_lamp_brightness31": { - "units": "Percent" - }, - "bw5_lamp_brightness25": { - "units": "Percent" - }, - "bw5_lamp_brightness26": { - "units": "Percent" - }, - "bw5_lamp_brightness27": { - "units": "Percent" - }, - "bw5_lamp_brightness28": { - "units": "Percent" - }, - "bw2_lamp_brightness47": { - "units": "Percent" - }, - "bw5_lamp_brightness21": { - "units": "Percent" - }, - "bw2_lamp_brightness46": { - "units": "Percent" - }, - "bw5_lamp_brightness22": { - "units": "Percent" - }, - "bw6_lamp_brightness19": { - "units": "Percent" - }, - "bw2_lamp_brightness49": { - "units": "Percent" - }, - "bw5_lamp_brightness23": { - "units": "Percent" - }, - "bw6_lamp_brightness18": { - "units": "Percent" - }, - "bw2_lamp_brightness48": { - "units": "Percent" - }, - "bw5_lamp_brightness24": { - "units": "Percent" - }, - "bw6_lamp_brightness17": { - "units": "Percent" - }, - "bw2_lamp_brightness43": { - "units": "Percent" - }, - "bw2_lamp_brightness42": { - "units": "Percent" - }, - "bw2_lamp_brightness45": { - "units": "Percent" - }, - "bw2_lamp_brightness44": { - "units": "Percent" - }, - "bw5_lamp_brightness20": { - "units": "Percent" - }, - "bw2_lamp_brightness41": { - "units": "Percent" - }, - "bw2_lamp_brightness40": { - "units": "Percent" - }, - "bw3_lamp_brightness44": { - "units": "Percent" - }, - "bw3_lamp_brightness43": { - "units": "Percent" - }, - "bw3_lamp_brightness42": { - "units": "Percent" - }, - "bw3_lamp_brightness41": { - "units": "Percent" - }, - "bw3_lamp_brightness40": { - "units": "Percent" - }, - "bw6_lamp_brightness27": { - "units": "Percent" - }, - "bw6_lamp_brightness26": { - "units": "Percent" - }, - "bw6_lamp_brightness25": { - "units": "Percent" - }, - "bw3_lamp_brightness49": { - "units": "Percent" - }, - "bw6_lamp_brightness24": { - "units": "Percent" - }, - "bw3_lamp_brightness48": { - "units": "Percent" - }, - "bw5_lamp_brightness18": { - "units": "Percent" - }, - "bw6_lamp_brightness23": { - "units": "Percent" - }, - "bw3_lamp_brightness47": { - "units": "Percent" - }, - "bw5_lamp_brightness19": { - "units": "Percent" - }, - "bw6_lamp_brightness22": { - "units": "Percent" - }, - "bw3_lamp_brightness46": { - "units": "Percent" - }, - "bw6_lamp_brightness21": { - "units": "Percent" - }, - "bw3_lamp_brightness45": { - "units": "Percent" - }, - "bw6_lamp_brightness20": { - "units": "Percent" - }, - "bw5_lamp_brightness14": { - "units": "Percent" - }, - "bw2_lamp_brightness39": { - "units": "Percent" - }, - "bw5_lamp_brightness15": { - "units": "Percent" - }, - "bw5_lamp_brightness16": { - "units": "Percent" - }, - "bw5_lamp_brightness17": { - "units": "Percent" - }, - "bw2_lamp_brightness36": { - "units": "Percent" - }, - "bw5_lamp_brightness10": { - "units": "Percent" - }, - "bw2_lamp_brightness35": { - "units": "Percent" - }, - "bw5_lamp_brightness11": { - "units": "Percent" - }, - "bw2_lamp_brightness38": { - "units": "Percent" - }, - "bw5_lamp_brightness12": { - "units": "Percent" - }, - "bw2_lamp_brightness37": { - "units": "Percent" - }, - "bw5_lamp_brightness13": { - "units": "Percent" - }, - "bw2_lamp_brightness32": { - "units": "Percent" - }, - "bw2_lamp_brightness31": { - "units": "Percent" - }, - "bw2_lamp_brightness34": { - "units": "Percent" - }, - "bw2_lamp_brightness33": { - "units": "Percent" - }, - "bw2_lamp_brightness30": { - "units": "Percent" - }, - "bw6_lamp_brightness52": { - "units": "Percent" - }, - "bw3_light_level1": { - "units": "Luxes" - }, - "bw6_lamp_brightness51": { - "units": "Percent" - }, - "bw6_lamp_brightness50": { - "units": "Percent" - }, - "bw1_occupancy1": { - "units": "No-units" - }, - "bw1_occupancy5": { - "units": "No-units" - }, - "bw3_light_level8": { - "units": "Luxes" - }, - "bw1_occupancy4": { - "units": "No-units" - }, - "bw3_light_level9": { - "units": "Luxes" - }, - "bw6_lamp_brightness59": { - "units": "Percent" - }, - "bw1_occupancy3": { - "units": "No-units" - }, - "bw3_light_level6": { - "units": "Luxes" - }, - "bw6_lamp_brightness58": { - "units": "Percent" - }, - "bw1_occupancy2": { - "units": "No-units" - }, - "bw3_light_level7": { - "units": "Luxes" - }, - "bw6_lamp_brightness57": { - "units": "Percent" - }, - "bw1_occupancy9": { - "units": "No-units" - }, - "bw3_light_level4": { - "units": "Luxes" - }, - "bw6_lamp_brightness56": { - "units": "Percent" - }, - "bw1_occupancy8": { - "units": "No-units" - }, - "bw3_light_level5": { - "units": "Luxes" - }, - "bw6_lamp_brightness55": { - "units": "Percent" - }, - "bw1_occupancy7": { - "units": "No-units" - }, - "bw3_light_level2": { - "units": "Luxes" - }, - "bw6_lamp_brightness54": { - "units": "Percent" - }, - "bw1_occupancy6": { - "units": "No-units" - }, - "bw3_light_level3": { - "units": "Luxes" - }, - "bw6_lamp_brightness53": { - "units": "Percent" - }, - "bw2_lamp_brightness29": { - "units": "Percent" - }, - "bw2_lamp_brightness28": { - "units": "Percent" - }, - "bw2_lamp_brightness25": { - "units": "Percent" - }, - "bw2_lamp_brightness24": { - "units": "Percent" - }, - "bw2_lamp_brightness27": { - "units": "Percent" - }, - "bw2_lamp_brightness26": { - "units": "Percent" - }, - "bw6_lamp_brightness39": { - "units": "Percent" - }, - "bw2_lamp_brightness21": { - "units": "Percent" - }, - "bw2_lamp_brightness20": { - "units": "Percent" - }, - "bw2_lamp_brightness23": { - "units": "Percent" - }, - "bw2_lamp_brightness22": { - "units": "Percent" - }, - "bw6_lamp_brightness41": { - "units": "Percent" - }, - "bw6_lamp_brightness40": { - "units": "Percent" - }, - "bw3_lamp_brightness64": { - "units": "Percent" - }, - "bw3_lamp_brightness63": { - "units": "Percent" - }, - "bw3_lamp_brightness62": { - "units": "Percent" - }, - "bw3_lamp_brightness61": { - "units": "Percent" - }, - "bw3_lamp_brightness60": { - "units": "Percent" - }, - "bw6_lamp_brightness49": { - "units": "Percent" - }, - "bw6_lamp_brightness48": { - "units": "Percent" - }, - "bw6_lamp_brightness47": { - "units": "Percent" - }, - "bw6_lamp_brightness46": { - "units": "Percent" - }, - "bw6_lamp_brightness45": { - "units": "Percent" - }, - "bw3_lamp_brightness9": { - "units": "Percent" - }, - "bw6_lamp_brightness44": { - "units": "Percent" - }, - "bw3_lamp_brightness8": { - "units": "Percent" - }, - "bw6_lamp_brightness43": { - "units": "Percent" - }, - "bw3_lamp_brightness7": { - "units": "Percent" - }, - "bw6_lamp_brightness42": { - "units": "Percent" - }, - "bw1_lamp_brightness20": { - "units": "Percent" - }, - "bw1_lamp_brightness24": { - "units": "Percent" - }, - "bw1_group_brightness1": { - "units": "Percent" - }, - "bw1_lamp_brightness23": { - "units": "Percent" - }, - "bw1_group_brightness2": { - "units": "Percent" - }, - "bw1_lamp_brightness22": { - "units": "Percent" - }, - "bw1_group_brightness3": { - "units": "Percent" - }, - "bw1_lamp_brightness21": { - "units": "Percent" - }, - "bw1_lamp_brightness28": { - "units": "Percent" - }, - "bw1_lamp_brightness27": { - "units": "Percent" - }, - "bw1_lamp_brightness26": { - "units": "Percent" - }, - "bw1_lamp_brightness25": { - "units": "Percent" - }, - "bw1_lamp_brightness29": { - "units": "Percent" - }, - "bw1_lamp_brightness31": { - "units": "Percent" - }, - "bw1_light_level13": { - "units": "Luxes" - }, - "bw1_lamp_brightness30": { - "units": "Percent" - }, - "bw1_light_level14": { - "units": "Luxes" - }, - "bw1_light_level11": { - "units": "Luxes" - }, - "bw1_light_level12": { - "units": "Luxes" - }, - "bw1_lamp_brightness35": { - "units": "Percent" - }, - "bw1_lamp_brightness34": { - "units": "Percent" - }, - "bw1_lamp_brightness33": { - "units": "Percent" - }, - "bw1_light_level15": { - "units": "Luxes" - }, - "bw1_lamp_brightness32": { - "units": "Percent" - }, - "bw1_light_level16": { - "units": "Luxes" - }, - "bw1_lamp_brightness39": { - "units": "Percent" - }, - "bw1_lamp_brightness38": { - "units": "Percent" - }, - "bw1_lamp_brightness37": { - "units": "Percent" - }, - "bw1_lamp_brightness36": { - "units": "Percent" - }, - "bw1_light_level10": { - "units": "Luxes" - }, - "bw3_group_brightness10": { - "units": "Percent" - }, - "bw5_group_brightness15": { - "units": "Percent" - }, - "bw5_group_brightness16": { - "units": "Percent" - }, - "bw3_group_brightness12": { - "units": "Percent" - }, - "bw3_group_brightness11": { - "units": "Percent" - }, - "bw3_group_brightness14": { - "units": "Percent" - }, - "bw5_group_brightness11": { - "units": "Percent" - }, - "bw3_group_brightness13": { - "units": "Percent" - }, - "bw5_group_brightness12": { - "units": "Percent" - }, - "bw3_group_brightness16": { - "units": "Percent" - }, - "bw5_group_brightness13": { - "units": "Percent" - }, - "bw3_group_brightness15": { - "units": "Percent" - }, - "bw5_group_brightness14": { - "units": "Percent" - }, - "bw6_lamp_brightness16": { - "units": "Percent" - }, - "bw6_lamp_brightness15": { - "units": "Percent" - }, - "bw6_lamp_brightness14": { - "units": "Percent" - }, - "bw5_group_brightness10": { - "units": "Percent" - }, - "bw6_lamp_brightness13": { - "units": "Percent" - }, - "bw6_lamp_brightness12": { - "units": "Percent" - }, - "bw6_lamp_brightness11": { - "units": "Percent" - }, - "bw6_lamp_brightness10": { - "units": "Percent" - }, - "bw3_occupancy10": { - "units": "No-units" - }, - "bw6_occupancy16": { - "units": "No-units" - }, - "bw2_occupancy10": { - "units": "No-units" - }, - "bw2_occupancy11": { - "units": "No-units" - }, - "bw1_lamp_brightness4": { - "units": "Percent" - }, - "bw1_lamp_brightness13": { - "units": "Percent" - }, - "bw2_occupancy12": { - "units": "No-units" - }, - "bw3_occupancy14": { - "units": "No-units" - }, - "bw6_occupancy12": { - "units": "No-units" - }, - "bw1_lamp_brightness3": { - "units": "Percent" - }, - "bw1_lamp_brightness12": { - "units": "Percent" - }, - "bw2_occupancy13": { - "units": "No-units" - }, - "bw3_occupancy13": { - "units": "No-units" - }, - "bw6_occupancy13": { - "units": "No-units" - }, - "bw1_lamp_brightness2": { - "units": "Percent" - }, - "bw1_lamp_brightness11": { - "units": "Percent" - }, - "bw2_occupancy14": { - "units": "No-units" - }, - "bw3_occupancy12": { - "units": "No-units" - }, - "bw6_occupancy14": { - "units": "No-units" - }, - "bw1_lamp_brightness1": { - "units": "Percent" - }, - "bw1_lamp_brightness10": { - "units": "Percent" - }, - "bw2_occupancy15": { - "units": "No-units" - }, - "bw3_occupancy11": { - "units": "No-units" - }, - "bw6_occupancy15": { - "units": "No-units" - }, - "bw1_lamp_brightness17": { - "units": "Percent" - }, - "bw2_light_level9": { - "units": "Luxes" - }, - "bw1_lamp_brightness16": { - "units": "Percent" - }, - "bw1_lamp_brightness15": { - "units": "Percent" - }, - "bw1_lamp_brightness14": { - "units": "Percent" - }, - "bw1_lamp_brightness19": { - "units": "Percent" - }, - "bw1_lamp_brightness18": { - "units": "Percent" - }, - "bw1_group_brightness4": { - "units": "Percent" - }, - "bw2_occupancy16": { - "units": "No-units" - }, - "bw1_group_brightness5": { - "units": "Percent" - }, - "bw1_group_brightness6": { - "units": "Percent" - }, - "bw3_occupancy16": { - "units": "No-units" - }, - "bw6_occupancy10": { - "units": "No-units" - }, - "bw1_group_brightness7": { - "units": "Percent" - }, - "bw3_occupancy15": { - "units": "No-units" - }, - "bw6_occupancy11": { - "units": "No-units" - }, - "bw1_group_brightness8": { - "units": "Percent" - }, - "bw1_group_brightness9": { - "units": "Percent" - }, - "bw1_lamp_brightness64": { - "units": "Percent" - }, - "bw1_lamp_brightness63": { - "units": "Percent" - }, - "bw1_lamp_brightness62": { - "units": "Percent" - }, - "bw1_lamp_brightness61": { - "units": "Percent" - }, - "bw1_lamp_brightness8": { - "units": "Percent" - }, - "bw1_lamp_brightness7": { - "units": "Percent" - }, - "bw1_lamp_brightness6": { - "units": "Percent" - }, - "bw1_lamp_brightness5": { - "units": "Percent" - }, - "bw1_lamp_brightness60": { - "units": "Percent" - }, - "bw1_lamp_brightness9": { - "units": "Percent" - }, - "bw1_lamp_brightness42": { - "units": "Percent" - }, - "bw1_lamp_brightness41": { - "units": "Percent" - }, - "bw1_lamp_brightness40": { - "units": "Percent" - }, - "bw1_lamp_brightness46": { - "units": "Percent" - }, - "bw1_lamp_brightness45": { - "units": "Percent" - }, - "bw1_lamp_brightness44": { - "units": "Percent" - }, - "bw1_lamp_brightness43": { - "units": "Percent" - }, - "bw1_lamp_brightness49": { - "units": "Percent" - }, - "bw1_lamp_brightness48": { - "units": "Percent" - }, - "bw1_lamp_brightness47": { - "units": "Percent" - }, - "bw1_light_level3": { - "units": "Luxes" - }, - "bw1_light_level2": { - "units": "Luxes" - }, - "bw1_light_level1": { - "units": "Luxes" - }, - "bw1_light_level7": { - "units": "Luxes" - }, - "bw1_light_level6": { - "units": "Luxes" - }, - "bw1_light_level5": { - "units": "Luxes" - }, - "bw1_light_level4": { - "units": "Luxes" - }, - "bw1_lamp_brightness53": { - "units": "Percent" - }, - "bw1_lamp_brightness52": { - "units": "Percent" - }, - "bw1_lamp_brightness51": { - "units": "Percent" - }, - "bw1_lamp_brightness50": { - "units": "Percent" - }, - "bw1_lamp_brightness57": { - "units": "Percent" - }, - "bw1_lamp_brightness56": { - "units": "Percent" - }, - "bw1_lamp_brightness55": { - "units": "Percent" - }, - "bw1_lamp_brightness54": { - "units": "Percent" - }, - "bw1_lamp_brightness59": { - "units": "Percent" - }, - "bw1_light_level9": { - "units": "Luxes" - }, - "bw1_lamp_brightness58": { - "units": "Percent" - }, - "bw1_light_level8": { - "units": "Luxes" - }, - "bw4_lamp_brightness1": { - "units": "Percent" - }, - "bw4_lamp_brightness3": { - "units": "Percent" - }, - "bw4_lamp_brightness2": { - "units": "Percent" - }, - "bw4_lamp_brightness5": { - "units": "Percent" - }, - "bw4_lamp_brightness4": { - "units": "Percent" - }, - "bw4_lamp_brightness7": { - "units": "Percent" - }, - "bw4_lamp_brightness6": { - "units": "Percent" - }, - "bw5_occupancy8": { - "units": "No-units" - }, - "bw5_occupancy9": { - "units": "No-units" - }, - "bw5_occupancy6": { - "units": "No-units" - }, - "bw5_occupancy7": { - "units": "No-units" - }, - "bw5_occupancy1": { - "units": "No-units" - }, - "bw5_occupancy4": { - "units": "No-units" - }, - "bw5_occupancy5": { - "units": "No-units" - }, - "bw5_occupancy2": { - "units": "No-units" - }, - "bw5_occupancy3": { - "units": "No-units" - }, - "bw4_lamp_brightness9": { - "units": "Percent" - }, - "bw4_lamp_brightness8": { - "units": "Percent" - }, - "bw6_group_brightness16": { - "units": "Percent" - }, - "bw6_group_brightness7": { - "units": "Percent" - }, - "bw6_group_brightness14": { - "units": "Percent" - }, - "bw6_group_brightness8": { - "units": "Percent" - }, - "bw6_group_brightness15": { - "units": "Percent" - }, - "bw6_group_brightness9": { - "units": "Percent" - }, - "bw6_group_brightness12": { - "units": "Percent" - }, - "bw6_group_brightness13": { - "units": "Percent" - }, - "bw2_light_level15": { - "units": "Luxes" - }, - "bw6_group_brightness3": { - "units": "Percent" - }, - "bw2_light_level14": { - "units": "Luxes" - }, - "bw6_group_brightness4": { - "units": "Percent" - }, - "bw6_group_brightness5": { - "units": "Percent" - }, - "bw2_light_level16": { - "units": "Luxes" - }, - "bw6_group_brightness6": { - "units": "Percent" - }, - "bw2_light_level11": { - "units": "Luxes" - }, - "bw2_light_level10": { - "units": "Luxes" - }, - "bw2_light_level13": { - "units": "Luxes" - }, - "bw6_group_brightness1": { - "units": "Percent" - }, - "bw2_light_level12": { - "units": "Luxes" - }, - "bw6_group_brightness2": { - "units": "Percent" - }, - "bw2_group_brightness16": { - "units": "Percent" - }, - "bw2_group_brightness15": { - "units": "Percent" - }, - "bw6_group_brightness10": { - "units": "Percent" - }, - "bw2_group_brightness14": { - "units": "Percent" - }, - "bw6_group_brightness11": { - "units": "Percent" - }, - "bw2_group_brightness13": { - "units": "Percent" - }, - "bw2_group_brightness12": { - "units": "Percent" - }, - "bw2_group_brightness11": { - "units": "Percent" - }, - "bw2_group_brightness10": { - "units": "Percent" - }, - "bw5_group_brightness1": { - "units": "Percent" - }, - "bw5_group_brightness3": { - "units": "Percent" - }, - "bw5_group_brightness2": { - "units": "Percent" - }, - "bw5_group_brightness5": { - "units": "Percent" - }, - "bw5_group_brightness4": { - "units": "Percent" - }, - "bw5_group_brightness7": { - "units": "Percent" - }, - "bw5_group_brightness6": { - "units": "Percent" - }, - "bw5_group_brightness9": { - "units": "Percent" - }, - "bw5_group_brightness8": { - "units": "Percent" - }, - "bw4_light_level16": { - "units": "Luxes" - }, - "bw3_occupancy3": { - "units": "No-units" - }, - "bw3_occupancy2": { - "units": "No-units" - }, - "bw3_occupancy1": { - "units": "No-units" - }, - "bw5_light_level10": { - "units": "Luxes" - }, - "bw5_light_level11": { - "units": "Luxes" - }, - "bw5_light_level12": { - "units": "Luxes" - }, - "bw5_light_level13": { - "units": "Luxes" - }, - "bw5_light_level14": { - "units": "Luxes" - }, - "bw3_occupancy9": { - "units": "No-units" - }, - "bw3_occupancy8": { - "units": "No-units" - }, - "bw3_occupancy7": { - "units": "No-units" - }, - "bw3_occupancy6": { - "units": "No-units" - }, - "bw3_occupancy5": { - "units": "No-units" - }, - "bw3_occupancy4": { - "units": "No-units" - }, - "bw4_light_level12": { - "units": "Luxes" - }, - "bw4_light_level13": { - "units": "Luxes" - }, - "bw4_light_level14": { - "units": "Luxes" - }, - "bw4_light_level15": { - "units": "Luxes" - }, - "bw4_light_level10": { - "units": "Luxes" - }, - "bw4_light_level11": { - "units": "Luxes" - }, - "bw2_group_brightness5": { - "units": "Percent" - }, - "bw2_group_brightness6": { - "units": "Percent" - }, - "bw2_group_brightness3": { - "units": "Percent" - }, - "bw2_group_brightness4": { - "units": "Percent" - }, - "bw6_lamp_brightness1": { - "units": "Percent" - }, - "bw2_group_brightness9": { - "units": "Percent" - }, - "bw2_group_brightness7": { - "units": "Percent" - }, - "bw2_group_brightness8": { - "units": "Percent" - }, - "bw3_light_level10": { - "units": "Luxes" - }, - "bw6_lamp_brightness6": { - "units": "Percent" - }, - "bw6_lamp_brightness7": { - "units": "Percent" - }, - "bw3_light_level12": { - "units": "Luxes" - }, - "bw6_lamp_brightness8": { - "units": "Percent" - }, - "bw3_light_level11": { - "units": "Luxes" - }, - "bw6_lamp_brightness9": { - "units": "Percent" - }, - "bw3_light_level14": { - "units": "Luxes" - }, - "bw6_lamp_brightness2": { - "units": "Percent" - }, - "bw3_light_level13": { - "units": "Luxes" - }, - "bw6_lamp_brightness3": { - "units": "Percent" - }, - "bw3_light_level16": { - "units": "Luxes" - }, - "bw6_lamp_brightness4": { - "units": "Percent" - }, - "bw3_light_level15": { - "units": "Luxes" - }, - "bw6_lamp_brightness5": { - "units": "Percent" - }, - "bw2_lamp_brightness18": { - "units": "Percent" - }, - "bw2_lamp_brightness17": { - "units": "Percent" - }, - "bw2_lamp_brightness19": { - "units": "Percent" - }, - "bw2_lamp_brightness14": { - "units": "Percent" - }, - "bw2_lamp_brightness13": { - "units": "Percent" - }, - "bw2_lamp_brightness16": { - "units": "Percent" - }, - "bw2_lamp_brightness15": { - "units": "Percent" - }, - "bw2_lamp_brightness10": { - "units": "Percent" - }, - "bw2_lamp_brightness12": { - "units": "Percent" - }, - "bw2_lamp_brightness11": { - "units": "Percent" - }, - "bw2_lamp_brightness7": { - "units": "Percent" - }, - "bw2_lamp_brightness6": { - "units": "Percent" - }, - "bw2_lamp_brightness9": { - "units": "Percent" - }, - "bw2_lamp_brightness8": { - "units": "Percent" - }, - "bw3_lamp_brightness11": { - "units": "Percent" - }, - "bw3_lamp_brightness10": { - "units": "Percent" - }, - "bw3_lamp_brightness19": { - "units": "Percent" - }, - "bw3_lamp_brightness18": { - "units": "Percent" - }, - "bw3_lamp_brightness17": { - "units": "Percent" - }, - "bw3_lamp_brightness16": { - "units": "Percent" - }, - "bw2_group_brightness1": { - "units": "Percent" - }, - "bw3_lamp_brightness15": { - "units": "Percent" - }, - "bw6_light_level13": { - "units": "Luxes" - }, - "bw2_group_brightness2": { - "units": "Percent" - }, - "bw3_lamp_brightness14": { - "units": "Percent" - }, - "bw6_light_level12": { - "units": "Luxes" - }, - "bw3_lamp_brightness13": { - "units": "Percent" - }, - "bw6_light_level11": { - "units": "Luxes" - }, - "bw3_lamp_brightness12": { - "units": "Percent" - }, - "bw6_light_level10": { - "units": "Luxes" - }, - "bw2_occupancy2": { - "units": "No-units" - }, - "bw2_occupancy1": { - "units": "No-units" - }, - "bw4_lamp_brightness10": { - "units": "Percent" - }, - "bw2_occupancy8": { - "units": "No-units" - }, - "bw4_lamp_brightness13": { - "units": "Percent" - }, - "bw2_occupancy7": { - "units": "No-units" - }, - "bw4_lamp_brightness14": { - "units": "Percent" - }, - "bw4_lamp_brightness11": { - "units": "Percent" - }, - "bw2_occupancy9": { - "units": "No-units" - }, - "bw4_lamp_brightness12": { - "units": "Percent" - }, - "bw2_occupancy4": { - "units": "No-units" - }, - "bw4_lamp_brightness17": { - "units": "Percent" - }, - "bw2_occupancy3": { - "units": "No-units" - }, - "bw4_lamp_brightness18": { - "units": "Percent" - }, - "bw2_occupancy6": { - "units": "No-units" - }, - "bw4_lamp_brightness15": { - "units": "Percent" - }, - "bw2_occupancy5": { - "units": "No-units" - }, - "bw4_lamp_brightness16": { - "units": "Percent" - }, - "bw2_lamp_brightness3": { - "units": "Percent" - }, - "bw2_lamp_brightness2": { - "units": "Percent" - }, - "bw2_lamp_brightness5": { - "units": "Percent" - }, - "bw2_lamp_brightness4": { - "units": "Percent" - }, - "bw3_group_brightness1": { - "units": "Percent" - }, - "bw2_lamp_brightness1": { - "units": "Percent" - }, - "bw3_group_brightness6": { - "units": "Percent" - }, - "bw5_light_level15": { - "units": "Luxes" - }, - "bw3_group_brightness7": { - "units": "Percent" - }, - "bw5_light_level16": { - "units": "Luxes" - }, - "bw3_group_brightness8": { - "units": "Percent" - }, - "bw3_group_brightness9": { - "units": "Percent" - }, - "bw3_group_brightness2": { - "units": "Percent" - }, - "bw3_group_brightness3": { - "units": "Percent" - }, - "bw3_group_brightness4": { - "units": "Percent" - }, - "bw3_group_brightness5": { - "units": "Percent" - }, - "bw3_lamp_brightness33": { - "units": "Percent" - }, - "bw3_lamp_brightness32": { - "units": "Percent" - }, - "bw3_lamp_brightness31": { - "units": "Percent" - }, - "bw3_lamp_brightness30": { - "units": "Percent" - }, - "bw3_lamp_brightness39": { - "units": "Percent" - }, - "bw3_lamp_brightness38": { - "units": "Percent" - }, - "bw3_lamp_brightness37": { - "units": "Percent" - }, - "bw3_lamp_brightness36": { - "units": "Percent" - }, - "bw3_lamp_brightness35": { - "units": "Percent" - }, - "bw3_lamp_brightness34": { - "units": "Percent" - }, - "bw4_occupancy12": { - "units": "No-units" - }, - "bw5_occupancy14": { - "units": "No-units" - }, - "bw4_occupancy13": { - "units": "No-units" - }, - "bw5_occupancy13": { - "units": "No-units" - }, - "bw6_light_level16": { - "units": "Luxes" - }, - "bw4_occupancy10": { - "units": "No-units" - }, - "bw5_occupancy16": { - "units": "No-units" - }, - "bw6_light_level15": { - "units": "Luxes" - }, - "bw4_occupancy11": { - "units": "No-units" - }, - "bw5_occupancy15": { - "units": "No-units" - }, - "bw6_light_level14": { - "units": "Luxes" - }, - "bw1_occupancy14": { - "units": "No-units" - }, - "bw1_occupancy13": { - "units": "No-units" - }, - "bw1_occupancy16": { - "units": "No-units" - }, - "bw1_occupancy15": { - "units": "No-units" - }, - "bw1_occupancy10": { - "units": "No-units" - }, - "bw1_occupancy12": { - "units": "No-units" - }, - "bw1_occupancy11": { - "units": "No-units" - }, - "bw3_lamp_brightness22": { - "units": "Percent" - }, - "bw3_lamp_brightness21": { - "units": "Percent" - }, - "bw3_lamp_brightness20": { - "units": "Percent" - }, - "bw3_lamp_brightness29": { - "units": "Percent" - }, - "bw3_lamp_brightness28": { - "units": "Percent" - }, - "bw3_lamp_brightness27": { - "units": "Percent" - }, - "bw3_lamp_brightness26": { - "units": "Percent" - }, - "bw4_occupancy16": { - "units": "No-units" - }, - "bw5_occupancy10": { - "units": "No-units" - }, - "bw3_lamp_brightness25": { - "units": "Percent" - }, - "bw3_lamp_brightness24": { - "units": "Percent" - }, - "bw4_occupancy14": { - "units": "No-units" - }, - "bw5_occupancy12": { - "units": "No-units" - }, - "bw3_lamp_brightness23": { - "units": "Percent" - }, - "bw4_occupancy15": { - "units": "No-units" - }, - "bw5_occupancy11": { - "units": "No-units" - }, - "bw4_lamp_brightness42": { - "units": "Percent" - }, - "bw4_lamp_brightness43": { - "units": "Percent" - }, - "bw4_lamp_brightness40": { - "units": "Percent" - }, - "bw4_lamp_brightness41": { - "units": "Percent" - }, - "bw4_lamp_brightness46": { - "units": "Percent" - }, - "bw4_lamp_brightness47": { - "units": "Percent" - }, - "bw4_lamp_brightness44": { - "units": "Percent" - }, - "bw4_lamp_brightness45": { - "units": "Percent" - }, - "bw4_lamp_brightness48": { - "units": "Percent" - }, - "bw4_lamp_brightness49": { - "units": "Percent" - }, - "bw5_lamp_brightness3": { - "units": "Percent" - }, - "bw5_lamp_brightness4": { - "units": "Percent" - }, - "bw5_lamp_brightness1": { - "units": "Percent" - }, - "bw5_lamp_brightness2": { - "units": "Percent" - }, - "bw5_lamp_brightness7": { - "units": "Percent" - }, - "bw5_lamp_brightness8": { - "units": "Percent" - }, - "bw5_lamp_brightness5": { - "units": "Percent" - }, - "bw5_lamp_brightness6": { - "units": "Percent" - }, - "bw4_lamp_brightness50": { - "units": "Percent" - }, - "bw4_lamp_brightness53": { - "units": "Percent" - }, - "bw4_lamp_brightness54": { - "units": "Percent" - }, - "bw4_lamp_brightness51": { - "units": "Percent" - }, - "bw4_lamp_brightness52": { - "units": "Percent" - }, - "bw4_lamp_brightness57": { - "units": "Percent" - }, - "bw4_lamp_brightness58": { - "units": "Percent" - }, - "bw4_lamp_brightness55": { - "units": "Percent" - }, - "bw4_lamp_brightness56": { - "units": "Percent" - }, - "bw4_lamp_brightness59": { - "units": "Percent" - }, - "bw4_group_brightness8": { - "units": "Percent" - }, - "bw4_group_brightness7": { - "units": "Percent" - }, - "bw4_group_brightness6": { - "units": "Percent" - }, - "bw4_group_brightness5": { - "units": "Percent" - }, - "bw4_group_brightness4": { - "units": "Percent" - }, - "bw4_group_brightness3": { - "units": "Percent" - }, - "bw4_group_brightness2": { - "units": "Percent" - }, - "bw4_group_brightness1": { - "units": "Percent" - }, - "bw4_group_brightness9": { - "units": "Percent" - }, - "bw4_lamp_brightness20": { - "units": "Percent" - }, - "bw4_lamp_brightness21": { - "units": "Percent" - }, - "bw4_lamp_brightness24": { - "units": "Percent" - }, - "bw4_lamp_brightness25": { - "units": "Percent" - }, - "bw4_lamp_brightness22": { - "units": "Percent" - }, - "bw4_lamp_brightness23": { - "units": "Percent" - }, - "bw4_lamp_brightness28": { - "units": "Percent" - }, - "bw4_lamp_brightness29": { - "units": "Percent" - }, - "bw4_lamp_brightness26": { - "units": "Percent" - }, - "bw4_lamp_brightness27": { - "units": "Percent" - }, - "bw4_lamp_brightness19": { - "units": "Percent" - }, - "bw5_light_level2": { - "units": "Luxes" - }, - "bw5_light_level3": { - "units": "Luxes" - }, - "bw5_light_level1": { - "units": "Luxes" - }, - "bw5_light_level6": { - "units": "Luxes" - }, - "bw5_light_level7": { - "units": "Luxes" - }, - "bw5_light_level4": { - "units": "Luxes" - }, - "bw5_light_level5": { - "units": "Luxes" - }, - "bw5_light_level8": { - "units": "Luxes" - }, - "bw5_light_level9": { - "units": "Luxes" - }, - "bw4_lamp_brightness31": { - "units": "Percent" - }, - "bw4_lamp_brightness32": { - "units": "Percent" - }, - "bw4_lamp_brightness30": { - "units": "Percent" - }, - "bw4_lamp_brightness35": { - "units": "Percent" - }, - "bw4_lamp_brightness36": { - "units": "Percent" - }, - "bw4_lamp_brightness33": { - "units": "Percent" - }, - "bw4_lamp_brightness34": { - "units": "Percent" - }, - "bw4_lamp_brightness39": { - "units": "Percent" - }, - "bw4_lamp_brightness37": { - "units": "Percent" - }, - "bw4_lamp_brightness38": { - "units": "Percent" - } - } - }, - "version": 1, - "timestamp": "2020-03-05T14:42:59.743Z" -} diff --git a/schemas/udmi/metadata.tests/toomany.out b/schemas/udmi/metadata.tests/toomany.out deleted file mode 100644 index c4e33ac250..0000000000 --- a/schemas/udmi/metadata.tests/toomany.out +++ /dev/null @@ -1,6 +0,0 @@ -Validating 1 schemas - Validating 1 files against metadata.json - Against input metadata.tests/toomany.json - #: 2 schema violations found - #/pointset/points: maximum size: [150], found: [672] - #/system/physical_tag/asset/name: string [UK-LON-S2_LTGW-3] does not match pattern ^[A-Z]{2,6}-[0-9]{1,6}$ diff --git a/schemas/udmi/metadata_cloud.json b/schemas/udmi/metadata_cloud.json deleted file mode 100644 index 5ca41285a7..0000000000 --- a/schemas/udmi/metadata_cloud.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "title": "Cloud configuration metadata snippet", - "type": "object", - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false, - "properties": { - "auth_type": { - "enum": [ - "RS256", - "RS256_X506" - ] - }, - "is_gateway": { - "type": "boolean" - } - }, - "required": [ - "auth_type" - ] -} diff --git a/schemas/udmi/metadata_gateway.json b/schemas/udmi/metadata_gateway.json deleted file mode 100644 index f15dee7344..0000000000 --- a/schemas/udmi/metadata_gateway.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "title": "Gateway metadata snippet", - "type": "object", - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false, - "properties": { - "gateway_id": { - "type": "string", - "pattern": "^[A-Z]{3}-[1-9][0-9]{0,2}$" - }, - "subsystem": { - "type": "string", - "pattern": "^[a-z0-9-]+$" - }, - "proxy_ids": { - "type": "array", - "items": { - "type": "string", - "pattern": "^[A-Z]{3}-[1-9][0-9]{0,2}$" - } - } - }, - "oneOf": [ - { "required": ["gateway_id"] }, - { "required": ["proxy_ids"] } - ] -} diff --git a/schemas/udmi/metadata_localnet.json b/schemas/udmi/metadata_localnet.json deleted file mode 100644 index be7de102b5..0000000000 --- a/schemas/udmi/metadata_localnet.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "title": "Local network metadata snippet", - "type": "object", - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false, - "properties": { - "subsystem": { - "type": "object", - "patternProperties": { - "^[a-z0-9-]+$": { - "additionalProperties": false, - "properties": { - "local_id": { - "type": "string" - } - }, - "required": [ - "local_id" - ] - } - } - } - }, - "required": [ - "subsystem" - ] -} diff --git a/schemas/udmi/metadata_pointset.json b/schemas/udmi/metadata_pointset.json deleted file mode 100644 index 4d6ac05dce..0000000000 --- a/schemas/udmi/metadata_pointset.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "title": "Pointset metadata snippet", - "type": "object", - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false, - "properties": { - "points": { - "additionalProperties": false, - "maxProperties": 150, - "patternProperties": { - "^[a-z][a-z0-9]*(_[a-z0-9]+)*$": { - "additionalProperties": false, - "properties": { - "units": { - "$ref": "file:units.json#" - }, - "ref": { - "type": "string" - } - } - } - } - } - }, - "required": [ - "points" - ] -} diff --git a/schemas/udmi/metadata_system.json b/schemas/udmi/metadata_system.json deleted file mode 100644 index f1d48da2fd..0000000000 --- a/schemas/udmi/metadata_system.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "title": "System metadata snippet", - "type": "object", - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false, - "properties": { - "location": { - "type": "object", - "additionalProperties": false, - "properties": { - "site": { - "type": "string", - "pattern": "^[A-Z]{2}-[A-Z]{3}-[A-Z0-9]{2,9}$" - }, - "section": { - "type": "string", - "pattern": "^[A-Z0-9-]+$" - }, - "position": { - "type": "object", - "additionalProperties": false, - "properties": { - "x": { - "type": "number" - }, - "y": { - "type": "number" - } - }, - "required": [ - "x", - "y" - ] - } - }, - "required": [ - "site" - ] - }, - "physical_tag": { - "type": "object", - "additionalProperties": false, - "properties": { - "asset": { - "type": "object", - "additionalProperties": false, - "properties": { - "guid": { - "type": "string", - "pattern": "^[a-z]+://[-0-9a-zA-Z_$]+$" - }, - "site": { - "type": "string", - "pattern": "^[A-Z]{2}-[A-Z]{3}-[A-Z0-9]{2,9}$" - }, - "name": { - "type": "string", - "pattern": "^[A-Z]{2,6}-[0-9]{1,6}$" - } - }, - "required": [ - "guid", - "name" - ] - } - }, - "required": [ - "asset" - ] - }, - "aux": { - "type": "object", - "additionalProperties": false, - "properties": { - "suffix": { - "type": "string", - "pattern": "^[a-zA-Z0-9-]+$" - } - } - } - }, - "required": [ - "location", - "physical_tag" - ] -} diff --git a/schemas/udmi/pointset.json b/schemas/udmi/pointset.json deleted file mode 100644 index b18d31eda8..0000000000 --- a/schemas/udmi/pointset.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "title": "Pointset telemetry schema", - "type": "object", - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false, - "properties": { - "timestamp": { - "type": "string", - "format": "date-time" - }, - "version": { - "enum": [ - 1 - ] - }, - "points": { - "additionalProperties": false, - "patternProperties": { - "^[a-z][a-z0-9]*(_[a-z0-9]+)*$": { - "$ref": "#/definitions/point_property_names" - } - } - } - }, - "required": [ - "timestamp", - "version", - "points" - ], - "definitions": { - "point_property_names": { - "type": "object", - "propertyNames": { - "oneOf": [ - { - "enum": [ - "present_value" - ] - } - ] - }, - "required": [ - "present_value" - ] - } - } -} diff --git a/schemas/udmi/pointset.tests/empty.json b/schemas/udmi/pointset.tests/empty.json deleted file mode 100644 index 2c63c08510..0000000000 --- a/schemas/udmi/pointset.tests/empty.json +++ /dev/null @@ -1,2 +0,0 @@ -{ -} diff --git a/schemas/udmi/pointset.tests/empty.out b/schemas/udmi/pointset.tests/empty.out deleted file mode 100644 index 5f645ca58a..0000000000 --- a/schemas/udmi/pointset.tests/empty.out +++ /dev/null @@ -1,7 +0,0 @@ -Validating 1 schemas - Validating 1 files against pointset.json - Against input pointset.tests/empty.json - #: 3 schema violations found - #: required key [points] not found - #: required key [timestamp] not found - #: required key [version] not found diff --git a/schemas/udmi/pointset.tests/errors.json b/schemas/udmi/pointset.tests/errors.json deleted file mode 100644 index 321ea7c4a5..0000000000 --- a/schemas/udmi/pointset.tests/errors.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "version": 1, - "timestamp": "2018-08-26T21:39:29.364Z", - "id": "sneakyCASE", - "comment$string": "world", - "properties": { - "$comment": "Common error cases for target telemetry." - }, - "points": { - "comment$string": "world", - "analogValue_1": { - "present_value": true - }, - "bad_entity_name_": { - "present_value": 21.30108642578125 - }, - "guid": "ab9402fa-2c5a-42d1-b4f3-d40b440dea13", - "yoyo_motion_sensor": { - "bad_property_name": true - }, - "bad_____sensor": { - "present_value": true - }, - "missing_present_value": { - }, - "old_properties": { - "properties": { - "present_value": true - } - }, - "magic_voice_recognizer": { - "present_value": { - "present_value": true - } - } - } -} diff --git a/schemas/udmi/pointset.tests/errors.out b/schemas/udmi/pointset.tests/errors.out deleted file mode 100644 index e973a0e733..0000000000 --- a/schemas/udmi/pointset.tests/errors.out +++ /dev/null @@ -1,22 +0,0 @@ -Validating 1 schemas - Validating 1 files against pointset.json - Against input pointset.tests/errors.json - #: 13 schema violations found - #/points: 10 schema violations found - #/points/guid: expected type: JSONObject, found: String - #/points/missing_present_value: required key [present_value] not found - #/points/old_properties: 2 schema violations found - #/points/old_properties/properties: #: 0 subschemas matched instead of one - #/points/old_properties/properties: properties is not a valid enum value - #/points/old_properties: required key [present_value] not found - #/points/yoyo_motion_sensor: 2 schema violations found - #/points/yoyo_motion_sensor/bad_property_name: #: 0 subschemas matched instead of one - #/points/yoyo_motion_sensor/bad_property_name: bad_property_name is not a valid enum value - #/points/yoyo_motion_sensor: required key [present_value] not found - #/points: extraneous key [analogValue_1] is not permitted - #/points: extraneous key [bad_____sensor] is not permitted - #/points: extraneous key [bad_entity_name_] is not permitted - #/points: extraneous key [comment$string] is not permitted - #: extraneous key [comment$string] is not permitted - #: extraneous key [id] is not permitted - #: extraneous key [properties] is not permitted diff --git a/schemas/udmi/pointset.tests/example.json b/schemas/udmi/pointset.tests/example.json deleted file mode 100644 index 7af10743e5..0000000000 --- a/schemas/udmi/pointset.tests/example.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "version": 1, - "timestamp": "2018-08-26T21:39:29.364Z", - "points": { - "reading_value": { - "present_value": 21.30108642578125 - }, - "nexus_sensor": { - "present_value": 21.1 - }, - "yoyo_motion_sensor": { - "present_value": true - }, - "enum_value": { - "present_value": "hello" - } - } -} diff --git a/schemas/udmi/pointset.tests/example.out b/schemas/udmi/pointset.tests/example.out deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/schemas/udmi/pointset.tests/fcu.json b/schemas/udmi/pointset.tests/fcu.json deleted file mode 100644 index 9b45dfbfe6..0000000000 --- a/schemas/udmi/pointset.tests/fcu.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "version": 1, - "timestamp": "2019-01-17T14:02:29.364Z", - "points": { - "space_temperature_sensor": { - "present_value": 21.30108642578125 - }, - "fan_run_status": { - "present_value": true - }, - "fan_run_enable": { - "present_value": false - }, - "chilled_water_valve_percentage_command": { - "present_value": 76 - } - } -} diff --git a/schemas/udmi/pointset.tests/fcu.out b/schemas/udmi/pointset.tests/fcu.out deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/schemas/udmi/pointset.tests/smartprimus.json b/schemas/udmi/pointset.tests/smartprimus.json deleted file mode 100644 index 9b45dfbfe6..0000000000 --- a/schemas/udmi/pointset.tests/smartprimus.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "version": 1, - "timestamp": "2019-01-17T14:02:29.364Z", - "points": { - "space_temperature_sensor": { - "present_value": 21.30108642578125 - }, - "fan_run_status": { - "present_value": true - }, - "fan_run_enable": { - "present_value": false - }, - "chilled_water_valve_percentage_command": { - "present_value": 76 - } - } -} diff --git a/schemas/udmi/pointset.tests/smartprimus.out b/schemas/udmi/pointset.tests/smartprimus.out deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/schemas/udmi/properties.json b/schemas/udmi/properties.json deleted file mode 100644 index 8b4375c07a..0000000000 --- a/schemas/udmi/properties.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "title": "Device Properties Schema", - "type": "object", - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false, - "required": [ - "key_type", - "version", - "connect" - ], - "properties": { - "key_type": { - "enum": [ - "RSA_PEM", - "RSA_X509_PEM" - ] - }, - "version": { - "enum": [ - 1 - ] - }, - "connect": { - "enum": [ - "direct" - ] - } - } -} diff --git a/schemas/udmi/state.json b/schemas/udmi/state.json deleted file mode 100644 index 117881e3cb..0000000000 --- a/schemas/udmi/state.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "title": "Device State schema", - "type": "object", - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false, - "required": [ - "timestamp", - "version", - "system" - ], - "properties": { - "timestamp": { - "type": "string", - "format": "date-time" - }, - "version": { - "enum": [ - 1 - ] - }, - "system": { - "$ref": "file:state_system.json#" - }, - "gateway": { - "$ref": "file:state_gateway.json#" - }, - "pointset": { - "$ref": "file:state_pointset.json#" - } - } -} diff --git a/schemas/udmi/state.tests/empty.json b/schemas/udmi/state.tests/empty.json deleted file mode 100644 index 2c63c08510..0000000000 --- a/schemas/udmi/state.tests/empty.json +++ /dev/null @@ -1,2 +0,0 @@ -{ -} diff --git a/schemas/udmi/state.tests/empty.out b/schemas/udmi/state.tests/empty.out deleted file mode 100644 index 09d7bf88cf..0000000000 --- a/schemas/udmi/state.tests/empty.out +++ /dev/null @@ -1,7 +0,0 @@ -Validating 1 schemas - Validating 1 files against state.json - Against input state.tests/empty.json - #: 3 schema violations found - #: required key [system] not found - #: required key [timestamp] not found - #: required key [version] not found diff --git a/schemas/udmi/state.tests/errors.json b/schemas/udmi/state.tests/errors.json deleted file mode 100644 index 5977f68e90..0000000000 --- a/schemas/udmi/state.tests/errors.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "version": 1, - "timestamp": "2018-08-26T21:39:29.364Z", - "id": "monkey_brains", - "system": { - "device_id": "33895507", - "device_status": "ok", - "object_name": "UK-BRH-XX_AHU-001", - "fling": "hello", - "firmware": { - "revision": "should be version" - }, - "system_status": "Operational", - "statuses": { - "default": { - "timestamp": "2018-08-26T21:39:30.364Z", - "level": 30 - } - }, - "status": "hunky-dory" - }, - "status": [ - { - "level": 30 - } - ], - "pointset": { - "points": { - "return_air_temperature_sensor": { - "object_type": "analog_input", - "instance_number": 4, - "cov_increment": 0.300000011920929, - "deadband": 0, - "rapt": "hello", - "high_limit": 0, - "low_limit": 0, - "resolution": 0.04952822998166084, - "units": "Degrees Celsius", - "status": "it's working!" - } - } - } -} diff --git a/schemas/udmi/state.tests/errors.out b/schemas/udmi/state.tests/errors.out deleted file mode 100644 index f58e247fc5..0000000000 --- a/schemas/udmi/state.tests/errors.out +++ /dev/null @@ -1,32 +0,0 @@ -Validating 1 schemas - Validating 1 files against state.json - Against input state.tests/errors.json - #: 24 schema violations found - #/pointset/points/return_air_temperature_sensor: 9 schema violations found - #/pointset/points/return_air_temperature_sensor/status: expected type: JSONObject, found: String - #/pointset/points/return_air_temperature_sensor: extraneous key [cov_increment] is not permitted - #/pointset/points/return_air_temperature_sensor: extraneous key [deadband] is not permitted - #/pointset/points/return_air_temperature_sensor: extraneous key [high_limit] is not permitted - #/pointset/points/return_air_temperature_sensor: extraneous key [instance_number] is not permitted - #/pointset/points/return_air_temperature_sensor: extraneous key [low_limit] is not permitted - #/pointset/points/return_air_temperature_sensor: extraneous key [object_type] is not permitted - #/pointset/points/return_air_temperature_sensor: extraneous key [rapt] is not permitted - #/pointset/points/return_air_temperature_sensor: extraneous key [resolution] is not permitted - #/system: 13 schema violations found - #/system/firmware: 2 schema violations found - #/system/firmware: extraneous key [revision] is not permitted - #/system/firmware: required key [version] not found - #/system/statuses/default: 3 schema violations found - #/system/statuses/default/level: 30 is not greater or equal to 100 - #/system/statuses/default: required key [category] not found - #/system/statuses/default: required key [message] not found - #/system: extraneous key [device_id] is not permitted - #/system: extraneous key [device_status] is not permitted - #/system: extraneous key [fling] is not permitted - #/system: extraneous key [object_name] is not permitted - #/system: extraneous key [status] is not permitted - #/system: extraneous key [system_status] is not permitted - #/system: required key [make_model] not found - #/system: required key [operational] not found - #: extraneous key [id] is not permitted - #: extraneous key [status] is not permitted diff --git a/schemas/udmi/state.tests/example.json b/schemas/udmi/state.tests/example.json deleted file mode 100644 index 92044b86a6..0000000000 --- a/schemas/udmi/state.tests/example.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "version": 1, - "timestamp": "2018-08-26T21:39:29.364Z", - "system": { - "make_model": "ACME Bird Trap", - "firmware": { - "version": "3.2a" - }, - "last_config": "2018-08-26T21:49:29.364Z", - "operational": true, - "statuses": { - "base_system": { - "message": "Tickity Boo", - "category": "device.state.com", - "timestamp": "2018-08-26T21:39:30.364Z", - "level": 600 - } - } - }, - "pointset": { - "points": { - "return_air_temperature_sensor": { - "units": "Celsius", - "status": { - "message": "Invalid sample time", - "category": "device.config.validate", - "timestamp": "2018-08-26T21:39:28.364Z", - "level": 800 - } - }, - "nexus_sensor": { - "units": "Celsius", - "source": "fix" - } - } - } -} diff --git a/schemas/udmi/state.tests/example.out b/schemas/udmi/state.tests/example.out deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/schemas/udmi/state.tests/fcu.json b/schemas/udmi/state.tests/fcu.json deleted file mode 100644 index b2a55220e8..0000000000 --- a/schemas/udmi/state.tests/fcu.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "version": 1, - "timestamp": "2019-01-17T14:02:29.364Z", - "system": { - "make_model": "EasyIO FW-14", - "firmware": { - "version": "3.2a" - }, - "last_config": "2019-01-14T21:49:29.364Z", - "operational": true, - "statuses": { - "base_system": { - "message": "Time on the device is not synchronized", - "category": "com.acme.sync", - "timestamp": "2019-01-17T13:29:47.364Z", - "level": 600 - } - } - }, - "pointset": { - "points": { - "space_temperature_sensor": { - "units": "Degrees-Celsius", - "status": { - "message": "Present value out of limits", - "category": "com.acme.device.regulator", - "timestamp": "2019-01-17T11:39:28.364Z", - "level": 400 - } - }, - "fan_run_status": { - "status": { - "message": "Value overridden by fix_value", - "category": "com.acme.device.monitor", - "timestamp": "2019-01-17T10:59:11.364Z", - "level": 300 - } - }, - "fan_run_enable": { - "status": { - "message": "Value overridden by fix_value", - "category": "com.acme.device.manager", - "timestamp": "2019-01-17T13:14:55.364Z", - "level": 300 - } - }, - "chilled_water_valve_percentage_command": { - "units": "Percent" - } - } - } -} diff --git a/schemas/udmi/state.tests/fcu.out b/schemas/udmi/state.tests/fcu.out deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/schemas/udmi/state.tests/gateway.json b/schemas/udmi/state.tests/gateway.json deleted file mode 100644 index 72bbdbc4bb..0000000000 --- a/schemas/udmi/state.tests/gateway.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "version": 1, - "timestamp": "2018-08-26T21:39:29.364Z", - "system": { - "make_model": "ACME Gateway v2", - "firmware": { - "version": "3.2a" - }, - "last_config": "2018-08-26T21:49:29.364Z", - "operational": true, - "statuses": { - "base_system": { - "message": "Tickity Boo", - "category": "device.state.com", - "timestamp": "2018-08-26T21:39:30.364Z", - "level": 600 - } - } - }, - "gateway": { - "error_ids": [ "991", "SMS-91" ] - } -} diff --git a/schemas/udmi/state.tests/gateway.out b/schemas/udmi/state.tests/gateway.out deleted file mode 100644 index ae5507e2c2..0000000000 --- a/schemas/udmi/state.tests/gateway.out +++ /dev/null @@ -1,4 +0,0 @@ -Validating 1 schemas - Validating 1 files against state.json - Against input state.tests/gateway.json - #/gateway/error_ids/0: string [991] does not match pattern ^[A-Z]{3}-[1-9][0-9]{0,2}$ diff --git a/schemas/udmi/state.tests/rotate.json b/schemas/udmi/state.tests/rotate.json deleted file mode 100644 index 9c77e543ea..0000000000 --- a/schemas/udmi/state.tests/rotate.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "version": 1, - "timestamp": "2018-08-26T21:39:29.364Z", - "system": { - "make_model": "ACME Bird Trap", - "firmware": { - "version": "3.2a" - }, - "auth_key": { - "private_hash": "sha512:4e61746f21abe6708ca81a45a1851b82efd1f3ad7f9e6f6fc2dcf431e0ff95cdbcc6f5940a4bfb77df7aeb2f057d19cf5f234a664775edc66175025a14a87c3b" - }, - "last_config": "2018-08-26T21:49:29.364Z", - "operational": true, - "statuses": { - "base_system": { - "message": "Tickity Boo", - "category": "device.state.com", - "timestamp": "2018-08-26T21:39:30.364Z", - "level": 600 - } - } - }, - "pointset": { - "points": { - "return_air_temperature_sensor": { - "units": "Celsius", - "status": { - "message": "Invalid sample time", - "category": "device.config.validate", - "timestamp": "2018-08-26T21:39:28.364Z", - "level": 800 - } - } - } - } -} - diff --git a/schemas/udmi/state.tests/rotate.out b/schemas/udmi/state.tests/rotate.out deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/schemas/udmi/state_gateway.json b/schemas/udmi/state_gateway.json deleted file mode 100644 index 45dfd6f35c..0000000000 --- a/schemas/udmi/state_gateway.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "title": "Gateway Config Snippet", - "type": "object", - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false, - "required": [ - "error_ids" - ], - "properties": { - "error_ids": { - "type": "array", - "items": { - "type": "string", - "pattern": "^[A-Z]{3}-[1-9][0-9]{0,2}$" - } - } - } -} diff --git a/schemas/udmi/state_pointset.json b/schemas/udmi/state_pointset.json deleted file mode 100644 index b6d44061bd..0000000000 --- a/schemas/udmi/state_pointset.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "title": "pointset state snippet", - "type": "object", - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false, - "properties": { - "points": { - "additionalProperties": false, - "patternProperties": { - "^[a-z][a-z0-9]*(_[a-z0-9]+)*$": { - "additionalProperties": false, - "properties": { - "fault": { - "type": "boolean" - }, - "units": { - "type": "string", - }, - "source": { - "enum": [ - "fix" - ] - }, - "status": { - "$ref": "file:system.json#/definitions/entry" - } - } - } - } - } - }, - "required": [ - "points" - ] -} diff --git a/schemas/udmi/state_system.json b/schemas/udmi/state_system.json deleted file mode 100644 index 5fb326ac93..0000000000 --- a/schemas/udmi/state_system.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "title": "System state snippet", - "type": "object", - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false, - "properties": { - "make_model": { - "type": "string" - }, - "auth_key": { - "type": "object", - "additionalProperties": false, - "properties": { - "private_hash": { - "type": "string" - } - }, - "required": [ - "private_hash" - ] - }, - "firmware": { - "type": "object", - "additionalProperties": false, - "properties": { - "version": { - "type": "string" - } - }, - "required": [ - "version" - ] - }, - "last_config": { - "type": "string", - "format": "date-time" - }, - "operational": { - "type": "boolean" - }, - "statuses": { - "type": "object", - "additionalProperties": false, - "patternProperties": { - "^[a-z][a-z0-9]*(_[a-z0-9]+)*$": { - "$ref": "file:system.json#/definitions/entry" - } - } - } - }, - "required": [ - "make_model", - "firmware", - "operational" - ] -} diff --git a/schemas/udmi/system.json b/schemas/udmi/system.json deleted file mode 100644 index ca3d33d2d4..0000000000 --- a/schemas/udmi/system.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "title": "Log entry schema", - "type": "object", - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false, - "properties": { - "timestamp": { - "type": "string", - "format": "date-time" - }, - "version": { - "enum": [ - 1 - ] - }, - "logentries": { - "type": "array", - "items": { - "$ref": "#/definitions/entry" - } - } - }, - "required": [ - "timestamp", - "version" - ], - "definitions": { - "entry": { - "type": "object", - "additionalProperties": false, - "properties": { - "message": { - "type": "string" - }, - "detail": { - "type": "string" - }, - "category": { - "type": "string", - "pattern": "^[a-z][.a-zA-Z]*[a-zA-Z]$" - }, - "timestamp": { - "type": "string", - "format": "date-time" - }, - "level": { - "$comment": "https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#logseverity", - "type": "integer", - "multipleOf": 1, - "minimum": 100, - "maximum": 800 - } - }, - "required": [ - "message", - "category", - "timestamp", - "level" - ] - } - } -} diff --git a/schemas/udmi/system.tests/empty.json b/schemas/udmi/system.tests/empty.json deleted file mode 100644 index 2c63c08510..0000000000 --- a/schemas/udmi/system.tests/empty.json +++ /dev/null @@ -1,2 +0,0 @@ -{ -} diff --git a/schemas/udmi/system.tests/empty.out b/schemas/udmi/system.tests/empty.out deleted file mode 100644 index ad7bdffef5..0000000000 --- a/schemas/udmi/system.tests/empty.out +++ /dev/null @@ -1,6 +0,0 @@ -Validating 1 schemas - Validating 1 files against system.json - Against input system.tests/empty.json - #: 2 schema violations found - #: required key [timestamp] not found - #: required key [version] not found diff --git a/schemas/udmi/system.tests/errors.json b/schemas/udmi/system.tests/errors.json deleted file mode 100644 index ddf4c70815..0000000000 --- a/schemas/udmi/system.tests/errors.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "version": 1, - "timestamp": "2018-08-26T21:39:29.364Z", - "logentries": [ - { - "detail": "someplace, sometime", - "category": "com.testCategory$", - "level": 60 - }, - "nope" - ] -} diff --git a/schemas/udmi/system.tests/errors.out b/schemas/udmi/system.tests/errors.out deleted file mode 100644 index 3479a7a113..0000000000 --- a/schemas/udmi/system.tests/errors.out +++ /dev/null @@ -1,10 +0,0 @@ -Validating 1 schemas - Validating 1 files against system.json - Against input system.tests/errors.json - #/logentries: 5 schema violations found - #/logentries/0: 4 schema violations found - #/logentries/0/category: string [com.testCategory$] does not match pattern ^[a-z][.a-zA-Z]*[a-zA-Z]$ - #/logentries/0/level: 60 is not greater or equal to 100 - #/logentries/0: required key [message] not found - #/logentries/0: required key [timestamp] not found - #/logentries/1: expected type: JSONObject, found: String diff --git a/schemas/udmi/system.tests/example.json b/schemas/udmi/system.tests/example.json deleted file mode 100644 index 139253f721..0000000000 --- a/schemas/udmi/system.tests/example.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "version": 1, - "timestamp": "2018-08-26T21:39:29.364Z", - "logentries": [ - { - "message": "things are happening", - "detail": "someplace, sometime", - "timestamp": "2018-08-26T21:39:19.364Z", - "category": "com.testCategory", - "level": 600 - }, - { - "message": "something else happened", - "timestamp": "2018-08-26T21:39:39.364Z", - "detail": "someplace, sometime", - "category": "com.testCategory", - "level": 700 - } - ] -} diff --git a/schemas/udmi/system.tests/example.out b/schemas/udmi/system.tests/example.out deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/schemas/udmi/system.tests/fcu.json b/schemas/udmi/system.tests/fcu.json deleted file mode 100644 index ed4a8c7f1b..0000000000 --- a/schemas/udmi/system.tests/fcu.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "version": 1, - "timestamp": "2018-08-26T21:39:29.364Z", - "logentries": [ - { - "message": "System Booted", - "timestamp": "2018-08-26T20:39:19.364Z", - "category": "com.acme.system", - "level": 300 - }, - { - "message": "Device communication failed", - "detail": "Connection attempt to device 3564 failed", - "timestamp": "2018-08-26T21:39:19.364Z", - "category": "com.acme.comms", - "level": 700 - } - ] -} diff --git a/schemas/udmi/system.tests/fcu.out b/schemas/udmi/system.tests/fcu.out deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/schemas/udmi/units.json b/schemas/udmi/units.json deleted file mode 100644 index 3e375667d1..0000000000 --- a/schemas/udmi/units.json +++ /dev/null @@ -1,194 +0,0 @@ -{ - "description": "Taken from standard BACnet engineering units", - "enum": [ - "Square-meters", - "Square-feet", - "Milliamperes", - "Amperes", - "Ohms", - "Volts", - "Kilo-volts", - "Mega-volts", - "Volt-amperes", - "Kilo-volt-amperes", - "Mega-volt-amperes", - "Volt-amperes-reactive", - "Kilo-volt-amperes-reactive", - "Mega-volt-amperes-reactive", - "Degrees-phase", - "Power-factor", - "Joules", - "Kilojoules", - "Watt-hours", - "Kilowatt-hours", - "BTUs", - "Therms", - "Ton-hours", - "Joules-per-kilogram-dry-air", - "BTUs-per-pound-dry-air", - "Cycles-per-hour", - "Cycles-per-minute", - "Hertz", - "Grams-of-water-per-kilogram-dry-air", - "Percent-relative-humidity", - "Millimeters", - "Meters", - "Inches", - "Feet", - "Watts-per-square-foot", - "Watts-per-square-meter", - "Lumens", - "Luxes", - "Foot-candles", - "Kilograms", - "Pounds-mass", - "Tons", - "Kilograms-per-second", - "Kilograms-per-minute", - "Kilograms-per-hour", - "Pounds-mass-per-minute", - "Pounds-mass-per-hour", - "Watts", - "Kilowatts", - "Megawatts", - "BTUs-per-hour", - "Horsepower", - "Tons-refrigeration", - "Pascals", - "Kilopascals", - "Bars", - "Pounds-force-per-square-inch", - "Centimeters-of-water", - "Inches-of-water", - "Millimeters-of-mercury", - "Centimeters-of-mercury", - "Inches-of-mercury", - "Degrees-Celsius", - "Degrees-Kelvin", - "Degrees-Fahrenheit", - "Degree-days-Celsius", - "Degree-days-Fahrenheit", - "Years", - "Months", - "Weeks", - "Days", - "Hours", - "Minutes", - "Seconds", - "Meters-per-second", - "Kilometers-per-hour", - "Feet-per-second", - "Feet-per-minute", - "Miles-per-hour", - "Cubic-feet", - "Cubic-meters", - "Imperial-gallons", - "Liters", - "Us-gallons", - "Cubic-feet-per-minute", - "Cubic-meters-per-second", - "Imperial-gallons-per-minute", - "Liters-per-second", - "Liters-per-minute", - "Us-gallons-per-minute", - "Degrees-angular", - "Degrees-Celsius-per-hour", - "Degrees-Celsius-per-minute", - "Degrees-Fahrenheit-per-hour", - "Degrees-Fahrenheit-per-minute", - "No-units", - "Parts-per-million", - "Parts-per-billion", - "Percent", - "Percent-per-second", - "Per-minute", - "Per-second", - "Psi-per-Degree-Fahrenheit", - "Radians", - "Revolutions-per-minute", - "Currency1", - "Currency2", - "Currency3", - "Currency4", - "Currency5", - "Currency6", - "Currency7", - "Currency8", - "Currency9", - "Currency10", - "Square-inches", - "Square-centimeters", - "BTUs-per-pound", - "Centimeters", - "Pounds-mass-per-second", - "Delta-Degrees-Fahrenheit", - "Delta-Degrees-Kelvin", - "Kilohms", - "Megohms", - "Millivolts", - "Kilojoules-per-kilogram", - "Megajoules", - "Joules-per-degree-Kelvin", - "Joules-per-kilogram-degree-Kelvin", - "Kilohertz", - "Megahertz", - "Per-hour", - "Milliwatts", - "Hectopascals", - "Millibars", - "Cubic-meters-per-hour", - "Liters-per-hour", - "Kilowatt-hours-per-square-meter", - "Kilowatt-hours-per-square-foot", - "Megajoules-per-square-meter", - "Megajoules-per-square-foot", - "Watts-per-square-meter-Degree-Kelvin", - "Cubic-feet-per-second", - "Percent-obscuration-per-foot", - "Percent-obscuration-per-meter", - "Milliohms", - "Megawatt-hours", - "Kilo-BTUs", - "Mega-BTUs", - "Kilojoules-per-kilogram-dry-air", - "Megajoules-per-kilogram-dry-air", - "Kilojoules-per-degree-Kelvin", - "Megajoules-per-degree-Kelvin", - "Newton", - "Grams-per-second", - "Grams-per-minute", - "Tons-per-hour", - "Kilo-BTUs-per-hour", - "Hundredths-seconds", - "Milliseconds", - "Newton-meters", - "Millimeters-per-second", - "Millimeters-per-minute", - "Meters-per-minute", - "Meters-per-hour", - "Cubic-meters-per-minute", - "Meters-per-second-per-second", - "Amperes-per-meter", - "Amperes-per-square-meter", - "Ampere-square-meters", - "Farads", - "Henrys", - "Ohm-meters", - "Siemens", - "Siemens-per-meter", - "Teslas", - "Volts-per-degree-Kelvin", - "Volts-per-meter", - "Webers", - "Candelas", - "Candelas-per-square-meter", - "Kelvins-per-hour", - "Kelvins-per-minute", - "Joule-seconds", - "Square-meters-per-Newton", - "Kilogram-per-cubic-meter", - "Newton-seconds", - "Newtons-per-meter", - "Watts-per-meter-per-degree-Kelvin" - ] -} diff --git a/validator/.idea/codeStyles/codeStyleConfig.xml b/validator/.idea/codeStyles/codeStyleConfig.xml deleted file mode 100644 index b9d18bf599..0000000000 --- a/validator/.idea/codeStyles/codeStyleConfig.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/validator/.idea/encodings.xml b/validator/.idea/encodings.xml deleted file mode 100644 index 15a15b218a..0000000000 --- a/validator/.idea/encodings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/validator/.idea/gradle.xml b/validator/.idea/gradle.xml deleted file mode 100644 index 854749173b..0000000000 --- a/validator/.idea/gradle.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/validator/.idea/inspectionProfiles/Project_Default.xml b/validator/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index d7a7dfacf9..0000000000 --- a/validator/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - \ No newline at end of file diff --git a/validator/.idea/jarRepositories.xml b/validator/.idea/jarRepositories.xml deleted file mode 100644 index f5a0c5d630..0000000000 --- a/validator/.idea/jarRepositories.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_damnhandy_handy_uri_templates_2_1_6.xml b/validator/.idea/libraries/Gradle__com_damnhandy_handy_uri_templates_2_1_6.xml deleted file mode 100644 index 06fc55732d..0000000000 --- a/validator/.idea/libraries/Gradle__com_damnhandy_handy_uri_templates_2_1_6.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_annotations_2_11_0.xml b/validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_annotations_2_11_0.xml deleted file mode 100644 index fef9a9403a..0000000000 --- a/validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_annotations_2_11_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_core_2_11_0.xml b/validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_core_2_11_0.xml deleted file mode 100644 index 93709bc78c..0000000000 --- a/validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_core_2_11_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_databind_2_11_0.xml b/validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_databind_2_11_0.xml deleted file mode 100644 index 326959d4e0..0000000000 --- a/validator/.idea/libraries/Gradle__com_fasterxml_jackson_core_jackson_databind_2_11_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_fasterxml_jackson_dataformat_jackson_dataformat_yaml_2_11_0.xml b/validator/.idea/libraries/Gradle__com_fasterxml_jackson_dataformat_jackson_dataformat_yaml_2_11_0.xml deleted file mode 100644 index 8b4a7f585e..0000000000 --- a/validator/.idea/libraries/Gradle__com_fasterxml_jackson_dataformat_jackson_dataformat_yaml_2_11_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_github_everit_org_json_schema_org_everit_json_schema_1_9_1.xml b/validator/.idea/libraries/Gradle__com_github_everit_org_json_schema_org_everit_json_schema_1_9_1.xml deleted file mode 100644 index b593493a54..0000000000 --- a/validator/.idea/libraries/Gradle__com_github_everit_org_json_schema_org_everit_json_schema_1_9_1.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_api_api_common_1_7_0.xml b/validator/.idea/libraries/Gradle__com_google_api_api_common_1_7_0.xml deleted file mode 100644 index 375d39d770..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_api_api_common_1_7_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_api_client_google_api_client_1_27_0.xml b/validator/.idea/libraries/Gradle__com_google_api_client_google_api_client_1_27_0.xml deleted file mode 100644 index 5e8f46fd94..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_api_client_google_api_client_1_27_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_api_gax_1_42_0.xml b/validator/.idea/libraries/Gradle__com_google_api_gax_1_42_0.xml deleted file mode 100644 index 5e68c48029..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_api_gax_1_42_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_api_gax_grpc_1_42_0.xml b/validator/.idea/libraries/Gradle__com_google_api_gax_grpc_1_42_0.xml deleted file mode 100644 index f0d0844afe..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_api_gax_grpc_1_42_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_api_grpc_grpc_google_cloud_pubsub_v1_1_48_0.xml b/validator/.idea/libraries/Gradle__com_google_api_grpc_grpc_google_cloud_pubsub_v1_1_48_0.xml deleted file mode 100644 index 6827686b9c..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_api_grpc_grpc_google_cloud_pubsub_v1_1_48_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_api_grpc_proto_google_cloud_firestore_v1_0_49_0.xml b/validator/.idea/libraries/Gradle__com_google_api_grpc_proto_google_cloud_firestore_v1_0_49_0.xml deleted file mode 100644 index 4a56a72303..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_api_grpc_proto_google_cloud_firestore_v1_0_49_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_api_grpc_proto_google_cloud_firestore_v1beta1_0_49_0.xml b/validator/.idea/libraries/Gradle__com_google_api_grpc_proto_google_cloud_firestore_v1beta1_0_49_0.xml deleted file mode 100644 index 3ae4446a46..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_api_grpc_proto_google_cloud_firestore_v1beta1_0_49_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_api_grpc_proto_google_cloud_logging_v2_0_49_0.xml b/validator/.idea/libraries/Gradle__com_google_api_grpc_proto_google_cloud_logging_v2_0_49_0.xml deleted file mode 100644 index daff23e355..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_api_grpc_proto_google_cloud_logging_v2_0_49_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_api_grpc_proto_google_cloud_pubsub_v1_1_48_0.xml b/validator/.idea/libraries/Gradle__com_google_api_grpc_proto_google_cloud_pubsub_v1_1_48_0.xml deleted file mode 100644 index 7ecc7143d6..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_api_grpc_proto_google_cloud_pubsub_v1_1_48_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_api_grpc_proto_google_common_protos_1_14_0.xml b/validator/.idea/libraries/Gradle__com_google_api_grpc_proto_google_common_protos_1_14_0.xml deleted file mode 100644 index 940dcdf6fb..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_api_grpc_proto_google_common_protos_1_14_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_api_grpc_proto_google_iam_v1_0_12_0.xml b/validator/.idea/libraries/Gradle__com_google_api_grpc_proto_google_iam_v1_0_12_0.xml deleted file mode 100644 index 3255c67202..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_api_grpc_proto_google_iam_v1_0_12_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_apis_google_api_services_cloudiot_v1_rev20181120_1_27_0.xml b/validator/.idea/libraries/Gradle__com_google_apis_google_api_services_cloudiot_v1_rev20181120_1_27_0.xml deleted file mode 100644 index 976f5bad3f..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_apis_google_api_services_cloudiot_v1_rev20181120_1_27_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_auth_google_auth_library_credentials_0_13_0.xml b/validator/.idea/libraries/Gradle__com_google_auth_google_auth_library_credentials_0_13_0.xml deleted file mode 100644 index 0f00e2cf53..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_auth_google_auth_library_credentials_0_13_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_auth_google_auth_library_oauth2_http_0_13_0.xml b/validator/.idea/libraries/Gradle__com_google_auth_google_auth_library_oauth2_http_0_13_0.xml deleted file mode 100644 index 5899b266d7..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_auth_google_auth_library_oauth2_http_0_13_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_cloud_google_cloud_core_1_66_0.xml b/validator/.idea/libraries/Gradle__com_google_cloud_google_cloud_core_1_66_0.xml deleted file mode 100644 index 1b348bd118..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_cloud_google_cloud_core_1_66_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_cloud_google_cloud_core_grpc_1_66_0.xml b/validator/.idea/libraries/Gradle__com_google_cloud_google_cloud_core_grpc_1_66_0.xml deleted file mode 100644 index cc313478fc..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_cloud_google_cloud_core_grpc_1_66_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_cloud_google_cloud_firestore_0_84_0_beta.xml b/validator/.idea/libraries/Gradle__com_google_cloud_google_cloud_firestore_0_84_0_beta.xml deleted file mode 100644 index 7314479e1f..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_cloud_google_cloud_firestore_0_84_0_beta.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_cloud_google_cloud_logging_1_66_0.xml b/validator/.idea/libraries/Gradle__com_google_cloud_google_cloud_logging_1_66_0.xml deleted file mode 100644 index c61dc8841a..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_cloud_google_cloud_logging_1_66_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_cloud_google_cloud_pubsub_1_66_0.xml b/validator/.idea/libraries/Gradle__com_google_cloud_google_cloud_pubsub_1_66_0.xml deleted file mode 100644 index 5a5df67856..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_cloud_google_cloud_pubsub_1_66_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_code_findbugs_jsr305_3_0_2.xml b/validator/.idea/libraries/Gradle__com_google_code_findbugs_jsr305_3_0_2.xml deleted file mode 100644 index 122552e3fe..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_code_findbugs_jsr305_3_0_2.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_code_gson_gson_2_7.xml b/validator/.idea/libraries/Gradle__com_google_code_gson_gson_2_7.xml deleted file mode 100644 index cbe1b3266b..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_code_gson_gson_2_7.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_errorprone_error_prone_annotations_2_2_0.xml b/validator/.idea/libraries/Gradle__com_google_errorprone_error_prone_annotations_2_2_0.xml deleted file mode 100644 index 9b2f90767c..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_errorprone_error_prone_annotations_2_2_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_guava_guava_26_0_android.xml b/validator/.idea/libraries/Gradle__com_google_guava_guava_26_0_android.xml deleted file mode 100644 index 85d219b6b1..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_guava_guava_26_0_android.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_http_client_google_http_client_1_28_0.xml b/validator/.idea/libraries/Gradle__com_google_http_client_google_http_client_1_28_0.xml deleted file mode 100644 index c5f9810e75..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_http_client_google_http_client_1_28_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_http_client_google_http_client_jackson2_1_28_0.xml b/validator/.idea/libraries/Gradle__com_google_http_client_google_http_client_jackson2_1_28_0.xml deleted file mode 100644 index 553c5c252c..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_http_client_google_http_client_jackson2_1_28_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_j2objc_j2objc_annotations_1_1.xml b/validator/.idea/libraries/Gradle__com_google_j2objc_j2objc_annotations_1_1.xml deleted file mode 100644 index ab45264c2d..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_j2objc_j2objc_annotations_1_1.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_oauth_client_google_oauth_client_1_27_0.xml b/validator/.idea/libraries/Gradle__com_google_oauth_client_google_oauth_client_1_27_0.xml deleted file mode 100644 index 6aa514b846..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_oauth_client_google_oauth_client_1_27_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_protobuf_protobuf_java_3_6_1.xml b/validator/.idea/libraries/Gradle__com_google_protobuf_protobuf_java_3_6_1.xml deleted file mode 100644 index ba08aca4c9..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_protobuf_protobuf_java_3_6_1.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_protobuf_protobuf_java_util_3_6_1.xml b/validator/.idea/libraries/Gradle__com_google_protobuf_protobuf_java_util_3_6_1.xml deleted file mode 100644 index b13413867f..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_protobuf_protobuf_java_util_3_6_1.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__com_google_re2j_re2j_1_1.xml b/validator/.idea/libraries/Gradle__com_google_re2j_re2j_1_1.xml deleted file mode 100644 index c30869dedd..0000000000 --- a/validator/.idea/libraries/Gradle__com_google_re2j_re2j_1_1.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__commons_beanutils_commons_beanutils_1_9_2.xml b/validator/.idea/libraries/Gradle__commons_beanutils_commons_beanutils_1_9_2.xml deleted file mode 100644 index f564ac0fad..0000000000 --- a/validator/.idea/libraries/Gradle__commons_beanutils_commons_beanutils_1_9_2.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__commons_collections_commons_collections_3_2_2.xml b/validator/.idea/libraries/Gradle__commons_collections_commons_collections_3_2_2.xml deleted file mode 100644 index 03b4c932e9..0000000000 --- a/validator/.idea/libraries/Gradle__commons_collections_commons_collections_3_2_2.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__commons_digester_commons_digester_1_8_1.xml b/validator/.idea/libraries/Gradle__commons_digester_commons_digester_1_8_1.xml deleted file mode 100644 index 0482c8e86a..0000000000 --- a/validator/.idea/libraries/Gradle__commons_digester_commons_digester_1_8_1.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__commons_io_commons_io_2_5.xml b/validator/.idea/libraries/Gradle__commons_io_commons_io_2_5.xml deleted file mode 100644 index 12ab8e6678..0000000000 --- a/validator/.idea/libraries/Gradle__commons_io_commons_io_2_5.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__commons_logging_commons_logging_1_2.xml b/validator/.idea/libraries/Gradle__commons_logging_commons_logging_1_2.xml deleted file mode 100644 index d26e0617f1..0000000000 --- a/validator/.idea/libraries/Gradle__commons_logging_commons_logging_1_2.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__commons_validator_commons_validator_1_6.xml b/validator/.idea/libraries/Gradle__commons_validator_commons_validator_1_6.xml deleted file mode 100644 index 06fde17888..0000000000 --- a/validator/.idea/libraries/Gradle__commons_validator_commons_validator_1_6.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__io_grpc_grpc_alts_1_18_0.xml b/validator/.idea/libraries/Gradle__io_grpc_grpc_alts_1_18_0.xml deleted file mode 100644 index 845906af4d..0000000000 --- a/validator/.idea/libraries/Gradle__io_grpc_grpc_alts_1_18_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__io_grpc_grpc_auth_1_18_0.xml b/validator/.idea/libraries/Gradle__io_grpc_grpc_auth_1_18_0.xml deleted file mode 100644 index f4059f435c..0000000000 --- a/validator/.idea/libraries/Gradle__io_grpc_grpc_auth_1_18_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__io_grpc_grpc_context_1_18_0.xml b/validator/.idea/libraries/Gradle__io_grpc_grpc_context_1_18_0.xml deleted file mode 100644 index ffde830105..0000000000 --- a/validator/.idea/libraries/Gradle__io_grpc_grpc_context_1_18_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__io_grpc_grpc_core_1_18_0.xml b/validator/.idea/libraries/Gradle__io_grpc_grpc_core_1_18_0.xml deleted file mode 100644 index 443667d791..0000000000 --- a/validator/.idea/libraries/Gradle__io_grpc_grpc_core_1_18_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__io_grpc_grpc_grpclb_1_18_0.xml b/validator/.idea/libraries/Gradle__io_grpc_grpc_grpclb_1_18_0.xml deleted file mode 100644 index 1d97b75a72..0000000000 --- a/validator/.idea/libraries/Gradle__io_grpc_grpc_grpclb_1_18_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__io_grpc_grpc_netty_shaded_1_18_0.xml b/validator/.idea/libraries/Gradle__io_grpc_grpc_netty_shaded_1_18_0.xml deleted file mode 100644 index b6d9ed29f8..0000000000 --- a/validator/.idea/libraries/Gradle__io_grpc_grpc_netty_shaded_1_18_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__io_grpc_grpc_protobuf_1_18_0.xml b/validator/.idea/libraries/Gradle__io_grpc_grpc_protobuf_1_18_0.xml deleted file mode 100644 index 43a745faad..0000000000 --- a/validator/.idea/libraries/Gradle__io_grpc_grpc_protobuf_1_18_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__io_grpc_grpc_protobuf_lite_1_18_0.xml b/validator/.idea/libraries/Gradle__io_grpc_grpc_protobuf_lite_1_18_0.xml deleted file mode 100644 index f140dac0ed..0000000000 --- a/validator/.idea/libraries/Gradle__io_grpc_grpc_protobuf_lite_1_18_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__io_grpc_grpc_stub_1_18_0.xml b/validator/.idea/libraries/Gradle__io_grpc_grpc_stub_1_18_0.xml deleted file mode 100644 index 658340cd48..0000000000 --- a/validator/.idea/libraries/Gradle__io_grpc_grpc_stub_1_18_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__io_opencensus_opencensus_api_0_18_0.xml b/validator/.idea/libraries/Gradle__io_opencensus_opencensus_api_0_18_0.xml deleted file mode 100644 index 5e6f89071d..0000000000 --- a/validator/.idea/libraries/Gradle__io_opencensus_opencensus_api_0_18_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__io_opencensus_opencensus_contrib_grpc_metrics_0_18_0.xml b/validator/.idea/libraries/Gradle__io_opencensus_opencensus_contrib_grpc_metrics_0_18_0.xml deleted file mode 100644 index 2090ef845c..0000000000 --- a/validator/.idea/libraries/Gradle__io_opencensus_opencensus_contrib_grpc_metrics_0_18_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__io_opencensus_opencensus_contrib_grpc_util_0_18_0.xml b/validator/.idea/libraries/Gradle__io_opencensus_opencensus_contrib_grpc_util_0_18_0.xml deleted file mode 100644 index 069dfadd6f..0000000000 --- a/validator/.idea/libraries/Gradle__io_opencensus_opencensus_contrib_grpc_util_0_18_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__io_opencensus_opencensus_contrib_http_util_0_18_0.xml b/validator/.idea/libraries/Gradle__io_opencensus_opencensus_contrib_http_util_0_18_0.xml deleted file mode 100644 index 22d05e51e8..0000000000 --- a/validator/.idea/libraries/Gradle__io_opencensus_opencensus_contrib_http_util_0_18_0.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__javax_annotation_javax_annotation_api_1_3_2.xml b/validator/.idea/libraries/Gradle__javax_annotation_javax_annotation_api_1_3_2.xml deleted file mode 100644 index c9125edcd6..0000000000 --- a/validator/.idea/libraries/Gradle__javax_annotation_javax_annotation_api_1_3_2.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__joda_time_joda_time_2_9_4.xml b/validator/.idea/libraries/Gradle__joda_time_joda_time_2_9_4.xml deleted file mode 100644 index 1bab911479..0000000000 --- a/validator/.idea/libraries/Gradle__joda_time_joda_time_2_9_4.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__junit_junit_4_13.xml b/validator/.idea/libraries/Gradle__junit_junit_4_13.xml deleted file mode 100644 index 0cef6bc81e..0000000000 --- a/validator/.idea/libraries/Gradle__junit_junit_4_13.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__org_apache_commons_commons_lang3_3_5.xml b/validator/.idea/libraries/Gradle__org_apache_commons_commons_lang3_3_5.xml deleted file mode 100644 index fed9b5690b..0000000000 --- a/validator/.idea/libraries/Gradle__org_apache_commons_commons_lang3_3_5.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__org_checkerframework_checker_compat_qual_2_5_2.xml b/validator/.idea/libraries/Gradle__org_checkerframework_checker_compat_qual_2_5_2.xml deleted file mode 100644 index b87180fb05..0000000000 --- a/validator/.idea/libraries/Gradle__org_checkerframework_checker_compat_qual_2_5_2.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__org_codehaus_mojo_animal_sniffer_annotations_1_17.xml b/validator/.idea/libraries/Gradle__org_codehaus_mojo_animal_sniffer_annotations_1_17.xml deleted file mode 100644 index cbfbdf1d12..0000000000 --- a/validator/.idea/libraries/Gradle__org_codehaus_mojo_animal_sniffer_annotations_1_17.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__org_hamcrest_hamcrest_core_1_3.xml b/validator/.idea/libraries/Gradle__org_hamcrest_hamcrest_core_1_3.xml deleted file mode 100644 index 8262f729c2..0000000000 --- a/validator/.idea/libraries/Gradle__org_hamcrest_hamcrest_core_1_3.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__org_json_json_20180130.xml b/validator/.idea/libraries/Gradle__org_json_json_20180130.xml deleted file mode 100644 index 83318a7eed..0000000000 --- a/validator/.idea/libraries/Gradle__org_json_json_20180130.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__org_threeten_threetenbp_1_3_3.xml b/validator/.idea/libraries/Gradle__org_threeten_threetenbp_1_3_3.xml deleted file mode 100644 index 0fcafe29d0..0000000000 --- a/validator/.idea/libraries/Gradle__org_threeten_threetenbp_1_3_3.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/Gradle__org_yaml_snakeyaml_1_26.xml b/validator/.idea/libraries/Gradle__org_yaml_snakeyaml_1_26.xml deleted file mode 100644 index 734cd9dad1..0000000000 --- a/validator/.idea/libraries/Gradle__org_yaml_snakeyaml_1_26.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/libraries/com_fasterxml_jackson_core_jackson_databind_2_10_2.xml b/validator/.idea/libraries/com_fasterxml_jackson_core_jackson_databind_2_10_2.xml deleted file mode 100644 index 0eaf3101e7..0000000000 --- a/validator/.idea/libraries/com_fasterxml_jackson_core_jackson_databind_2_10_2.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/misc.xml b/validator/.idea/misc.xml deleted file mode 100644 index 50b0ab60d9..0000000000 --- a/validator/.idea/misc.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/validator/.idea/modules.xml b/validator/.idea/modules.xml deleted file mode 100644 index 2b55d713a9..0000000000 --- a/validator/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/modules/daq-validator.validator.iml b/validator/.idea/modules/daq-validator.validator.iml deleted file mode 100644 index f12ef8c574..0000000000 --- a/validator/.idea/modules/daq-validator.validator.iml +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/uiDesigner.xml b/validator/.idea/uiDesigner.xml deleted file mode 100644 index e96534fb27..0000000000 --- a/validator/.idea/uiDesigner.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/validator.iml b/validator/.idea/validator.iml deleted file mode 100644 index d6ebd48059..0000000000 --- a/validator/.idea/validator.iml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/validator/.idea/vcs.xml b/validator/.idea/vcs.xml deleted file mode 100644 index 63ec3e9c8b..0000000000 --- a/validator/.idea/vcs.xml +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/validator/bin/build b/validator/bin/build deleted file mode 100755 index 603b77548b..0000000000 --- a/validator/bin/build +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash -e - -ROOT=$(dirname $0)/.. - -cd $ROOT -rm -rf build -./gradlew shadow - -ls -l build/libs/validator-1.0-SNAPSHOT-all.jar - -echo Done with validator build. diff --git a/validator/bin/config b/validator/bin/config deleted file mode 100755 index a340ba9d87..0000000000 --- a/validator/bin/config +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash -e - -ROOT=$(dirname $0)/../.. -cd $ROOT - -CONFIG=local/pubber.json - -DEVICE=$1 -DATA=$2 -PROJECT=`jq -r .projectId $CONFIG` -REGION=`jq -r .cloudRegion $CONFIG` -REGISTRY=`jq -r .registryId $CONFIG` -TOPIC=target -SUBFOLDER=config - -if [ ! -f "$DATA" ]; then - echo Missing device or config file $DATA - echo Usage: $0 [device] [config_message] - false -fi - -echo Configuring $PROJECT:$REGION:$REGISTRY:$DEVICE from $DATA - -ATTRIBUTES="subFolder=$SUBFOLDER,deviceId=$DEVICE,deviceRegistryId=$REGISTRY" -ATTRIBUTES+=",deviceNumId=$RANDOM,projectId=$PROJECT" - -gcloud pubsub topics publish $TOPIC --project=$PROJECT \ - --attribute=$ATTRIBUTES \ - --message "$(< $DATA)" - -gcloud iot devices configs update \ - --project=$PROJECT \ - --region=$REGION \ - --registry=$REGISTRY \ - --device=$DEVICE \ - --config-file=$DATA diff --git a/validator/bin/keygen b/validator/bin/keygen deleted file mode 100755 index a544c87578..0000000000 --- a/validator/bin/keygen +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash -e - -if [ "$#" != 2 ]; then - echo $0 [type] [out_dir] - false -fi - -type=$1 -cd $2 - -if [ $type == RS256 ]; then - openssl genrsa -out rsa_private.pem 2048 - openssl rsa -in rsa_private.pem -pubout -out rsa_public.pem -elif [ $type == RS256_X509 ]; then - openssl req -x509 -nodes -newkey rsa:2048 -keyout rsa_private.pem -days 1000000 -out rsa_cert.pem -subj "/CN=unused" -else - echo Unknown key type $type. Try one of { RS256, RS256_X509 } - false -fi - -openssl pkcs8 -topk8 -inform PEM -outform DER -in rsa_private.pem -nocrypt > rsa_private.pkcs8 diff --git a/validator/bin/registrar b/validator/bin/registrar deleted file mode 100755 index 49dc18d1e3..0000000000 --- a/validator/bin/registrar +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash -e - -ROOT=$(dirname $0)/../.. -cd $ROOT - -jarfile=validator/build/libs/validator-1.0-SNAPSHOT-all.jar -mainclass=com.google.daq.mqtt.registrar.Registrar - -if [ -z "$1" -o -z "$2" ]; then - echo Usage: $0 [project_id] [devices_dir] [schema_dir] '(device_filter)' - false -fi - -project_id=$1 -devices_dir=$2 -schema_dir=$3 -device_filter=$4 - -echo Using gcloud auth: -gcloud config get-value account || true - -echo Using cloud project $project_id -echo Using site config dir $devices_dir -echo Using schema root dir $schema_dir -echo Using device filter $device_filter - -JAVA=/usr/lib/jvm/java-11-openjdk-amd64/bin/java - -error=0 -echo java args $project_id $devices_dir $schema_dir $device_filter -$JAVA -cp $jarfile $mainclass $project_id $devices_dir $schema_dir $device_filter || error=$? - -echo Registrar complete, exit $error -exit $error diff --git a/validator/bin/test_schema b/validator/bin/test_schema deleted file mode 100755 index f3adbf1657..0000000000 --- a/validator/bin/test_schema +++ /dev/null @@ -1,81 +0,0 @@ -#!/bin/bash -e - -ROOT=$(dirname $0)/.. -cd $ROOT - -schema_root=../schemas - -errorfile=`mktemp` -rm -f $errorfile - -build=y -force=n -ignoreset=. - -while getopts ":fn" opt; do - case $opt in - f) force=y - ;; - n) build=n - ;; - \?) echo "Usage: $0 [-f] [-n]" - exit -1 - ;; - esac -done - -outroot=out -rm -rf $outroot - -if [ "$build" == y ]; then - bin/build -fi - -jarfile=$(realpath build/libs/validator-1.0-SNAPSHOT-all.jar) - -schemas=$(cd $schema_root && ls) -if [ -z "$schemas" ]; then - echo No schemas found. - false -fi -for schema in $schemas; do - rootdir=$schema_root/$schema - subsets=$(cd $rootdir; ls -d *.tests) - for subset in $subsets; do - if [ -z "$subset" ]; then - echo Schema $schema has no .tests dirs. - false - fi - schemaname=${subset%.tests}.json - testfiles=$(cd $rootdir/$subset; ls *.json) - for testfile in $testfiles; do - outfile=${testfile%.json}.out - testdir=$rootdir/$subset - testpath=$testdir/$testfile - expected=$testdir/$outfile - outdir=$outroot/${testdir#${schema_root}/} - mkdir -p $outdir - output=$outdir/$outfile - - error=0 - reltest=${testpath#$rootdir/} - (cd $rootdir; java -jar $jarfile $schemaname $reltest $ignoreset --) 2> $output || error=$? - if [ $force == y ]; then - diff $expected $output || echo Updating $expected && cp $output $expected - else - diff -b $expected $output || (echo ' ' cp $output $expected | tee -a $errorfile) - fi - done - done -done - -echo - -if [ -f $errorfile ]; then - echo Validation errors found in $(pwd): - cat $errorfile - false -fi - -echo Done with validation. - diff --git a/validator/bin/validate b/validator/bin/validate deleted file mode 100755 index e79c158756..0000000000 --- a/validator/bin/validate +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash -e - -ROOT=$(dirname $0)/../.. -cd $ROOT - -jarfile=validator/build/libs/validator-1.0-SNAPSHOT-all.jar - -if [ "$#" -lt 2 ]; then - echo Usage: $0 [schema] [target] [devset] [sitepath] - false -fi - -schema=$1 -target=$2 -devset=${3:-$USER} -sitepath=$4 - -if [ ! -f $jarfile ]; then - echo Building validator... - validator/bin/build -fi - -echo Using gcloud auth: -gcloud config get-value account || true - -echo Executing validator $schema $target... - -echo Validating against schema $schemafile into validations/ -rm -rf validations - -echo java -jar $jarfile $schema $target $devset $sitepath - -error=0 -java -jar $jarfile $schema $target $devset $sitepath || error=$? - -echo Validation complete, exit $error -exit $error diff --git a/validator/build.gradle b/validator/build.gradle deleted file mode 100644 index 1248f8d10d..0000000000 --- a/validator/build.gradle +++ /dev/null @@ -1,51 +0,0 @@ -buildscript { - repositories { - maven { - url "https://plugins.gradle.org/m2/" - } - } - dependencies { - classpath "com.github.jengelman.gradle.plugins:shadow:5.2.0" - } -} - -plugins { - id 'com.github.johnrengelman.shadow' version '5.2.0' - id 'java' - id 'maven' -} - -group 'daq-validator' -version '1.0-SNAPSHOT' - -sourceCompatibility = 1.8 - -jar { - manifest { - attributes 'Main-Class': 'com.google.daq.mqtt.validator.Validator' - } -} - -repositories { - mavenCentral() - maven { - url "https://jitpack.io" - } -} - -dependencies { - compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.11.0' - compile group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: '2.11.0' - compile group: 'com.github.everit-org.json-schema', name: 'org.everit.json.schema', version: '1.9.1' - - compile 'com.google.guava:guava:22.0' - compile 'com.google.cloud:google-cloud-logging:1.66.0' - compile ('com.google.apis:google-api-services-cloudiot:v1-rev20181120-1.27.0') { - exclude group: 'com.google.guava', module: 'guava-jdk5' - } - compile 'commons-io:commons-io:2.5' - - compile 'com.google.cloud:google-cloud-pubsub:1.66.0' - compile 'com.google.cloud:google-cloud-firestore:0.84.0-beta' - testCompile group: 'junit', name: 'junit', version: '4.13' -} diff --git a/validator/gradle/wrapper/gradle-wrapper.jar b/validator/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 01b8bf6b1f99cad9213fc495b33ad5bbab8efd20..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54329 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

      <5G2M1WZP5 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 \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - -exec "$JAVACMD" "$@" diff --git a/validator/gradlew.bat b/validator/gradlew.bat deleted file mode 100644 index e95643d6a2..0000000000 --- a/validator/gradlew.bat +++ /dev/null @@ -1,84 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/validator/settings.gradle b/validator/settings.gradle deleted file mode 100644 index 9ad209fbe9..0000000000 --- a/validator/settings.gradle +++ /dev/null @@ -1,2 +0,0 @@ -rootProject.name = 'validator' - diff --git a/validator/src/main/java/com/google/daq/mqtt/registrar/LocalDevice.java b/validator/src/main/java/com/google/daq/mqtt/registrar/LocalDevice.java deleted file mode 100644 index e32dc8b2b0..0000000000 --- a/validator/src/main/java/com/google/daq/mqtt/registrar/LocalDevice.java +++ /dev/null @@ -1,415 +0,0 @@ -package com.google.daq.mqtt.registrar; - -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.JsonParser.Feature; -import com.fasterxml.jackson.core.PrettyPrinter; -import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.util.ISO8601DateFormat; -import com.google.api.services.cloudiot.v1.model.DeviceCredential; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Sets; -import com.google.common.collect.Sets.SetView; -import com.google.daq.mqtt.util.CloudDeviceSettings; -import com.google.daq.mqtt.util.CloudIotManager; -import com.google.daq.mqtt.util.ExceptionMap; -import org.apache.commons.io.IOUtils; -import org.everit.json.schema.Schema; -import org.json.JSONObject; -import org.json.JSONTokener; - -import java.io.*; -import java.nio.charset.Charset; -import java.util.*; - -import static com.google.daq.mqtt.registrar.Registrar.*; - -class LocalDevice { - - private static final PrettyPrinter PROPER_PRETTY_PRINTER_POLICY = new ProperPrettyPrinterPolicy(); - - private static final ObjectMapper OBJECT_MAPPER_RAW = new ObjectMapper() - .enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS) - .enable(Feature.ALLOW_TRAILING_COMMA) - .enable(Feature.STRICT_DUPLICATE_DETECTION) - .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) - .setDateFormat(new ISO8601DateFormat()) - .setSerializationInclusion(Include.NON_NULL); - - private static final ObjectMapper OBJECT_MAPPER = OBJECT_MAPPER_RAW.copy() - .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) - .enable(SerializationFeature.INDENT_OUTPUT); - - private static final String RSA_CERT_TYPE = "RS256_X509"; - private static final String RSA_KEY_FILE = "RSA_PEM"; - private static final String RSA_CERT_FILE = "RSA_X509_PEM"; - private static final String RSA_PUBLIC_PEM = "rsa_public.pem"; - private static final String RSA_CERT_PEM = "rsa_cert.pem"; - private static final String RSA_PRIVATE_PEM = "rsa_private.pem"; - private static final String RSA_PRIVATE_PKCS8 = "rsa_private.pkcs8"; - - private static final Set DEVICE_FILES = ImmutableSet.of(METADATA_JSON); - private static final Set KEY_FILES = ImmutableSet.of(RSA_PUBLIC_PEM, RSA_PRIVATE_PEM, RSA_PRIVATE_PKCS8); - private static final Set OPTIONAL_FILES = ImmutableSet.of( - GENERATED_CONFIG_JSON, DEVICE_ERRORS_JSON, NORMALIZED_JSON); - - private static final String KEYGEN_EXEC_FORMAT = "validator/bin/keygen %s %s"; - public static final String METADATA_SUBFOLDER = "metadata"; - private static final String ERROR_FORMAT_INDENT = " "; - private static final int MAX_METADATA_LENGTH = 32767; - public static final String INVALID_METADATA_HASH = "INVALID"; - - private final String deviceId; - private final Map schemas; - private final File deviceDir; - private final UdmiSchema.Metadata metadata; - private final ExceptionMap exceptionMap; - - private String deviceNumId; - - private CloudDeviceSettings settings; - private DeviceCredential deviceCredential; - - LocalDevice(File devicesDir, String deviceId, Map schemas) { - try { - this.deviceId = deviceId; - this.schemas = schemas; - exceptionMap = new ExceptionMap("Exceptions for " + deviceId); - deviceDir = new File(devicesDir, deviceId); - metadata = readMetadata(); - } catch (Exception e) { - throw new RuntimeException("While loading local device " + deviceId, e); - } - } - - static boolean deviceExists(File devicesDir, String deviceName) { - return new File(new File(devicesDir, deviceName), METADATA_JSON).isFile(); - } - - public void validatedDeviceDir() { - try { - String[] files = deviceDir.list(); - Preconditions.checkNotNull(files, "No files found in " + deviceDir.getAbsolutePath()); - Set actualFiles = ImmutableSet.copyOf(files); - Set expectedFiles = Sets.union(DEVICE_FILES, keyFiles()); - SetView missing = Sets.difference(expectedFiles, actualFiles); - if (!missing.isEmpty()) { - throw new RuntimeException("Missing files: " + missing); - } - SetView extra = Sets.difference(Sets.difference(actualFiles, expectedFiles), OPTIONAL_FILES); - if (!extra.isEmpty()) { - throw new RuntimeException("Extra files: " + extra); - } - } catch (Exception e) { - throw new RuntimeException("While validating device directory " + deviceId, e); - } - } - - private UdmiSchema.Metadata readMetadata() { - File metadataFile = new File(deviceDir, METADATA_JSON); - try (InputStream targetStream = new FileInputStream(metadataFile)) { - schemas.get(METADATA_JSON).validate(new JSONObject(new JSONTokener(targetStream))); - } catch (Exception metadata_exception) { - exceptionMap.put("Validating", metadata_exception); - } - try { - return OBJECT_MAPPER.readValue(metadataFile, UdmiSchema.Metadata.class); - } catch (Exception mapping_exception) { - exceptionMap.put("Reading", mapping_exception); - } - return null; - } - - private UdmiSchema.Metadata readNormalized() { - try { - File metadataFile = new File(deviceDir, NORMALIZED_JSON); - return OBJECT_MAPPER.readValue(metadataFile, UdmiSchema.Metadata.class); - } catch (Exception mapping_exception) { - return new UdmiSchema.Metadata(); - } - } - - private String metadataHash() { - if (metadata == null) { - return INVALID_METADATA_HASH; - } - String savedHash = metadata.hash; - Date savedTimestamp = metadata.timestamp; - try { - metadata.hash = null; - metadata.timestamp = null; - String json = metadataString(); - return String.format("%08x", Objects.hash(json)); - } catch (Exception e) { - throw new RuntimeException("Converting object to string", e); - } finally { - metadata.hash = savedHash; - metadata.timestamp = savedTimestamp; - } - } - - private String getAuthType() { - return metadata.cloud == null ? null : metadata.cloud.auth_type; - } - - private String getAuthFileType() { - return RSA_CERT_TYPE.equals(getAuthType()) ? RSA_CERT_FILE : RSA_KEY_FILE; - } - - public DeviceCredential loadCredential() { - deviceCredential = readCredential(); - return deviceCredential; - } - - public DeviceCredential readCredential() { - try { - if (hasGateway() && getAuthType() != null) { - throw new RuntimeException("Proxied devices should not have cloud.auth_type defined"); - } - if (!isDirectConnect()) { - return null; - } - if (getAuthType() == null) { - throw new RuntimeException("Credential cloud.auth_type definition missing"); - } - File deviceKeyFile = new File(deviceDir, publicKeyFile()); - if (!deviceKeyFile.exists()) { - generateNewKey(); - } - return CloudIotManager.makeCredentials(getAuthFileType(), - IOUtils.toString(new FileInputStream(deviceKeyFile), Charset.defaultCharset())); - } catch (Exception e) { - throw new RuntimeException("While loading credential for local device " + deviceId, e); - } - } - - private Set keyFiles() { - if (!isDirectConnect()) { - return ImmutableSet.of(); - } - return Sets.union(Sets.union(DEVICE_FILES, KEY_FILES), Set.of(publicKeyFile())); - } - - private String publicKeyFile() { - return RSA_CERT_TYPE.equals(getAuthType()) ? RSA_CERT_PEM : RSA_PUBLIC_PEM; - } - - private void generateNewKey() { - String absolutePath = deviceDir.getAbsolutePath(); - try { - String command = String.format(KEYGEN_EXEC_FORMAT, getAuthType(), absolutePath); - System.err.println(command); - int exitCode = Runtime.getRuntime().exec(command).waitFor(); - if (exitCode != 0) { - throw new RuntimeException("Keygen exit code " + exitCode); - } - } catch (Exception e) { - throw new RuntimeException("While generating new credential for " + deviceId, e); - } - } - - boolean isGateway() { - return metadata != null && metadata.gateway != null && - metadata.gateway.proxy_ids != null; - } - - boolean hasGateway() { - return metadata != null && metadata.gateway != null && - metadata.gateway.gateway_id != null; - } - - boolean isDirectConnect() { - return isGateway() || !hasGateway(); - } - - CloudDeviceSettings getSettings() { - try { - if (settings != null) { - return settings; - } - settings = new CloudDeviceSettings(); - if (metadata == null) { - return settings; - } - settings.credential = deviceCredential; - settings.metadata = metadataString(); - settings.config = deviceConfigString(); - settings.proxyDevices = getProxyDevicesList(); - return settings; - } catch (Exception e) { - throw new RuntimeException("While getting settings for device " + deviceId, e); - } - } - - private List getProxyDevicesList() { - return isGateway() ? metadata.gateway.proxy_ids : null; - } - - private String deviceConfigString() { - try { - UdmiSchema.Config config = new UdmiSchema.Config(); - config.timestamp = metadata.timestamp; - if (isGateway()) { - config.gateway = new UdmiSchema.GatewayConfig(); - config.gateway.proxy_ids = getProxyDevicesList(); - } - if (metadata.pointset != null) { - config.pointset = getDevicePointsetConfig(); - } - if (metadata.localnet != null) { - config.localnet = getDeviceLocalnetConfig(); - } - return OBJECT_MAPPER.writeValueAsString(config); - } catch (Exception e) { - throw new RuntimeException("While converting device config to string", e); - } - } - - private UdmiSchema.LocalnetConfig getDeviceLocalnetConfig() { - UdmiSchema.LocalnetConfig localnetConfig = new UdmiSchema.LocalnetConfig(); - localnetConfig.subsystems = metadata.localnet.subsystem; - return localnetConfig; - } - - private UdmiSchema.PointsetConfig getDevicePointsetConfig() { - UdmiSchema.PointsetConfig pointsetConfig = new UdmiSchema.PointsetConfig(); - metadata.pointset.points.forEach((metadataKey, value) -> - pointsetConfig.points.computeIfAbsent(metadataKey, configKey -> - UdmiSchema.PointConfig.fromRef(value.ref))); - return pointsetConfig; - } - - private String metadataString() { - try { - String prettyString = OBJECT_MAPPER.writeValueAsString(metadata); - if (prettyString.length() <= MAX_METADATA_LENGTH) { - return prettyString; - } - return OBJECT_MAPPER_RAW.writeValueAsString(metadata); - } catch (Exception e) { - throw new RuntimeException("While converting metadata to string", e); - } - } - - public void validateEnvelope(String registryId, String siteName) { - checkConsistency(siteName); - try { - UdmiSchema.Envelope envelope = new UdmiSchema.Envelope(); - envelope.deviceId = deviceId; - envelope.deviceRegistryId = registryId; - // Don't use actual project id because it should be abstracted away. - envelope.projectId = fakeProjectId(); - envelope.deviceNumId = makeNumId(envelope); - String envelopeJson = OBJECT_MAPPER.writeValueAsString(envelope); - schemas.get(ENVELOPE_JSON).validate(new JSONObject(new JSONTokener(envelopeJson))); - } catch (Exception e) { - throw new IllegalStateException("Validating envelope " + deviceId, e); - } - } - - private String fakeProjectId() { - return metadata.system.location.site.toLowerCase(); - } - - private void checkConsistency(String expectedSite) { - String assetName = metadata.system.physical_tag.asset.name; - Preconditions.checkState(deviceId.equals(assetName), - String.format("system.physical_tag.asset.name %s does not match expected %s", assetName, deviceId)); - - String assetSite = metadata.system.physical_tag.asset.site; - Preconditions.checkState(expectedSite.equals(assetSite), - String.format("system.physical_tag.asset.site %s does not match expected %s", assetSite, expectedSite)); - - String siteName = metadata.system.location.site; - Preconditions.checkState(expectedSite.equals(siteName), - String.format("system.location.site %s does not match expected %s", siteName, expectedSite)); - } - - private String makeNumId(UdmiSchema.Envelope envelope) { - int hash = Objects.hash(deviceId, envelope.deviceRegistryId, envelope.projectId); - return Integer.toString(hash < 0 ? -hash : hash); - } - - public void writeErrors() { - File errorsFile = new File(deviceDir, DEVICE_ERRORS_JSON); - if (exceptionMap.isEmpty()) { - System.err.println("Removing " + errorsFile); - errorsFile.delete(); - return; - } - System.err.println("Updating " + errorsFile); - try (PrintStream printStream = new PrintStream(new FileOutputStream(errorsFile))) { - ExceptionMap.ErrorTree errorTree = ExceptionMap.format(exceptionMap, ERROR_FORMAT_INDENT); - errorTree.write(printStream); - } catch (Exception e) { - throw new RuntimeException("While writing "+ errorsFile.getAbsolutePath(), e); - } - } - - void writeNormalized() { - File metadataFile = new File(deviceDir, NORMALIZED_JSON); - if (metadata == null) { - System.err.println("Deleting (invalid) " + metadataFile.getAbsolutePath()); - metadataFile.delete(); - return; - } - UdmiSchema.Metadata normalized = readNormalized(); - String writeHash = metadataHash(); - if (normalized.hash != null && normalized.hash.equals(writeHash)) { - return; - } - metadata.timestamp = new Date(); - metadata.hash = writeHash; - System.err.println("Writing normalized " + metadataFile.getAbsolutePath()); - try (OutputStream outputStream = new FileOutputStream(metadataFile)) { - // Super annoying, but can't set this on the global static instance. - JsonGenerator generator = OBJECT_MAPPER.getFactory() - .createGenerator(outputStream) - .setPrettyPrinter(PROPER_PRETTY_PRINTER_POLICY); - OBJECT_MAPPER.writeValue(generator, metadata); - } catch (Exception e) { - exceptionMap.put("Writing", e); - } - } - - public void writeConfigFile() { - File configFile = new File(deviceDir, GENERATED_CONFIG_JSON); - try (OutputStream outputStream = new FileOutputStream(configFile)) { - outputStream.write(getSettings().config.getBytes()); - } catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException("While writing "+ configFile.getAbsolutePath(), e); - } - } - - public String getDeviceId() { - return deviceId; - } - - public String getDeviceNumId() { - return Preconditions.checkNotNull(deviceNumId, "deviceNumId not set"); - } - - public void setDeviceNumId(String numId) { - deviceNumId = numId; - } - - public ExceptionMap getErrors() { - return exceptionMap; - } - - public boolean isValid() { - return metadata != null; - } - - private static class ProperPrettyPrinterPolicy extends DefaultPrettyPrinter { - @Override - public void writeObjectFieldValueSeparator(JsonGenerator jg) throws IOException { - jg.writeRaw(": "); - } - } -} diff --git a/validator/src/main/java/com/google/daq/mqtt/registrar/Registrar.java b/validator/src/main/java/com/google/daq/mqtt/registrar/Registrar.java deleted file mode 100644 index e665d9ed16..0000000000 --- a/validator/src/main/java/com/google/daq/mqtt/registrar/Registrar.java +++ /dev/null @@ -1,344 +0,0 @@ -package com.google.daq.mqtt.registrar; - -import static java.util.stream.Collectors.toSet; - -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.databind.util.ISO8601DateFormat; -import com.google.api.services.cloudiot.v1.model.Device; -import com.google.api.services.cloudiot.v1.model.DeviceCredential; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; -import com.google.daq.mqtt.util.CloudDeviceSettings; -import com.google.daq.mqtt.util.CloudIotManager; -import com.google.daq.mqtt.util.ConfigUtil; -import com.google.daq.mqtt.util.ExceptionMap; -import com.google.daq.mqtt.util.ExceptionMap.ErrorTree; -import com.google.daq.mqtt.util.PubSubPusher; -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; -import java.math.BigInteger; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import org.everit.json.schema.Schema; -import org.everit.json.schema.loader.SchemaClient; -import org.everit.json.schema.loader.SchemaLoader; -import org.json.JSONObject; -import org.json.JSONTokener; - -public class Registrar { - - static final String METADATA_JSON = "metadata.json"; - static final String NORMALIZED_JSON = "metadata_norm.json"; - static final String DEVICE_ERRORS_JSON = "errors.json"; - static final String ENVELOPE_JSON = "envelope.json"; - static final String GENERATED_CONFIG_JSON = "generated_config.json"; - - private static final String DEVICES_DIR = "devices"; - private static final String ERROR_FORMAT_INDENT = " "; - - private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper() - .enable(SerializationFeature.INDENT_OUTPUT) - .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) - .setDateFormat(new ISO8601DateFormat()) - .setSerializationInclusion(Include.NON_NULL); - public static final String ALL_MATCH = ""; - private static final String LOCAL_ONLY_PROJECT_ID = "--"; - - private CloudIotManager cloudIotManager; - private File siteConfig; - private final Map schemas = new HashMap<>(); - private File schemaBase; - private String schemaName; - private PubSubPusher pubSubPusher; - private Map localDevices; - private File summaryFile; - private ExceptionMap blockErrors; - private String projectId; - - public static void main(String[] args) { - Registrar registrar = new Registrar(); - try { - if (args.length < 3 || args.length > 4) { - throw new IllegalArgumentException("Args: [project_id] [site_dir] [schema_file] (device_regex)"); - } - registrar.setProjectId(args[0]); - registrar.setSchemaBase(args[2]); - registrar.setSiteConfigPath(args[1]); - registrar.processDevices(args.length > 3 ? args[3] : ALL_MATCH); - registrar.writeErrors(); - registrar.shutdown(); - } catch (ExceptionMap em) { - ErrorTree errorTree = ExceptionMap.format(em, ERROR_FORMAT_INDENT); - errorTree.write(System.err); - System.exit(2); - } catch (Exception ex) { - ex.printStackTrace(); - System.exit(-1); - } - System.exit(0); - } - - private void writeErrors() throws Exception { - Map> errorSummary = new TreeMap<>(); - localDevices.values().forEach(LocalDevice::writeErrors); - localDevices.values().forEach(device -> { - device.getErrors().stream().forEach(error -> errorSummary - .computeIfAbsent(error.getKey(), cat -> new TreeMap<>()) - .put(device.getDeviceId(), error.getValue().toString())); - if (device.getErrors().isEmpty()) { - errorSummary.computeIfAbsent("Clean", cat -> new TreeMap<>()) - .put(device.getDeviceId(), "True"); - } - }); - if (blockErrors != null && !blockErrors.isEmpty()) { - errorSummary.put("Block", blockErrors.stream().collect(Collectors.toMap( - Map.Entry::getKey, entry -> entry.getValue().toString()))); - } - System.err.println("\nSummary:"); - errorSummary.forEach((key, value) -> System.err.println(" Device " + key + ": " + value.size())); - System.err.println("Out of " + localDevices.size() + " total."); - OBJECT_MAPPER.writeValue(summaryFile, errorSummary); - } - - private void setSiteConfigPath(String siteConfigPath) { - Preconditions.checkNotNull(schemaName, "schemaName not set yet"); - siteConfig = new File(siteConfigPath); - summaryFile = new File(siteConfig, "registration_summary.json"); - summaryFile.delete(); - File cloudIotConfig = new File(siteConfig, ConfigUtil.CLOUD_IOT_CONFIG_JSON); - System.err.println("Reading Cloud IoT config from " + cloudIotConfig.getAbsolutePath()); - cloudIotManager = new CloudIotManager(projectId, cloudIotConfig, schemaName); - pubSubPusher = new PubSubPusher(projectId, cloudIotConfig); - System.err.println(String.format("Working with project %s registry %s/%s", - cloudIotManager.getProjectId(), cloudIotManager.getCloudRegion(), cloudIotManager.getRegistryId())); - } - - private void processDevices(String deviceRegex) { - try { - Pattern devicePattern = Pattern.compile(deviceRegex); - localDevices = loadLocalDevices(devicePattern); - List cloudDevices = fetchDeviceList(devicePattern); - Set extraDevices = cloudDevices.stream().map(Device::getId).collect(toSet()); - for (String localName : localDevices.keySet()) { - LocalDevice localDevice = localDevices.get(localName); - if (!localDevice.isValid()) { - System.err.println("Skipping (invalid) " + localName); - continue; - } - extraDevices.remove(localName); - try { - localDevice.writeConfigFile(); - if (!localOnly()) { - updateCloudIoT(localDevice); - Device device = Preconditions.checkNotNull(fetchDevice(localName), - "missing device " + localName); - BigInteger numId = Preconditions.checkNotNull(device.getNumId(), - "missing deviceNumId for " + localName); - localDevice.setDeviceNumId(numId.toString()); - sendMetadataMessage(localDevice); - } - } catch (Exception e) { - System.err.println("Deferring exception: " + e.toString()); - localDevice.getErrors().put("Registering", e); - } - } - if (!localOnly()) { - bindGatewayDevices(localDevices); - blockErrors = blockExtraDevices(extraDevices); - } - System.err.println(String.format("Processed %d devices", localDevices.size())); - } catch (Exception e) { - throw new RuntimeException("While processing devices", e); - } - } - - private ExceptionMap blockExtraDevices(Set extraDevices) { - ExceptionMap exceptionMap = new ExceptionMap("Block devices errors"); - for (String extraName : extraDevices) { - try { - System.err.println("Blocking extra device " + extraName); - cloudIotManager.blockDevice(extraName, true); - } catch (Exception e) { - exceptionMap.put(extraName, e); - } - } - return exceptionMap; - } - - private Device fetchDevice(String localName) { - try { - return cloudIotManager.fetchDevice(localName); - } catch (Exception e) { - throw new RuntimeException("Fetching device " + localName, e); - } - } - - private void sendMetadataMessage(LocalDevice localDevice) { - System.err.println("Sending metadata message for " + localDevice.getDeviceId()); - Map attributes = new HashMap<>(); - attributes.put("deviceId", localDevice.getDeviceId()); - attributes.put("deviceNumId", localDevice.getDeviceNumId()); - attributes.put("deviceRegistryId", cloudIotManager.getRegistryId()); - attributes.put("projectId", cloudIotManager.getProjectId()); - attributes.put("subFolder", LocalDevice.METADATA_SUBFOLDER); - pubSubPusher.sendMessage(attributes, localDevice.getSettings().metadata); - } - - private void updateCloudIoT(LocalDevice localDevice) { - String localName = localDevice.getDeviceId(); - fetchDevice(localName); - CloudDeviceSettings localDeviceSettings = localDevice.getSettings(); - if (cloudIotManager.registerDevice(localName, localDeviceSettings)) { - System.err.println("Created new device entry " + localName); - } else { - System.err.println("Updated device entry " + localName); - } - } - - private void bindGatewayDevices(Map localDevices) { - localDevices.values().stream().filter(localDevice -> localDevice.getSettings().proxyDevices != null).forEach( - localDevice -> localDevice.getSettings().proxyDevices.forEach(proxyDeviceId -> { - try { - System.err.println("Binding " + proxyDeviceId + " to gateway " + localDevice.getDeviceId()); - cloudIotManager.bindDevice(proxyDeviceId, localDevice.getDeviceId()); - } catch (Exception e) { - throw new RuntimeException("While binding device " + proxyDeviceId, e); - } - }) - ); - } - - private void shutdown() { - pubSubPusher.shutdown(); - } - - private List fetchDeviceList(Pattern devicePattern) { - if (localOnly()) { - System.err.println("Skipping remote registry fetch"); - return ImmutableList.of(); - } else { - System.err.println("Fetching remote registry " + cloudIotManager.getRegistryPath()); - return cloudIotManager.fetchDeviceList(devicePattern); - } - } - - private boolean localOnly() { - return LOCAL_ONLY_PROJECT_ID.equals(projectId); - } - - private Map loadLocalDevices(Pattern devicePattern) { - File devicesDir = new File(siteConfig, DEVICES_DIR); - String[] devices = devicesDir.list(); - Preconditions.checkNotNull(devices, "No devices found in " + devicesDir.getAbsolutePath()); - Map localDevices = loadDevices(devicesDir, devices, devicePattern); - validateKeys(localDevices); - validateFiles(localDevices); - writeNormalized(localDevices); - return localDevices; - } - - private void validateFiles(Map localDevices) { - for (LocalDevice device : localDevices.values()) { - try { - device.validatedDeviceDir(); - } catch (Exception e) { - device.getErrors().put("Files", e); - } - } - } - - private void writeNormalized(Map localDevices) { - for (String deviceName : localDevices.keySet()) { - try { - localDevices.get(deviceName).writeNormalized(); - } catch (Exception e) { - throw new RuntimeException("While writing normalized " + deviceName, e); - } - } - } - - private void validateKeys(Map localDevices) { - Map privateKeys = new HashMap<>(); - localDevices.values().stream().filter(LocalDevice::isDirectConnect).forEach( - localDevice -> { - String deviceName = localDevice.getDeviceId(); - CloudDeviceSettings settings = localDevice.getSettings(); - if (privateKeys.containsKey(settings.credential)) { - String previous = privateKeys.get(settings.credential); - RuntimeException exception = new RuntimeException( - String.format("Duplicate credentials found for %s & %s", previous, deviceName)); - localDevice.getErrors().put("Key", exception); - } else { - privateKeys.put(settings.credential, deviceName); - } - }); - } - - private Map loadDevices(File devicesDir, String[] devices, Pattern devicePattern) { - HashMap localDevices = new HashMap<>(); - for (String deviceName : devices) { - Matcher deviceMatch = devicePattern.matcher(deviceName); - if (deviceMatch.find() && LocalDevice.deviceExists(devicesDir, deviceName)) { - System.err.println("Loading local device " + deviceName); - LocalDevice localDevice = localDevices.computeIfAbsent(deviceName, - keyName -> new LocalDevice(devicesDir, deviceName, schemas)); - try { - localDevice.loadCredential(); - } catch (Exception e) { - localDevice.getErrors().put("Credential", e); - } - try { - localDevice.validateEnvelope(cloudIotManager.getRegistryId(), cloudIotManager.getSiteName()); - } catch (Exception e) { - localDevice.getErrors().put("Envelope", e); - } - } - } - return localDevices; - } - - private void setProjectId(String projectId) { - this.projectId = projectId; - } - - private void setSchemaBase(String schemaBasePath) { - schemaBase = new File(schemaBasePath); - schemaName = schemaBase.getName(); - loadSchema(METADATA_JSON); - loadSchema(ENVELOPE_JSON); - } - - private void loadSchema(String key) { - File schemaFile = new File(schemaBase, key); - try (InputStream schemaStream = new FileInputStream(schemaFile)) { - JSONObject rawSchema = new JSONObject(new JSONTokener(schemaStream)); - schemas.put(key, SchemaLoader.load(rawSchema, new Loader())); - } catch (Exception e) { - throw new RuntimeException("While loading schema " + schemaFile.getAbsolutePath(), e); - } - } - - private class Loader implements SchemaClient { - - public static final String FILE_PREFIX = "file:"; - - @Override - public InputStream get(String schema) { - try { - Preconditions.checkArgument(schema.startsWith(FILE_PREFIX)); - return new FileInputStream(new File(schemaBase, schema.substring(FILE_PREFIX.length()))); - } catch (Exception e) { - throw new RuntimeException("While loading sub-schema " + schema, e); - } - } - } -} diff --git a/validator/src/main/java/com/google/daq/mqtt/registrar/UdmiSchema.java b/validator/src/main/java/com/google/daq/mqtt/registrar/UdmiSchema.java deleted file mode 100644 index 9c2ed2701d..0000000000 --- a/validator/src/main/java/com/google/daq/mqtt/registrar/UdmiSchema.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.google.daq.mqtt.registrar; - -import java.util.*; - -public class UdmiSchema { - static class Envelope { - public String deviceId; - public String deviceNumId; - public String deviceRegistryId; - public String projectId; - public final String subFolder = LocalDevice.METADATA_SUBFOLDER; - } - - static class Metadata { - public PointsetMetadata pointset; - public SystemMetadata system; - public GatewayMetadata gateway; - public LocalnetMetadata localnet; - public CloudMetadata cloud; - public Integer version; - public Date timestamp; - public String hash; - } - - static class CloudMetadata { - public String auth_type; - } - - static class PointsetMetadata { - public Map points; - } - - static class SystemMetadata { - public LocationMetadata location; - public PhysicalTagMetadata physical_tag; - } - - static class GatewayMetadata { - public String gateway_id; - public List proxy_ids; - public String subsystem; - } - - static class PointMetadata { - public String units; - public String ref; - } - - static class LocationMetadata { - public String site; - public String section; - public Object position; - } - - static class PhysicalTagMetadata { - public AssetMetadata asset; - } - - static class AssetMetadata { - public String guid; - public String name; - public String site; - } - - static class Config { - public Integer version = 1; - public Date timestamp; - public GatewayConfig gateway; - public LocalnetConfig localnet; - public PointsetConfig pointset; - } - - static class GatewayConfig { - public List proxy_ids = new ArrayList<>(); - } - - static class LocalnetConfig { - public Map subsystems = new TreeMap<>(); - } - - static class PointsetConfig { - public Map points = new TreeMap<>(); - } - - static class PointConfig { - public String ref; - - static PointConfig fromRef(String ref) { - PointConfig pointConfig = new PointConfig(); - pointConfig.ref = ref; - return pointConfig; - } - } - - static class LocalnetMetadata { - public Map subsystem; - } - - static class LocalnetSubsystem { - public String local_id; - } -} diff --git a/validator/src/main/java/com/google/daq/mqtt/util/CloudDeviceSettings.java b/validator/src/main/java/com/google/daq/mqtt/util/CloudDeviceSettings.java deleted file mode 100644 index 5e8eec817e..0000000000 --- a/validator/src/main/java/com/google/daq/mqtt/util/CloudDeviceSettings.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.google.daq.mqtt.util; - -import com.google.api.services.cloudiot.v1.model.DeviceCredential; - -import java.util.List; - -public class CloudDeviceSettings { - public DeviceCredential credential; - public String metadata; - public List proxyDevices; - public String config; -} diff --git a/validator/src/main/java/com/google/daq/mqtt/util/CloudIotConfig.java b/validator/src/main/java/com/google/daq/mqtt/util/CloudIotConfig.java deleted file mode 100644 index 2a5fa86681..0000000000 --- a/validator/src/main/java/com/google/daq/mqtt/util/CloudIotConfig.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.google.daq.mqtt.util; - -public class CloudIotConfig { - public String registry_id; - public String cloud_region; - public String site_name; - public String registrar_topic; -} diff --git a/validator/src/main/java/com/google/daq/mqtt/util/CloudIotManager.java b/validator/src/main/java/com/google/daq/mqtt/util/CloudIotManager.java deleted file mode 100644 index 1fec58ed0a..0000000000 --- a/validator/src/main/java/com/google/daq/mqtt/util/CloudIotManager.java +++ /dev/null @@ -1,264 +0,0 @@ -package com.google.daq.mqtt.util; - -import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; -import com.google.api.client.googleapis.json.GoogleJsonResponseException; -import com.google.api.client.http.HttpRequestInitializer; -import com.google.api.client.json.JsonFactory; -import com.google.api.client.json.jackson2.JacksonFactory; -import com.google.api.services.cloudiot.v1.CloudIot; -import com.google.api.services.cloudiot.v1.CloudIotScopes; -import com.google.api.services.cloudiot.v1.model.BindDeviceToGatewayRequest; -import com.google.api.services.cloudiot.v1.model.Device; -import com.google.api.services.cloudiot.v1.model.DeviceCredential; -import com.google.api.services.cloudiot.v1.model.GatewayConfig; -import com.google.api.services.cloudiot.v1.model.ModifyCloudToDeviceConfigRequest; -import com.google.api.services.cloudiot.v1.model.PublicKeyCredential; -import com.google.auth.http.HttpCredentialsAdapter; -import com.google.auth.oauth2.GoogleCredentials; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Base64; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Pattern; - -import static com.google.daq.mqtt.util.ConfigUtil.readCloudIotConfig; -import static java.util.stream.Collectors.toList; - -/** - * Encapsulation of all Cloud IoT interaction functions. - */ -public class CloudIotManager { - - private static final String DEVICE_UPDATE_MASK = "blocked,credentials,metadata"; - private static final String REGISTERED_KEY = "registered"; - private static final String SCHEMA_KEY = "schema_name"; - private static final int LIST_PAGE_SIZE = 1000; - - private final CloudIotConfig cloudIotConfig; - - private final String registryId; - private final String projectId; - private final String cloudRegion; - - private CloudIot cloudIotService; - private String projectPath; - private CloudIot.Projects.Locations.Registries cloudIotRegistries; - private Map deviceMap = new HashMap<>(); - private String schemaName; - - public CloudIotManager(String projectId, File iotConfigFile, String schemaName) { - this.projectId = projectId; - this.schemaName = schemaName; - cloudIotConfig = validate(readCloudIotConfig(iotConfigFile)); - registryId = cloudIotConfig.registry_id; - cloudRegion = cloudIotConfig.cloud_region; - initializeCloudIoT(); - } - - private static CloudIotConfig validate(CloudIotConfig cloudIotConfig) { - Preconditions.checkNotNull(cloudIotConfig.registry_id, "registry_id not defined"); - Preconditions.checkNotNull(cloudIotConfig.cloud_region, "cloud_region not defined"); - Preconditions.checkNotNull(cloudIotConfig.site_name, "site_name not defined"); - return cloudIotConfig; - } - - public String getRegistryPath() { - return projectPath + "/registries/" + registryId; - } - - private String getDevicePath(String registryId, String deviceId) { - return getRegistryPath() + "/devices/" + deviceId; - } - - private void initializeCloudIoT() { - projectPath = "projects/" + projectId + "/locations/" + cloudRegion; - try { - System.err.println("Initializing with default credentials..."); - GoogleCredentials credential = - GoogleCredentials.getApplicationDefault().createScoped(CloudIotScopes.all()); - JsonFactory jsonFactory = JacksonFactory.getDefaultInstance(); - HttpRequestInitializer init = new HttpCredentialsAdapter(credential); - cloudIotService = - new CloudIot.Builder(GoogleNetHttpTransport.newTrustedTransport(), jsonFactory, init) - .setApplicationName("com.google.iot.bos") - .build(); - cloudIotRegistries = cloudIotService.projects().locations().registries(); - System.err.println("Created service for project " + projectPath); - } catch (Exception e) { - throw new RuntimeException("While initializing Cloud IoT project " + projectPath, e); - } - } - - public boolean registerDevice(String deviceId, CloudDeviceSettings settings) { - try { - Preconditions.checkNotNull(cloudIotService, "CloudIoT service not initialized"); - Preconditions.checkNotNull(deviceMap, "deviceMap not initialized"); - Device device = deviceMap.get(deviceId); - boolean isNewDevice = device == null; - if (isNewDevice) { - createDevice(deviceId, settings); - } else { - updateDevice(deviceId, settings, device); - } - writeDeviceConfig(deviceId, settings.config); - return isNewDevice; - } catch (Exception e) { - throw new RuntimeException("While registering device " + deviceId, e); - } - } - - private void writeDeviceConfig(String deviceId, String config) { - try { - cloudIotRegistries.devices().modifyCloudToDeviceConfig(getDevicePath(registryId, deviceId), - new ModifyCloudToDeviceConfigRequest().setBinaryData( - Base64.getEncoder().encodeToString(config.getBytes())) - ).execute(); - } catch (Exception e) { - throw new RuntimeException("While modifying device config", e); - } - } - - public void blockDevice(String deviceId, boolean blocked) { - try { - Device device = new Device(); - device.setBlocked(blocked); - String path = getDevicePath(registryId, deviceId); - cloudIotRegistries.devices().patch(path, device).setUpdateMask("blocked").execute(); - } catch (Exception e) { - throw new RuntimeException(String.format("While (un)blocking device %s/%s=%s", registryId, deviceId, blocked), e); - } - } - - private Device makeDevice(String deviceId, CloudDeviceSettings settings, - Device oldDevice) { - Map metadataMap = oldDevice == null ? null : oldDevice.getMetadata(); - if (metadataMap == null) { - metadataMap = new HashMap<>(); - } - metadataMap.put(REGISTERED_KEY, settings.metadata); - metadataMap.put(SCHEMA_KEY, schemaName); - return new Device() - .setId(deviceId) - .setGatewayConfig(getGatewayConfig(settings)) - .setCredentials(getCredentials(settings)) - .setMetadata(metadataMap); - } - - private ImmutableList getCredentials(CloudDeviceSettings settings) { - if (settings.credential != null) { - return ImmutableList.of(settings.credential); - } else { - return ImmutableList.of(); - } - } - - private GatewayConfig getGatewayConfig(CloudDeviceSettings settings) { - boolean isGateway = settings.proxyDevices != null; - GatewayConfig gwConfig = new GatewayConfig(); - gwConfig.setGatewayType(isGateway ? "GATEWAY" : "NON_GATEWAY"); - gwConfig.setGatewayAuthMethod("ASSOCIATION_ONLY"); - return gwConfig; - } - - private void createDevice(String deviceId, CloudDeviceSettings settings) throws IOException { - try { - cloudIotRegistries.devices().create(getRegistryPath(), - makeDevice(deviceId, settings, null)).execute(); - } catch (GoogleJsonResponseException e) { - throw new RuntimeException("Remote error creating device " + deviceId, e); - } - } - - private void updateDevice(String deviceId, CloudDeviceSettings settings, - Device oldDevice) { - try { - Device device = makeDevice(deviceId, settings, oldDevice) - .setId(null) - .setNumId(null); - cloudIotRegistries - .devices() - .patch(getDevicePath(registryId, deviceId), device).setUpdateMask(DEVICE_UPDATE_MASK) - .execute(); - } catch (Exception e) { - throw new RuntimeException("Remote error patching device " + deviceId, e); - } - } - - public static DeviceCredential makeCredentials(String keyFormat, String keyData) { - PublicKeyCredential publicKeyCredential = new PublicKeyCredential(); - publicKeyCredential.setFormat(keyFormat); - publicKeyCredential.setKey(keyData); - - DeviceCredential deviceCredential = new DeviceCredential(); - deviceCredential.setPublicKey(publicKeyCredential); - return deviceCredential; - } - - public List fetchDeviceList(Pattern devicePattern) { - Preconditions.checkNotNull(cloudIotService, "CloudIoT service not initialized"); - try { - List devices = cloudIotRegistries - .devices() - .list(getRegistryPath()) - .setPageSize(LIST_PAGE_SIZE) - .execute() - .getDevices(); - if (devices == null) { - return new ArrayList<>(); - } - if (devices.size() == LIST_PAGE_SIZE) { - throw new RuntimeException("Returned exact page size, likely not fetched all devices"); - } - return devices.stream().filter(device -> devicePattern.matcher(device.getId()).find()).collect(toList()); - } catch (Exception e) { - throw new RuntimeException("While listing devices for registry " + registryId, e); - } - } - - public Device fetchDevice(String deviceId) { - return deviceMap.computeIfAbsent(deviceId, this::fetchDeviceFromCloud); - } - - private Device fetchDeviceFromCloud(String deviceId) { - try { - return cloudIotRegistries.devices().get(getDevicePath(registryId, deviceId)).execute(); - } catch (Exception e) { - if (e instanceof GoogleJsonResponseException - && ((GoogleJsonResponseException) e).getDetails().getCode() == 404) { - return null; - } - throw new RuntimeException("While fetching " + deviceId, e); - } - } - - public String getRegistryId() { - return registryId; - } - - public String getProjectId() { - return projectId; - } - - public String getSiteName() { - return cloudIotConfig.site_name; - } - - public Object getCloudRegion() { - return cloudRegion; - } - - public void bindDevice(String proxyDeviceId, String gatewayDeviceId) throws IOException { - cloudIotRegistries.bindDeviceToGateway(getRegistryPath(), - getBindRequest(proxyDeviceId, gatewayDeviceId)).execute(); - } - - private BindDeviceToGatewayRequest getBindRequest(String deviceId, String gatewayId) { - return new BindDeviceToGatewayRequest().setDeviceId(deviceId).setGatewayId(gatewayId); - } -} diff --git a/validator/src/main/java/com/google/daq/mqtt/util/ConfigUtil.java b/validator/src/main/java/com/google/daq/mqtt/util/ConfigUtil.java deleted file mode 100644 index 16230859d4..0000000000 --- a/validator/src/main/java/com/google/daq/mqtt/util/ConfigUtil.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.google.daq.mqtt.util; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; -import com.google.api.services.cloudiot.v1.CloudIotScopes; - -import java.io.File; -import java.io.FileInputStream; - -public class ConfigUtil { - public static final String CLOUD_IOT_CONFIG_JSON = "cloud_iot_config.json"; - - private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); - - public static CloudIotConfig readCloudIotConfig(File configFile) { - try { - return OBJECT_MAPPER.readValue(configFile, CloudIotConfig.class); - } catch (Exception e) { - throw new RuntimeException("While reading config file "+ configFile.getAbsolutePath(), e); - } - } - - static GoogleCredential authorizeServiceAccount(File credFile) { - try (FileInputStream credStream = new FileInputStream(credFile)) { - return GoogleCredential - .fromStream(credStream) - .createScoped(CloudIotScopes.all()); - } catch (Exception e) { - throw new RuntimeException("While reading cred file " + credFile.getAbsolutePath(), e); - } - } -} diff --git a/validator/src/main/java/com/google/daq/mqtt/util/ExceptionMap.java b/validator/src/main/java/com/google/daq/mqtt/util/ExceptionMap.java deleted file mode 100644 index ce8cdcfd32..0000000000 --- a/validator/src/main/java/com/google/daq/mqtt/util/ExceptionMap.java +++ /dev/null @@ -1,109 +0,0 @@ -package com.google.daq.mqtt.util; - -import java.io.IOException; -import java.io.PrintStream; -import java.util.Map; -import java.util.TreeMap; -import java.util.function.BiConsumer; -import java.util.stream.Stream; - -import org.everit.json.schema.ValidationException; - -public class ExceptionMap extends RuntimeException { - - private static final byte[] NEWLINE_BYTES = "\n".getBytes(); - private static final byte[] SEPARATOR_BYTES = ": ".getBytes(); - - final Map exceptions = new TreeMap<>(); - - public ExceptionMap(String description) { - super(description); - } - - private void forEach(BiConsumer consumer) { - exceptions.forEach(consumer); - } - - public boolean isEmpty() { - return exceptions.isEmpty(); - } - - public void throwIfNotEmpty() { - if (!exceptions.isEmpty() || getCause() != null) { - throw this; - } - } - - public void put(String key, Exception exception) { - if (exceptions.put(key, exception) != null) { - throw new IllegalArgumentException("Exception key already defined: " + key); - } - } - - public static ErrorTree format(Exception e, String indent) { - return format(e, "", indent); - } - - private static ErrorTree format(Throwable e, final String prefix, final String indent) { - final ErrorTree errorTree = new ErrorTree(); - errorTree.prefix = prefix; - errorTree.message = e.getMessage(); - final String newPrefix = prefix + indent; - if (e instanceof ExceptionMap) { - if (e.getCause() != null) { - errorTree.child = format(e.getCause(), newPrefix, indent); - } - ((ExceptionMap) e).forEach( - (key, sub) -> errorTree.children.put(key, format(sub, newPrefix, indent))); - } else if (e instanceof ValidationException) { - ((ValidationException) e).getCausingExceptions().forEach( - sub -> errorTree.children.put(sub.getMessage(), format(sub, newPrefix, indent))); - } else if (e.getCause() != null) { - errorTree.child = format(e.getCause(), newPrefix, indent); - } - if (errorTree.children.isEmpty()) { - errorTree.children = null; - } - if (errorTree.child == null && errorTree.children == null && errorTree.message == null) { - errorTree.message = e.toString(); - } - return errorTree; - } - - public Stream> stream() { - return exceptions.entrySet().stream(); - } - - public int size() { - return exceptions.size(); - } - - public static class ErrorTree { - public String prefix; - public String message; - public ErrorTree child; - public Map children = new TreeMap<>(); - - public void write(PrintStream err) { - if (message == null && children == null && child == null) { - throw new RuntimeException("Empty ErrorTree object"); - } - try { - if (message != null) { - err.write(prefix.getBytes()); - err.write(message.getBytes()); - err.write(NEWLINE_BYTES); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - if (child != null) { - child.write(err); - } - if (children != null) { - children.forEach((key, value) -> value.write(err)); - } - } - } - -} diff --git a/validator/src/main/java/com/google/daq/mqtt/util/FirestoreDataSink.java b/validator/src/main/java/com/google/daq/mqtt/util/FirestoreDataSink.java deleted file mode 100644 index ac0d527f2a..0000000000 --- a/validator/src/main/java/com/google/daq/mqtt/util/FirestoreDataSink.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.google.daq.mqtt.util; - -import com.google.auth.oauth2.GoogleCredentials; -import com.google.cloud.ServiceOptions; -import com.google.cloud.firestore.DocumentReference; -import com.google.cloud.firestore.Firestore; -import com.google.cloud.firestore.FirestoreOptions; -import com.google.common.base.Preconditions; -import com.google.daq.mqtt.util.ExceptionMap.ErrorTree; -import java.time.Instant; -import java.time.ZoneOffset; -import java.time.format.DateTimeFormatter; -import java.util.Map; -import java.util.concurrent.atomic.AtomicReference; - -public class FirestoreDataSink { - - private static final String - VIEW_URL_FORMAT = "https://console.cloud.google.com/firestore/data/registries/?project=%s"; - - private static final DateTimeFormatter dateTimeFormatter = - DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX").withZone(ZoneOffset.UTC); - - private final Firestore db; - private final String projectId = ServiceOptions.getDefaultProjectId(); - - private final AtomicReference oldError = new AtomicReference<>(); - - public FirestoreDataSink() { - try { - GoogleCredentials credential = GoogleCredentials.getApplicationDefault(); - FirestoreOptions firestoreOptions = - FirestoreOptions.getDefaultInstance().toBuilder() - .setCredentials(credential) - .setProjectId(projectId) - .setTimestampsInSnapshotsEnabled(true) - .build(); - - db = firestoreOptions.getService(); - } catch (Exception e) { - throw new RuntimeException("While creating Firestore connection to " + projectId, e); - } - } - - public void validationResult(String deviceId, String schemaId, Map attributes, - Object message, ErrorTree errorTree) { - if (oldError.get() != null) { - throw oldError.getAndSet(null); - } - - try { - String registryId = attributes.get("deviceRegistryId"); - Preconditions.checkNotNull(deviceId, "deviceId attribute not defined"); - Preconditions.checkNotNull(schemaId, "schemaId not properly defined"); - Preconditions.checkNotNull(registryId, "deviceRegistryId attribute not defined"); - String instantNow = dateTimeFormatter.format(Instant.now()); - DocumentReference registryDoc = db.collection("registries").document(registryId); - registryDoc.update("validated", instantNow); - DocumentReference deviceDoc = registryDoc.collection("devices").document(deviceId); - deviceDoc.update("validated", instantNow); - DocumentReference resultDoc = deviceDoc.collection("validations").document(schemaId); - PojoBundle dataBundle = new PojoBundle(); - dataBundle.validated = instantNow; - dataBundle.errorTree = errorTree; - dataBundle.attributes = attributes; - dataBundle.message = message; - resultDoc.set(dataBundle); - } catch (Exception e) { - throw new RuntimeException("While writing result for " + deviceId, e); - } - } - - static class PojoBundle { - public String validated; - public ErrorTree errorTree; - public Object message; - public Map attributes; - } - - public String getViewUrl() { - return String.format(VIEW_URL_FORMAT, projectId); - } -} diff --git a/validator/src/main/java/com/google/daq/mqtt/util/PubSubClient.java b/validator/src/main/java/com/google/daq/mqtt/util/PubSubClient.java deleted file mode 100644 index c7c048dd1f..0000000000 --- a/validator/src/main/java/com/google/daq/mqtt/util/PubSubClient.java +++ /dev/null @@ -1,166 +0,0 @@ -package com.google.daq.mqtt.util; - -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.google.api.client.util.Base64; -import com.google.cloud.ServiceOptions; -import com.google.cloud.pubsub.v1.AckReplyConsumer; -import com.google.cloud.pubsub.v1.MessageReceiver; -import com.google.cloud.pubsub.v1.Subscriber; -import com.google.cloud.pubsub.v1.SubscriptionAdminClient; -import com.google.cloud.pubsub.v1.SubscriptionAdminClient.ListSubscriptionsPagedResponse; -import com.google.protobuf.Timestamp; -import com.google.pubsub.v1.*; -import io.grpc.LoadBalancerRegistry; -import io.grpc.internal.PickFirstLoadBalancerProvider; - -import java.util.HashMap; -import java.util.Map; -import java.util.TreeMap; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingDeque; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.BiConsumer; - -public class PubSubClient { - - private static final String CONNECT_ERROR_FORMAT = "While connecting to %s/%s"; - - private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper() - .enable(SerializationFeature.INDENT_OUTPUT) - .setSerializationInclusion(Include.NON_NULL); - private static final String SUBSCRIPTION_NAME_FORMAT = "daq-validator-%s"; - private static final String - REFRESH_ERROR_FORMAT = "While refreshing subscription to topic %s subscription %s"; - - private static final String PROJECT_ID = ServiceOptions.getDefaultProjectId(); - private static final long SUBSCRIPTION_RACE_DELAY_MS = 10000; - private static final String WAS_BASE_64 = "wasBase64"; - - private final AtomicBoolean active = new AtomicBoolean(); - private final BlockingQueue messages = new LinkedBlockingDeque<>(); - private final long startTimeSec = System.currentTimeMillis() / 1000; - - private Subscriber subscriber; - - { - // Why this needs to be done there is no rhyme or reason. - LoadBalancerRegistry.getDefaultRegistry().register(new PickFirstLoadBalancerProvider()); - } - - public PubSubClient(String instName, String topicId) { - try { - ProjectTopicName projectTopicName = ProjectTopicName.of(PROJECT_ID, topicId); - String name = String.format(SUBSCRIPTION_NAME_FORMAT, instName); - ProjectSubscriptionName subscriptionName = ProjectSubscriptionName.of(PROJECT_ID, name); - System.out.println("Resetting and connecting to pubsub subscription " + subscriptionName); - resetSubscription(projectTopicName, subscriptionName); - subscriber = Subscriber.newBuilder(subscriptionName, new MessageProcessor()).build(); - subscriber.startAsync().awaitRunning(); - active.set(true); - } catch (Exception e) { - throw new RuntimeException(String.format(CONNECT_ERROR_FORMAT, PROJECT_ID, topicId), e); - } - } - - private SeekRequest getCurrentTimeSeekRequest(String subscription) { - Timestamp timestamp = Timestamp.newBuilder().setSeconds(System.currentTimeMillis()/1000).build(); - return SeekRequest.newBuilder().setSubscription(subscription).setTime(timestamp).build(); - } - - public boolean isActive() { - return active.get(); - } - - @SuppressWarnings("unchecked") - public void processMessage(BiConsumer, Map> handler) { - try { - PubsubMessage message = messages.take(); - long seconds = message.getPublishTime().getSeconds(); - if (seconds < startTimeSec) { - System.out.println(String.format("Flushing outdated message from %d seconds ago", - startTimeSec - seconds)); - return; - } - Map attributes = message.getAttributesMap(); - byte[] rawData = message.getData().toByteArray(); - final String data; - boolean base64 = rawData[0] != '{'; - if (base64) { - data = new String(Base64.decodeBase64(rawData)); - } else { - data = new String(rawData); - } - Map asMap; - try { - asMap = OBJECT_MAPPER.readValue(data, TreeMap.class); - } catch (JsonProcessingException e) { - asMap = new ErrorContainer(e, data); - } - - attributes = new HashMap<>(attributes); - attributes.put(WAS_BASE_64, ""+ base64); - - handler.accept(asMap, attributes); - } catch (Exception e) { - throw new RuntimeException("Processing pubsub message for " + getSubscriptionId(), e); - } - } - - static class ErrorContainer extends TreeMap { - ErrorContainer(Exception e, String message) { - put("exception", e.toString()); - put("message", message); - } - } - - private void stop() { - if (subscriber != null) { - active.set(false); - subscriber.stopAsync(); - } - } - - public String getSubscriptionId() { - return subscriber.getSubscriptionNameString(); - } - - private class MessageProcessor implements MessageReceiver { - @Override - public void receiveMessage(PubsubMessage message, AckReplyConsumer consumer) { - messages.offer(message); - consumer.ack(); - } - } - - private void resetSubscription(ProjectTopicName topicName, ProjectSubscriptionName subscriptionName) { - try (SubscriptionAdminClient subscriptionAdminClient = SubscriptionAdminClient.create()) { - if (subscriptionExists(subscriptionAdminClient, topicName, subscriptionName)) { - System.out.println("Resetting existing subscription " + subscriptionName); - subscriptionAdminClient.seek(getCurrentTimeSeekRequest(subscriptionName.toString())); - Thread.sleep(SUBSCRIPTION_RACE_DELAY_MS); - } else { - System.out.println("Creating new subscription " + subscriptionName); - subscriptionAdminClient.createSubscription( - subscriptionName, topicName, PushConfig.getDefaultInstance(), 0); - } - } catch (Exception e) { - throw new RuntimeException( - String.format(REFRESH_ERROR_FORMAT, topicName, subscriptionName), e); - } - } - - private boolean subscriptionExists(SubscriptionAdminClient subscriptionAdminClient, - ProjectTopicName topicName, ProjectSubscriptionName subscriptionName) { - ListSubscriptionsPagedResponse listSubscriptionsPagedResponse = subscriptionAdminClient - .listSubscriptions(ProjectName.of(PROJECT_ID)); - for (Subscription subscription : listSubscriptionsPagedResponse.iterateAll()) { - if (subscription.getName().equals(subscriptionName.toString())) { - return true; - } - } - return false; - } -} diff --git a/validator/src/main/java/com/google/daq/mqtt/util/PubSubPusher.java b/validator/src/main/java/com/google/daq/mqtt/util/PubSubPusher.java deleted file mode 100644 index 3c9eca44bc..0000000000 --- a/validator/src/main/java/com/google/daq/mqtt/util/PubSubPusher.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.google.daq.mqtt.util; - -import com.google.api.core.ApiFuture; -import com.google.cloud.pubsub.v1.Publisher; -import com.google.common.base.Preconditions; -import com.google.protobuf.ByteString; -import com.google.pubsub.v1.ProjectTopicName; -import com.google.pubsub.v1.PubsubMessage; -import io.grpc.LoadBalancerRegistry; -import io.grpc.internal.PickFirstLoadBalancerProvider; - -import java.io.File; -import java.nio.charset.Charset; -import java.util.Map; - -import static com.google.daq.mqtt.util.ConfigUtil.readCloudIotConfig; - -public class PubSubPusher { - - private final Publisher publisher; - private final String registrar_topic; - - { - // Why this needs to be done there is no rhyme or reason. - LoadBalancerRegistry.getDefaultRegistry().register(new PickFirstLoadBalancerProvider()); - } - - public PubSubPusher(String projectId, File iotConfigFile) { - try { - CloudIotConfig cloudIotConfig = validate(readCloudIotConfig(iotConfigFile)); - registrar_topic = cloudIotConfig.registrar_topic; - ProjectTopicName topicName = ProjectTopicName.of(projectId, registrar_topic); - publisher = Publisher.newBuilder(topicName).build(); - } catch (Exception e) { - throw new RuntimeException("While creating PubSubPublisher", e); - } - } - - public String sendMessage(Map attributes, String body) { - try { - PubsubMessage message = PubsubMessage.newBuilder() - .setData(ByteString.copyFrom(body, Charset.defaultCharset())) - .putAllAttributes(attributes) - .build(); - ApiFuture publish = publisher.publish(message); - return publish.get(); - } catch (Exception e) { - throw new RuntimeException("While sending to topic " + registrar_topic, e); - } - } - - public void shutdown() { - try { - publisher.publishAllOutstanding(); - publisher.shutdown(); - System.err.println("Done with PubSubPusher"); - } catch (Exception e) { - throw new RuntimeException("While shutting down publisher" + registrar_topic, e); - } - } - - private CloudIotConfig validate(CloudIotConfig readCloudIotConfig) { - Preconditions.checkNotNull(readCloudIotConfig.registrar_topic, "registrar_topic not defined"); - return readCloudIotConfig; - } -} diff --git a/validator/src/main/java/com/google/daq/mqtt/util/RetryHttpInitializerWrapper.java b/validator/src/main/java/com/google/daq/mqtt/util/RetryHttpInitializerWrapper.java deleted file mode 100644 index dfc84aa9e6..0000000000 --- a/validator/src/main/java/com/google/daq/mqtt/util/RetryHttpInitializerWrapper.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.google.daq.mqtt.util; - -import com.google.api.client.auth.oauth2.Credential; -import com.google.api.client.http.HttpBackOffIOExceptionHandler; -import com.google.api.client.http.HttpBackOffUnsuccessfulResponseHandler; -import com.google.api.client.http.HttpRequest; -import com.google.api.client.http.HttpRequestInitializer; -import com.google.api.client.http.HttpResponse; -import com.google.api.client.http.HttpUnsuccessfulResponseHandler; -import com.google.api.client.util.ExponentialBackOff; -import com.google.api.client.util.Sleeper; -import com.google.common.base.Preconditions; -import java.io.IOException; -import java.util.logging.Logger; - -/** - * RetryHttpInitializerWrapper will automatically retry upon RPC failures, preserving the - * auto-refresh behavior of the Google Credentials. - */ -public class RetryHttpInitializerWrapper implements HttpRequestInitializer { - - /** A private logger. */ - private static final Logger LOG = Logger.getLogger(RetryHttpInitializerWrapper.class.getName()); - - /** One minutes in milliseconds. */ - private static final int ONE_MINUTE_MILLIS = 60 * 1000; - - /** - * Intercepts the request for filling in the "Authorization" header field, as well as recovering - * from certain unsuccessful error codes wherein the Credential must refresh its token for a - * retry. - */ - private final Credential wrappedCredential; - - /** A sleeper; you can replace it with a mock in your test. */ - private final Sleeper sleeper; - - /** - * A constructor. - * - * @param wrappedCredential Credential which will be wrapped and used for providing auth header. - */ - public RetryHttpInitializerWrapper(final Credential wrappedCredential) { - this(wrappedCredential, Sleeper.DEFAULT); - } - - /** - * A protected constructor only for testing. - * - * @param wrappedCredential Credential which will be wrapped and used for providing auth header. - * @param sleeper Sleeper for easy testing. - */ - RetryHttpInitializerWrapper(final Credential wrappedCredential, final Sleeper sleeper) { - this.wrappedCredential = Preconditions.checkNotNull(wrappedCredential); - this.sleeper = sleeper; - } - - /** Initializes the given request. */ - @Override - public final void initialize(final HttpRequest request) { - request.setReadTimeout(2 * ONE_MINUTE_MILLIS); // 2 minutes read timeout - final HttpUnsuccessfulResponseHandler backoffHandler = - new HttpBackOffUnsuccessfulResponseHandler(new ExponentialBackOff()).setSleeper(sleeper); - request.setInterceptor(wrappedCredential); - request.setUnsuccessfulResponseHandler( - new HttpUnsuccessfulResponseHandler() { - @Override - public boolean handleResponse( - final HttpRequest request, final HttpResponse response, final boolean supportsRetry) - throws IOException { - if (wrappedCredential.handleResponse(request, response, supportsRetry)) { - // If credential decides it can handle it, the return code or message indicated - // something specific to authentication, and no backoff is desired. - return true; - } else if (backoffHandler.handleResponse(request, response, supportsRetry)) { - // Otherwise, we defer to the judgment of our internal backoff handler. - LOG.info("Retrying " + request.getUrl().toString()); - return true; - } else { - return false; - } - } - }); - request.setIOExceptionHandler( - new HttpBackOffIOExceptionHandler(new ExponentialBackOff()).setSleeper(sleeper)); - } -} \ No newline at end of file diff --git a/validator/src/main/java/com/google/daq/mqtt/validator/ReportingDevice.java b/validator/src/main/java/com/google/daq/mqtt/validator/ReportingDevice.java deleted file mode 100644 index 65480463d0..0000000000 --- a/validator/src/main/java/com/google/daq/mqtt/validator/ReportingDevice.java +++ /dev/null @@ -1,101 +0,0 @@ -package com.google.daq.mqtt.validator; - -import com.google.common.base.Joiner; - -import java.util.*; - -public class ReportingDevice { - - private final String deviceId; - private final MetadataDiff metadataDiff = new MetadataDiff(); - private Metadata metadata; - private List errors = new ArrayList<>(); - - public ReportingDevice(String deviceId) { - this.deviceId = deviceId; - } - - public void setMetadata(Metadata metadata) { - this.metadata = metadata; - } - - public String getDeviceId() { - return deviceId; - } - - public boolean hasBeenValidated() { - return metadataDiff.extraPoints != null; - } - - public boolean hasError() { - return metadataDiff.errors != null && metadataDiff.errors.isEmpty(); - } - - public boolean hasMetadataDiff() { - return (metadataDiff.extraPoints != null && !metadataDiff.extraPoints.isEmpty()) - || (metadataDiff.missingPoints != null && !metadataDiff.missingPoints.isEmpty()); - } - - public String metadataMessage() { - if (metadataDiff.extraPoints != null && !metadataDiff.extraPoints.isEmpty()) { - return "Extra points: " + Joiner.on(",").join(metadataDiff.extraPoints); - } - if (metadataDiff.missingPoints != null && !metadataDiff.missingPoints.isEmpty()) { - return "Missing points: " + Joiner.on(",").join(metadataDiff.missingPoints); - } - return null; - } - - public MetadataDiff getMetadataDiff() { - return metadataDiff; - } - - public void validateMetadata(PointsetMessage message) { - Set expectedPoints = new TreeSet<>(metadata.pointset.points.keySet()); - Set deliveredPoints = new TreeSet<>(message.points.keySet()); - metadataDiff.extraPoints = new TreeSet<>(deliveredPoints); - metadataDiff.extraPoints.removeAll(expectedPoints); - metadataDiff.missingPoints = new TreeSet<>(expectedPoints); - metadataDiff.missingPoints.removeAll(deliveredPoints); - if (hasMetadataDiff()) { - throw new RuntimeException("Metadata validation failed: " + metadataMessage()); - } - } - - public void addError(Exception error) { - errors.add(error); - if (metadataDiff.errors == null) { - metadataDiff.errors = new ArrayList<>(); - } - metadataDiff.errors.add(error.toString()); - } - - public static class MetadataDiff { - public List errors; - public Set extraPoints; - public Set missingPoints; - } - - public static class PointsetMessage { - public Integer version; - public String timestamp; - public Map points; - } - - public static class Metadata { - public Integer version; - public String timestamp; - public String hash; - public Object system; - public PointSet pointset; - } - - public static class PointSet { - public Map points; - } - - public static class PointDescriptor { - public String units; - public Object present_value; - } -} diff --git a/validator/src/main/java/com/google/daq/mqtt/validator/Validator.java b/validator/src/main/java/com/google/daq/mqtt/validator/Validator.java deleted file mode 100644 index ca133f2769..0000000000 --- a/validator/src/main/java/com/google/daq/mqtt/validator/Validator.java +++ /dev/null @@ -1,463 +0,0 @@ -package com.google.daq.mqtt.validator; - -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.databind.util.ISO8601DateFormat; -import com.google.cloud.ServiceOptions; -import com.google.common.base.Preconditions; -import com.google.common.base.Strings; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; -import com.google.daq.mqtt.util.*; -import com.google.daq.mqtt.util.ExceptionMap.ErrorTree; -import org.everit.json.schema.Schema; -import org.everit.json.schema.ValidationException; -import org.everit.json.schema.loader.SchemaClient; -import org.everit.json.schema.loader.SchemaLoader; -import org.json.JSONObject; -import org.json.JSONTokener; - -import java.io.*; -import java.net.URL; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -public class Validator { - - private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd-MM-yyyy hh:mm"); - - private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper() - .enable(SerializationFeature.INDENT_OUTPUT) - .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) - .setDateFormat(new ISO8601DateFormat()) - .setSerializationInclusion(Include.NON_NULL); - - private static final String ERROR_FORMAT_INDENT = " "; - private static final String JSON_SUFFIX = ".json"; - private static final String SCHEMA_VALIDATION_FORMAT = "Validating %d schemas"; - private static final String TARGET_VALIDATION_FORMAT = "Validating %d files against %s"; - private static final String PUBSUB_PREFIX = "pubsub:"; - private static final File OUT_BASE_FILE = new File("validations"); - private static final String DEVICE_FILE_FORMAT = "devices/%s"; - private static final String ATTRIBUTE_FILE_FORMAT = "%s.attr"; - private static final String MESSAGE_FILE_FORMAT = "%s.json"; - private static final String ERROR_FILE_FORMAT = "%s.out"; - private static final Pattern DEVICE_ID_PATTERN = - Pattern.compile("^([a-z][_a-z0-9-]*[a-z0-9]|[A-Z][_A-Z0-9-]*[A-Z0-9])$"); - private static final String DEVICE_MATCH_FORMAT = "DeviceId %s must match pattern %s"; - private static final String SCHEMA_SKIP_FORMAT = "Unknown schema subFolder '%s' for %s"; - private static final String ENVELOPE_SCHEMA_ID = "envelope"; - private static final String METADATA_JSON = "metadata.json"; - private static final String DEVICES_SUBDIR = "devices"; - private static final String METADATA_REPORT_JSON = "metadata_report.json"; - private static final String DEVICE_REGISTRY_ID_KEY = "deviceRegistryId"; - private static final String UNKNOWN_SCHEMA_DEFAULT = "unknown"; - private static final String POINTSET_TYPE = "pointset"; - private static final String NO_SITE = "--"; - private FirestoreDataSink dataSink; - private File schemaRoot; - private String schemaSpec; - private final Map expectedDevices = new TreeMap<>(); - private final Set extraDevices = new TreeSet<>(); - private final Set processedDevices = new TreeSet<>(); - private final Set base64Devices = new TreeSet<>(); - private CloudIotConfig cloudIotConfig; - public static final File METADATA_REPORT_FILE = new File(OUT_BASE_FILE, METADATA_REPORT_JSON); - - public static void main(String[] args) { - Validator validator = new Validator(); - try { - if (args.length != 4) { - throw new IllegalArgumentException("Args: [schema] [target] [inst_name] [site]"); - } - validator.setSchemaSpec(args[0]); - String targetSpec = args[1]; - String instName = args[2]; - String siteDir = args[3]; - if (!NO_SITE.equals(siteDir)) { - validator.setSiteDir(args[3]); - } - if (targetSpec.startsWith(PUBSUB_PREFIX)) { - String topicName = targetSpec.substring(PUBSUB_PREFIX.length()); - validator.validatePubSub(instName, topicName); - } else { - validator.validateFilesOutput(targetSpec); - } - } catch (ExceptionMap | ValidationException processingException) { - System.exit(2); - } catch (Exception e) { - e.printStackTrace(); - System.err.flush(); - System.exit(-1); - } - System.exit(0); - } - - private void setSiteDir(String siteDir) { - File cloudConfig = new File(siteDir, "cloud_iot_config.json"); - try { - cloudIotConfig = ConfigUtil.readCloudIotConfig(cloudConfig); - } catch (Exception e) { - throw new RuntimeException("While reading config file " + cloudConfig.getAbsolutePath(), e); - } - - File devicesDir = new File(siteDir, DEVICES_SUBDIR); - try { - for (String device : Objects.requireNonNull(devicesDir.list())) { - try { - File deviceDir = new File(devicesDir, device); - File metadataFile = new File(deviceDir, METADATA_JSON); - ReportingDevice reportingDevice = new ReportingDevice(device); - reportingDevice.setMetadata( - OBJECT_MAPPER.readValue(metadataFile, ReportingDevice.Metadata.class)); - expectedDevices.put(device, reportingDevice); - } catch (Exception e) { - throw new RuntimeException("While loading device " + device, e); - } - } - System.out.println("Loaded " + expectedDevices.size() + " expected devices"); - } catch (Exception e) { - throw new RuntimeException( - "While loading devices directory " + devicesDir.getAbsolutePath(), e); - } - } - - private void setSchemaSpec(String schemaPath) { - File schemaFile = new File(schemaPath).getAbsoluteFile(); - if (schemaFile.isFile()) { - schemaRoot = schemaFile.getParentFile(); - schemaSpec = schemaFile.getName(); - } else if (schemaFile.isDirectory()) { - schemaRoot = schemaFile; - schemaSpec = null; - } else { - throw new RuntimeException("Schema directory/file not found: " + schemaFile); - } - } - - private void validatePubSub(String instName, String topicName) { - Map schemaMap = new TreeMap<>(); - for (File schemaFile : makeFileList(schemaRoot)) { - Schema schema = getSchema(schemaFile); - String fullName = schemaFile.getName(); - String schemaName = schemaFile.getName() - .substring(0, fullName.length() - JSON_SUFFIX.length()); - schemaMap.put(schemaName, schema); - } - if (!schemaMap.containsKey(ENVELOPE_SCHEMA_ID)) { - throw new RuntimeException("Missing schema for attribute validation: " + ENVELOPE_SCHEMA_ID); - } - dataSink = new FirestoreDataSink(); - System.out.println("Results will be uploaded to " + dataSink.getViewUrl()); - OUT_BASE_FILE.mkdirs(); - System.out.println("Also found in such directories as " + OUT_BASE_FILE.getAbsolutePath()); - System.out.println("Generating report file in " + METADATA_REPORT_FILE.getAbsolutePath()); - System.out.println("Connecting to pubsub topic " + topicName); - PubSubClient client = new PubSubClient(instName, topicName); - System.out.println("Entering pubsub message loop on " + client.getSubscriptionId()); - while(client.isActive()) { - try { - client.processMessage( - (message, attributes) -> validateMessage(schemaMap, message, attributes)); - } catch (Exception e) { - e.printStackTrace(); - } - } - System.out.println("Message loop complete"); - } - - private Set convertIgnoreSet(String ignoreSpec) { - if (ignoreSpec == null) { - return ImmutableSet.of(); - } - return Arrays.stream(ignoreSpec.split(",")).collect(Collectors.toSet()); - } - - private void validateMessage(Map schemaMap, Map message, - Map attributes) { - if (validateUpdate(schemaMap, message, attributes)) { - writeDeviceMetadataReport(); - } - } - - private boolean validateUpdate(Map schemaMap, Map message, - Map attributes) { - - String registryId = attributes.get(DEVICE_REGISTRY_ID_KEY); - if (cloudIotConfig != null && !cloudIotConfig.registry_id.equals(registryId)) { - // Silently drop messages for different registries. - return false; - } - - try { - String deviceId = attributes.get("deviceId"); - Preconditions.checkNotNull(deviceId, "Missing deviceId in message"); - - String schemaId = attributes.get("subFolder"); - - if (Strings.isNullOrEmpty(schemaId)) { - schemaId = UNKNOWN_SCHEMA_DEFAULT; - } - - if (!expectedDevices.isEmpty()) { - if (!processedDevices.add(deviceId)) { - return false; - } - System.out.println(String.format("Processing device #%d/%d: %s", - processedDevices.size(), expectedDevices.size(), deviceId)); - } - - if (attributes.get("wasBase64").equals("true")) { - base64Devices.add(deviceId); - } - - File deviceDir = new File(OUT_BASE_FILE, String.format(DEVICE_FILE_FORMAT, deviceId)); - deviceDir.mkdirs(); - - File attributesFile = new File(deviceDir, String.format(ATTRIBUTE_FILE_FORMAT, schemaId)); - OBJECT_MAPPER.writeValue(attributesFile, attributes); - - File messageFile = new File(deviceDir, String.format(MESSAGE_FILE_FORMAT, schemaId)); - OBJECT_MAPPER.writeValue(messageFile, message); - - File errorFile = new File(deviceDir, String.format(ERROR_FILE_FORMAT, schemaId)); - - final ReportingDevice reportingDevice = getReportingDevice(deviceId); - - try { - if (!schemaMap.containsKey(schemaId)) { - throw new IllegalArgumentException(String.format(SCHEMA_SKIP_FORMAT, schemaId, deviceId)); - } - } catch (Exception e) { - System.out.println(e.getMessage()); - OBJECT_MAPPER.writeValue(errorFile, e.getMessage()); - reportingDevice.addError(e); - } - - try { - validateMessage(schemaMap.get(ENVELOPE_SCHEMA_ID), attributes); - validateDeviceId(deviceId); - } catch (ExceptionMap | ValidationException e) { - processViolation(message, attributes, deviceId, ENVELOPE_SCHEMA_ID, attributesFile, errorFile, e); - reportingDevice.addError(e); - } - - if (schemaMap.containsKey(schemaId)) { - try { - validateMessage(schemaMap.get(schemaId), message); - dataSink.validationResult(deviceId, schemaId, attributes, message, null); - } catch (ExceptionMap | ValidationException e) { - processViolation(message, attributes, deviceId, schemaId, messageFile, errorFile, e); - reportingDevice.addError(e); - } - } - - boolean updated = false; - - if (expectedDevices.isEmpty()) { - // No devices configured, so don't check metadata. - updated = false; - } else if (expectedDevices.containsKey(deviceId)) { - try { - if (POINTSET_TYPE.equals(schemaId)) { - ReportingDevice.PointsetMessage pointsetMessage = - OBJECT_MAPPER.convertValue(message, ReportingDevice.PointsetMessage.class); - updated = !reportingDevice.hasBeenValidated(); - reportingDevice.validateMetadata(pointsetMessage); - } - } catch (Exception e) { - e.printStackTrace(); - OBJECT_MAPPER.writeValue(errorFile, e.getMessage()); - reportingDevice.addError(e); - } - } else if (extraDevices.add(deviceId)) { - updated = true; - } - - if (!reportingDevice.hasError()) { - System.out.println(String.format("Success validating %s/%s", deviceId, schemaId)); - } - - return updated; - } catch (Exception e){ - e.printStackTrace(); - return false; - } - } - - private ReportingDevice getReportingDevice(String deviceId) { - if (expectedDevices.containsKey(deviceId)) { - return expectedDevices.get(deviceId); - } else { - return new ReportingDevice(deviceId); - } - } - - private void writeDeviceMetadataReport() { - try { - MetadataReport metadataReport = new MetadataReport(); - metadataReport.updated = new Date(); - metadataReport.missingDevices = new TreeSet<>(); - metadataReport.extraDevices = extraDevices; - metadataReport.successfulDevices = new TreeSet<>(); - metadataReport.base64Devices = base64Devices; - metadataReport.expectedDevices = expectedDevices.keySet(); - metadataReport.errorDevices = new TreeMap<>(); - for (ReportingDevice deviceInfo : expectedDevices.values()) { - String deviceId = deviceInfo.getDeviceId(); - if (deviceInfo.hasMetadataDiff() || deviceInfo.hasError()) { - metadataReport.errorDevices.put(deviceId, deviceInfo.getMetadataDiff()); - } else if (deviceInfo.hasBeenValidated()) { - metadataReport.successfulDevices.add(deviceId); - } else { - metadataReport.missingDevices.add(deviceId); - } - } - OBJECT_MAPPER.writeValue(METADATA_REPORT_FILE, metadataReport); - } catch (Exception e) { - throw new RuntimeException("While generating metadata report file " + METADATA_REPORT_FILE.getAbsolutePath(), e); - } - } - - public static class MetadataReport { - public Date updated; - public Set expectedDevices; - public Set missingDevices; - public Set extraDevices; - public Set successfulDevices; - public Set base64Devices; - public Map errorDevices; - } - - private void processViolation(Map message, Map attributes, - String deviceId, String schemaId, File inputFile, File errorFile, RuntimeException e) - throws FileNotFoundException { - System.out.println("Error validating " + inputFile + ": " + e.getMessage()); - ErrorTree errorTree = ExceptionMap.format(e, ERROR_FORMAT_INDENT); - dataSink.validationResult(deviceId, schemaId, attributes, message, errorTree); - try (PrintStream errorOut = new PrintStream(errorFile)) { - errorTree.write(errorOut); - } - } - - private void validateDeviceId(String deviceId) { - if (!DEVICE_ID_PATTERN.matcher(deviceId).matches()) { - throw new ExceptionMap(String.format(DEVICE_MATCH_FORMAT, deviceId, DEVICE_ID_PATTERN.pattern())); - } - } - - private void validateFiles(String schemaSpec, String targetSpec) { - List schemaFiles = makeFileList(schemaSpec); - if (schemaFiles.size() == 0) { - throw new RuntimeException("Cowardly refusing to validate against zero schemas"); - } - List targetFiles = makeFileList(targetSpec); - if (targetFiles.size() == 0) { - throw new RuntimeException("Cowardly refusing to validate against zero targets"); - } - ExceptionMap schemaExceptions = new ExceptionMap( - String.format(SCHEMA_VALIDATION_FORMAT, schemaFiles.size())); - for (File schemaFile : schemaFiles) { - try { - Schema schema = getSchema(schemaFile); - ExceptionMap validateExceptions = new ExceptionMap( - String.format(TARGET_VALIDATION_FORMAT, targetFiles.size(), schemaFile.getName())); - for (File targetFile : targetFiles) { - try { - System.out.println("Validating " + targetFile.getName() + " against " + schemaFile.getName()); - validateFile(targetFile, schema); - } catch (Exception e) { - validateExceptions.put(targetFile.getName(), e); - } - } - validateExceptions.throwIfNotEmpty(); - } catch (Exception e) { - schemaExceptions.put(schemaFile.getName(), e); - } - } - schemaExceptions.throwIfNotEmpty(); - } - - private void validateFilesOutput(String targetSpec) { - try { - validateFiles(schemaSpec, targetSpec); - } catch (ExceptionMap | ValidationException processingException) { - ErrorTree errorTree = ExceptionMap.format(processingException, ERROR_FORMAT_INDENT); - errorTree.write(System.err); - throw processingException; - } - } - - private Schema getSchema(File schemaFile) { - try (InputStream schemaStream = new FileInputStream(schemaFile)) { - JSONObject rawSchema = new JSONObject(new JSONTokener(schemaStream)); - SchemaLoader loader = SchemaLoader.builder().schemaJson(rawSchema).httpClient(new RelativeClient()).build(); - return loader.load().build(); - } catch (Exception e) { - throw new RuntimeException("While loading schema " + schemaFile.getAbsolutePath(), e); - } - } - - class RelativeClient implements SchemaClient { - - public static final String FILE_URL_PREFIX = "file:"; - - @Override - public InputStream get(String url) { - try { - if (!url.startsWith(FILE_URL_PREFIX)) { - throw new IllegalStateException("Expected path to start with " + FILE_URL_PREFIX); - } - String new_url = FILE_URL_PREFIX + new File(schemaRoot, url.substring(FILE_URL_PREFIX.length())); - return (InputStream) (new URL(new_url)).getContent(); - } catch (Exception e) { - throw new RuntimeException("While loading URL " + url, e); - } - } - } - - private List makeFileList(String spec) { - return makeFileList(new File(spec)); - } - - private List makeFileList(File target) { - if (target.isFile()) { - return ImmutableList.of(target); - } - boolean isDir = target.isDirectory(); - String prefix = isDir ? "" : target.getName(); - File parent = isDir ? target : target.getAbsoluteFile().getParentFile(); - if (!parent.isDirectory()) { - throw new RuntimeException("Parent directory not found " + parent.getAbsolutePath()); - } - - FilenameFilter filter = (dir, file) -> file.startsWith(prefix) && file.endsWith(JSON_SUFFIX); - String[] fileNames = parent.list(filter); - - return Arrays.stream(fileNames).map(name -> new File(parent, name)) - .collect(Collectors.toList()); - } - - private void validateMessage(Schema schema, Object message) { - final String stringMessage; - try { - stringMessage = OBJECT_MAPPER.writeValueAsString(message); - } catch (Exception e) { - throw new RuntimeException("While converting to string", e); - } - schema.validate(new JSONObject(new JSONTokener(stringMessage))); - } - - private void validateFile(File targetFile, Schema schema) { - try (InputStream targetStream = new FileInputStream(targetFile)) { - schema.validate(new JSONObject(new JSONTokener(targetStream))); - } catch (Exception e) { - throw new RuntimeException("Against input " + targetFile, e); - } - } - - -} From bf366e0b470c5d1d8bfb939b229a3c53f05729a2 Mon Sep 17 00:00:00 2001 From: henry54809 Date: Mon, 20 Jul 2020 20:57:06 -0700 Subject: [PATCH 030/212] USI parsing logic fix (#547) --- usi/src/main/java/daq/usi/BaseSwitchController.java | 12 +++++++----- .../test/java/daq/usi/BaseSwitchControllerTest.java | 7 +++---- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/usi/src/main/java/daq/usi/BaseSwitchController.java b/usi/src/main/java/daq/usi/BaseSwitchController.java index 247930b298..5d1c3ef8f1 100644 --- a/usi/src/main/java/daq/usi/BaseSwitchController.java +++ b/usi/src/main/java/daq/usi/BaseSwitchController.java @@ -62,11 +62,11 @@ protected static HashMap mapSimpleTable( String rawPacket, String[] colNames, String[] mapNames) { HashMap colMap = new HashMap<>(); String[] lines = rawPacket.split("\n"); - if (lines.length > 0) { + if (lines.length >= 2) { String header = lines[0].trim(); String values = lines[1].trim(); int lastSectionEnd = 0; - for (int i = 0; i < colNames.length; ++i) { + for (int i = 0; i < colNames.length; i++) { int secStart = lastSectionEnd; int secEnd; if ((i + 1) >= colNames.length) { @@ -81,11 +81,13 @@ protected static HashMap mapSimpleTable( getIndexOfNonWhitespaceAfterWhitespace(values.substring(firstWhiteSpace)) + firstWhiteSpace; int nextHeaderStart = header.indexOf(colNames[i + 1]); - secEnd = Math.min(lastWhiteSpace, nextHeaderStart); + secEnd = Math.max(lastWhiteSpace, nextHeaderStart); } lastSectionEnd = secEnd; - String sectionRaw = values.substring(secStart, secEnd).trim(); - colMap.put(mapNames[i], sectionRaw); + // \u00A0 is non-breaking space which trim ignores. + String rawString = values.substring(secStart, secEnd) + .replace('\u00A0', ' ').trim(); + colMap.put(mapNames[i], rawString); } } return colMap; diff --git a/usi/src/test/java/daq/usi/BaseSwitchControllerTest.java b/usi/src/test/java/daq/usi/BaseSwitchControllerTest.java index 03a3ce8505..97e92c6403 100644 --- a/usi/src/test/java/daq/usi/BaseSwitchControllerTest.java +++ b/usi/src/test/java/daq/usi/BaseSwitchControllerTest.java @@ -40,7 +40,7 @@ void mapSimpleTableSampleInputAT() { "class", "0", "max", "15400 [C]"); Map response = BaseSwitchController.mapSimpleTable(raw, colNames, mapNames); for (String key : response.keySet()) { - assertEquals(response.get(key), expected.get(key)); + assertEquals(expected.get(key), response.get(key)); } } @@ -51,12 +51,11 @@ void mapSimpleTableSampleInputCisco9300() { String[] colNames = {"Port", "Name", "Status", "Vlan", "Duplex", "Speed", "Type"}; String[] mapNames = {"interface", "name", "status", "vlan", "duplex", "speed", "type"}; Map expected = Map.of("interface", "Gi1/0/1", "name", "", "status", - "Connected", "vlan", "routed", "Duplex", "a-full", "speed", "a-100", + "connected", "vlan", "routed", "duplex", "a-full", "speed", "a-100", "type", "10/100/1000BaseTX"); Map response = BaseSwitchController.mapSimpleTable(raw, colNames, mapNames); - System.out.println(response); for (String key : response.keySet()) { - assertEquals(response.get(key), expected.get(key)); + assertEquals(expected.get(key), response.get(key)); } } } \ No newline at end of file From 84c8b6fe6f47bd9fe7d27c1c4450dd91b4da3657 Mon Sep 17 00:00:00 2001 From: Trevor Date: Mon, 20 Jul 2020 23:29:09 -0700 Subject: [PATCH 031/212] Build check for updated deps (#549) --- cmd/build | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/cmd/build b/cmd/build index 834b1078a5..d9bdff7d86 100755 --- a/cmd/build +++ b/cmd/build @@ -128,7 +128,17 @@ target_commit=$(cd faucet; git rev-parse $target_version) if [ "$target_commit" != "$local_version" ]; then echo Local faucet commit is at: $local_version echo Mismatch with etc/FAUCET_VERSION: $target_version - echo Try 'bin/clean_dev && bin/setup_dev' to reset. + echo Try 'bin/setup_dev' to update. + false +fi + +local_version=$(cd udmi; git rev-list -n 1 HEAD) +target_version=$(cat etc/UDMI_VERSION) +target_commit=$(cd udmi; git rev-parse $target_version) +if [ "$target_commit" != "$local_version" ]; then + echo Local udmi commit is at: $local_version + echo Mismatch with etc/UDMI_VERSION: $target_version + echo Try 'bin/setup_dev' to update. false fi From 45942a4fbc20bf318005fc4ba398cc07bfcec702 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Jul 2020 01:21:34 -0700 Subject: [PATCH 032/212] Bump lodash from 4.17.15 to 4.17.19 in /firebase/functions (#538) --- firebase/functions/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/firebase/functions/package-lock.json b/firebase/functions/package-lock.json index 3d7970d0d1..222a41a665 100644 --- a/firebase/functions/package-lock.json +++ b/firebase/functions/package-lock.json @@ -1452,9 +1452,9 @@ } }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" }, "lodash.at": { "version": "4.6.0", From 5bc04f381efe335dfbb7eaf56d0a0e822e1feb18 Mon Sep 17 00:00:00 2001 From: Noureddine Date: Tue, 21 Jul 2020 12:47:04 +0100 Subject: [PATCH 033/212] add security.ssh.version test (#523) * ssh version test --- docker/include/bin/start_faux | 9 ++++++ docker/modules/Dockerfile.faux1 | 26 +++++++++++---- resources/test_site/module_config.json | 3 ++ subset/security/Dockerfile.test_ssh | 7 ++++ subset/security/build.conf | 1 + subset/security/readme.md | 8 +++++ subset/security/ssh_additions.config | 5 --- subset/security/sshfaux/ssh_build.sh | 28 ++++++++++++++++ subset/security/sshfaux/ssh_privsep.sh | 11 +++++++ subset/security/test_ssh | 44 ++++++++++++++++++++++++++ testing/test_aux.out | 6 ++++ testing/test_aux.sh | 4 +-- testing/test_modules.out | 6 ++++ testing/test_modules.sh | 3 ++ 14 files changed, 147 insertions(+), 14 deletions(-) create mode 100644 subset/security/Dockerfile.test_ssh delete mode 100644 subset/security/ssh_additions.config create mode 100644 subset/security/sshfaux/ssh_build.sh create mode 100644 subset/security/sshfaux/ssh_privsep.sh create mode 100755 subset/security/test_ssh diff --git a/docker/include/bin/start_faux b/docker/include/bin/start_faux index 911ef72415..ab6bb2c7b2 100755 --- a/docker/include/bin/start_faux +++ b/docker/include/bin/start_faux @@ -126,6 +126,15 @@ if [ -n "${options[telnet]}" ]; then (while true; do echo Telnet `hostname`; nc -nvlt -p 23 -e `which hostname`; done) & fi +if [ -n "${options[ssh]}" ]; then + echo Starting SSH server + /usr/local/sbin/sshd +elif [ -n "${options[sshv1]}" ]; then + echo Starting SSHv1 server + echo 'Protocol 1' >> /usr/local/etc/sshd_config + /usr/local/sbin/sshd +fi + if [ -n "${options[bacnet]}" ]; then echo Starting bacnet loop device. java -cp bacnetTests/build/libs/bacnet-1.0-SNAPSHOT-all.jar \ diff --git a/docker/modules/Dockerfile.faux1 b/docker/modules/Dockerfile.faux1 index 5789e8beb5..be9c483e0c 100644 --- a/docker/modules/Dockerfile.faux1 +++ b/docker/modules/Dockerfile.faux1 @@ -18,13 +18,23 @@ RUN bin/retry_cmd git clone https://github.com/grafnu/bacnet4j.git --single-bran COPY udmi/pubber/ pubber/ RUN pubber/bin/build +# Seperate stage to build older version of SSH and SSL +FROM daqf/aardvark:latest as ssh_build + +RUN $AG update && $AG install wget make build-essential gcc libz-dev ca-certificates + +# Build SSH, OpenSSL from source and configure + +COPY subset/security/sshfaux/*.sh ./ +RUN sh ssh_build.sh + FROM daqf/aardvark:latest # Run this separately so it can be shared with other builds. RUN $AG update && $AG install openjdk-8-jre RUN $AG update && $AG install openjdk-8-jdk git RUN $AG update && $AG install isc-dhcp-client ethtool network-manager netcat curl\ - python ifupdown openssl ssh nano apache2-utils ntpdate + python ifupdown openssl nano apache2-utils ntpdate # Additional OS dependencies RUN $AG update && $AG install -y telnetd && $AG install xinetd nginx @@ -52,17 +62,19 @@ COPY subset/bacnet/bacnetTests/src/main/resources/Faux*.json tmp/ COPY --from=java_build /root/bacnet4j/bacnet4j-1.0-SNAPSHOT-all.jar bacnetTests/libs/ RUN cd bacnetTests && ./gradlew build -# SSH dependency -COPY subset/security/ssh_additions.config ssh_additions.config -RUN cat ssh_additions.config >> /etc/ssh/sshd_config - # HTTP/HTTPS dependency COPY subset/security/nginxpass.conf /root/nginx/ COPY subset/security/nginxfail.conf /root/nginx/ COPY subset/security/nginx-site /var/www/nginx-site -# SSH login fix. Otherwise user is kicked off after login -RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd +COPY --from=ssh_build /usr/local/openssl/* /usr/local/openssl/ +COPY --from=ssh_build /usr/local/sbin/* /usr/local/sbin/ +COPY --from=ssh_build /usr/local/bin/* /usr/local/bin/ +COPY --from=ssh_build /usr/local/etc/* /usr/local/etc/ + +COPY subset/security/sshfaux/ssh_privsep.sh ssh_privsep.sh +RUN sh ssh_privsep.sh +RUN /usr/local/bin/ssh-keygen -A # Weird workaround for problem running tcdump in a privlidged container. RUN mv /usr/sbin/tcpdump /usr/bin/tcpdump diff --git a/resources/test_site/module_config.json b/resources/test_site/module_config.json index 3ff4030a4c..ac17f224b1 100644 --- a/resources/test_site/module_config.json +++ b/resources/test_site/module_config.json @@ -20,6 +20,9 @@ }, "ntp": { "enabled": true + }, + "ssh": { + "enabled": false } }, "process": { diff --git a/subset/security/Dockerfile.test_ssh b/subset/security/Dockerfile.test_ssh new file mode 100644 index 0000000000..aa701b5550 --- /dev/null +++ b/subset/security/Dockerfile.test_ssh @@ -0,0 +1,7 @@ +FROM daqf/aardvark:latest + +RUN $AG update && $AG install nmap + +COPY subset/security/test_ssh . + +CMD ./test_ssh diff --git a/subset/security/build.conf b/subset/security/build.conf index 763d155e46..26876f4343 100644 --- a/subset/security/build.conf +++ b/subset/security/build.conf @@ -1,3 +1,4 @@ build subset/security add tls add password +add ssh diff --git a/subset/security/readme.md b/subset/security/readme.md index a5f65cf277..2143155dc0 100644 --- a/subset/security/readme.md +++ b/subset/security/readme.md @@ -43,3 +43,11 @@ The functional test code is included in the `tlstest/src/main/java` folder. - pass -> If the device responds to a connection with TLS 1.3 support and provides a valid certificate. - fail -> If the device responds to a connection with TLS 1.3 support and provides an invalid certificate. - skip -> If no connection to the device can be established. + +## test_ssh +The SSH test will check that if a device has an SSH server, this only supports SSHv2 + +### Conditions for seucrity.ssh.version +- pass -> If the device runs an SSH server which only supports SSHv2 +- fail -> If the device runs an SSH server which supports SSHv1 +- skip -> If the device does not run an SSH server \ No newline at end of file diff --git a/subset/security/ssh_additions.config b/subset/security/ssh_additions.config deleted file mode 100644 index 7e8895f7c9..0000000000 --- a/subset/security/ssh_additions.config +++ /dev/null @@ -1,5 +0,0 @@ -Port 22 -ListenAddress 0.0.0.0 -PermitRootLogin yes -PasswordAuthentication yes -KexAlgorithms diffie-hellman-group1-sha1,diffie-hellman-group-exchange-sha1 diff --git a/subset/security/sshfaux/ssh_build.sh b/subset/security/sshfaux/ssh_build.sh new file mode 100644 index 0000000000..f870555f1d --- /dev/null +++ b/subset/security/sshfaux/ssh_build.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# +# Build older versions OpenSSL 1.0.2 and OpenSSH 7.2 +# Used for testing in faux devices only +# +# To run SSHD use /usr/local/sbin/sshd +# SSH components, e.g. ssh-keygen are found in /usr/local/bin +# SSH configuration and keys found in /usr/local/etc + +# Build OpenSSL 1.0.2 +wget https://www.openssl.org/source/openssl-1.0.2g.tar.gz +tar -xzf openssl-1.0.2g.tar.gz +cd openssl-1.0.2g +./config --prefix=/usr/local/openssl --openssldir=/usr/local/openssl +make -s +make -s install +cd .. + +# Prepare privellage seperation for SSHD +source ssh_privsep.sh + +# Build OpenSSH 7.2 +wget https://mirrors.mit.edu/pub/OpenBSD/OpenSSH/portable/openssh-7.2p1.tar.gz +tar -xzf openssh-7.2p1.tar.gz +cd openssh-7.2p1 +./configure --with-ssl-dir=/usr/local/openssl --with-ssh1 +make -s +make -s install diff --git a/subset/security/sshfaux/ssh_privsep.sh b/subset/security/sshfaux/ssh_privsep.sh new file mode 100644 index 0000000000..668d825f9e --- /dev/null +++ b/subset/security/sshfaux/ssh_privsep.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# +# Prepare environment for running SSHD with privilege separation +# https://github.com/openssh/openssh-portable/blob/master/README.privsep + +mkdir /etc/ssh +mkdir /var/empty +chown root:sys /var/empty +chmod 755 /var/empty +groupadd sshd +useradd -g sshd -c 'sshd privsep' -d /var/empty -s /bin/false sshd diff --git a/subset/security/test_ssh b/subset/security/test_ssh new file mode 100755 index 0000000000..e1af63282c --- /dev/null +++ b/subset/security/test_ssh @@ -0,0 +1,44 @@ +#!/bin/bash +# +# Checks if a device only support SSHv2 +# Runs NMAP to check if SSH is available +# Uses the 'sshv_1' nmap script to check if the server supports SSHv1 + +source reporting.sh + +TEST_NAME="security.ssh.version" +TEST_DESCRIPTION="Check that device only support SSHv2" +REPORT=/tmp/report.txt +LOG=/tmp/nmap_log.txt + +nmap -sV -sC $TARGET_IP > $LOG + +nmap_log=$(cat $LOG ) + +sshv1=$(grep 'sshv1: Server supports SSHv1' $LOG) + +if [[ -z "${sshv1}" ]]; then + #No SSHv1, but is there an SSHv2 server running ? + sshv2=$(grep -P '^\d+\/tcp\s+open ssh.*protocol 2.0\)$' $LOG) + + if [[ -z "${sshv2}" ]]; then + test_outcome="skip" + test_summary="Device is not running an SSH server" + else + test_outcome="pass" + test_summary="Device only supports SSHv2" + fi + +else + test_outcome="fail" + test_summary="Device supports SSHv1" +fi + +result_and_summary="RESULT ${test_outcome} ${TEST_NAME} ${test_summary}" + +write_out_result $REPORT \ + "$TEST_NAME" \ + "$TEST_DESCRIPTION" \ + "$sshv2" \ + "$result_and_summary" + \ No newline at end of file diff --git a/testing/test_aux.out b/testing/test_aux.out index b46c806282..75933922ee 100644 --- a/testing/test_aux.out +++ b/testing/test_aux.out @@ -126,6 +126,9 @@ port-01 module_config modules "password": { "enabled": true }, + "ssh": { + "enabled": false + }, "switch": { "enabled": true, "poe": { @@ -187,6 +190,9 @@ port-02 module_config modules "password": { "enabled": true }, + "ssh": { + "enabled": false + }, "switch": { "enabled": true }, diff --git a/testing/test_aux.sh b/testing/test_aux.sh index 7dc587088d..94a12f8612 100755 --- a/testing/test_aux.sh +++ b/testing/test_aux.sh @@ -65,9 +65,9 @@ interfaces: faux-1: opts: brute broadcast_client ntpv4 faux-2: - opts: nobrute expiredtls bacnetfail pubber passwordfail ntpv3 opendns + opts: nobrute expiredtls bacnetfail pubber passwordfail ntpv3 opendns ssh faux-3: - opts: tls macoui passwordpass bacnet pubber broadcast_client + opts: tls macoui passwordpass bacnet pubber broadcast_client ssh long_dhcp_response_sec: 0 monitor_scan_sec: 20 EOF diff --git a/testing/test_modules.out b/testing/test_modules.out index ff067a6826..f0c130ddd3 100644 --- a/testing/test_modules.out +++ b/testing/test_modules.out @@ -31,4 +31,10 @@ Testing nmap bacnet RESULT pass security.ports.nmap Only allowed ports found open. Testing nmap telnet RESULT fail security.ports.nmap Some disallowed ports are open: 23 +Testing ssh +RESULT skip security.ssh.version Device is not running an SSH server +Testing ssh ssh +RESULT pass security.ssh.version Device only supports SSHv2 +Testing ssh sshv1 +RESULT fail security.ssh.version Device supports SSHv1 Testing complete. diff --git a/testing/test_modules.sh b/testing/test_modules.sh index bc123230e1..f703b75c77 100755 --- a/testing/test_modules.sh +++ b/testing/test_modules.sh @@ -17,6 +17,9 @@ tls alt expiredtls nmap nmap bacnet nmap telnet +ssh +ssh ssh +ssh sshv1 EOF DAQ_TARGETS=aardvark,faux1,faux2 bin/docker_build force inline From ec5151f4c336c37d79851d8f58fe272dc102ed62 Mon Sep 17 00:00:00 2001 From: pbatta Date: Tue, 21 Jul 2020 07:34:38 -0700 Subject: [PATCH 034/212] Move ntp test to monitor pcap to reduce flakiness (#546) --- docker/include/bin/start_faux | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docker/include/bin/start_faux b/docker/include/bin/start_faux index ab6bb2c7b2..d00bacc623 100755 --- a/docker/include/bin/start_faux +++ b/docker/include/bin/start_faux @@ -145,7 +145,9 @@ elif [ -n "${options[bacnetfail]}" ]; then FauxDeviceEngine.EntryPoint $local_ip $broadcast_ip "Faux-Device-Fail.json" & fi -# Queries the NTP server learnt from DHCP. +# NTPv4 query to the NTP server learnt from DHCP. +# NTPv3 query to the IP of time.google.com (since resolv.conf is modified by other tests) +STATIC_NTP_SERVER=216.239.35.8 if [ -n "${options[ntpv4]}" ]; then (while date; do dhcp_ntp=$(fgrep NTPSERVERS= /run/ntpdate.dhcp) @@ -156,8 +158,8 @@ if [ -n "${options[ntpv4]}" ]; then done) & elif [ -n "${options[ntpv3]}" ]; then (while date; do - echo Transmitting NTP query to time.google.com using NTPv3 - ntpdate -q -o 3 time.google.com + echo Transmitting NTP query to $STATIC_NTP_SERVER using NTPv3 + ntpdate -q -o 3 $STATIC_NTP_SERVER sleep 5 done) & fi From f63be9d5839734db6a80c36310352b913e729737 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Jul 2020 08:15:32 -0700 Subject: [PATCH 035/212] Update dependency gradle to v6.5.1 (#518) --- mudacl/gradle/wrapper/gradle-wrapper.properties | 2 +- .../bacnet/bacnetTests/gradle/wrapper/gradle-wrapper.properties | 2 +- .../connection/mac_oui/gradle/wrapper/gradle-wrapper.properties | 2 +- .../network/NTPClient/gradle/wrapper/gradle-wrapper.properties | 2 +- .../security_passwords/gradle/wrapper/gradle-wrapper.properties | 2 +- .../security/tlstest/gradle/wrapper/gradle-wrapper.properties | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mudacl/gradle/wrapper/gradle-wrapper.properties b/mudacl/gradle/wrapper/gradle-wrapper.properties index 16871c71a0..af94776b0b 100644 --- a/mudacl/gradle/wrapper/gradle-wrapper.properties +++ b/mudacl/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-all.zip diff --git a/subset/bacnet/bacnetTests/gradle/wrapper/gradle-wrapper.properties b/subset/bacnet/bacnetTests/gradle/wrapper/gradle-wrapper.properties index 622ab64a3c..bb8b2fc26b 100644 --- a/subset/bacnet/bacnetTests/gradle/wrapper/gradle-wrapper.properties +++ b/subset/bacnet/bacnetTests/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/subset/connection/mac_oui/gradle/wrapper/gradle-wrapper.properties b/subset/connection/mac_oui/gradle/wrapper/gradle-wrapper.properties index 38c1d48d19..8db0d0d953 100644 --- a/subset/connection/mac_oui/gradle/wrapper/gradle-wrapper.properties +++ b/subset/connection/mac_oui/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-bin.zip diff --git a/subset/network/NTPClient/gradle/wrapper/gradle-wrapper.properties b/subset/network/NTPClient/gradle/wrapper/gradle-wrapper.properties index 622ab64a3c..bb8b2fc26b 100644 --- a/subset/network/NTPClient/gradle/wrapper/gradle-wrapper.properties +++ b/subset/network/NTPClient/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/subset/security/security_passwords/gradle/wrapper/gradle-wrapper.properties b/subset/security/security_passwords/gradle/wrapper/gradle-wrapper.properties index b727a41d73..da978e4ae9 100755 --- a/subset/security/security_passwords/gradle/wrapper/gradle-wrapper.properties +++ b/subset/security/security_passwords/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-all.zip diff --git a/subset/security/tlstest/gradle/wrapper/gradle-wrapper.properties b/subset/security/tlstest/gradle/wrapper/gradle-wrapper.properties index 622ab64a3c..bb8b2fc26b 100644 --- a/subset/security/tlstest/gradle/wrapper/gradle-wrapper.properties +++ b/subset/security/tlstest/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 2bde09ee341427173c87dd41b4ff60ce528e1f8f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Jul 2020 08:16:07 -0700 Subject: [PATCH 036/212] Update dependency @google-cloud/pubsub to v2.2.0 (#527) --- firebase/functions/package-lock.json | 63 ++++++++++++++-------------- firebase/functions/package.json | 2 +- 2 files changed, 32 insertions(+), 33 deletions(-) diff --git a/firebase/functions/package-lock.json b/firebase/functions/package-lock.json index 222a41a665..a4318bae57 100644 --- a/firebase/functions/package-lock.json +++ b/firebase/functions/package-lock.json @@ -119,9 +119,9 @@ } }, "@google-cloud/precise-date": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@google-cloud/precise-date/-/precise-date-2.0.1.tgz", - "integrity": "sha512-uXrLK/1rYx6pWNHL5U8NurHwmqLX7CwDFuJtRoaZe9lhe8RU7AJS67CMsMvHB0OziCcBAiKdAFzHm9zljI2nKQ==" + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@google-cloud/precise-date/-/precise-date-2.0.2.tgz", + "integrity": "sha512-eEnWN8vzy4Gji9dOlcr8rsX0Oz52eI6ZZZj0AIrUbqTXM8JFPqKzx53DpWIYuXW6c8AfiyY1txjOsg1cXvsoyQ==" }, "@google-cloud/projectify": { "version": "1.0.4", @@ -136,9 +136,9 @@ "optional": true }, "@google-cloud/pubsub": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@google-cloud/pubsub/-/pubsub-2.1.0.tgz", - "integrity": "sha512-9k4ucPR4X9/BKu1ht9RfXAqGpQzLZOGYpGgoq9Cnxhp9SDjAXkgIKN02pYCXZDdoLng25Mf+xkMnc3AfzJimnA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@google-cloud/pubsub/-/pubsub-2.2.0.tgz", + "integrity": "sha512-HOG6LbajfPgZPWEIEFz7TAjEa3OUJsksmtFCRyknnSY1fX4eKVvDq0PP2SSNe0HbG9WdfsJGOEfhCW1fOdqvKw==", "requires": { "@google-cloud/paginator": "^3.0.0", "@google-cloud/precise-date": "^2.0.0", @@ -157,18 +157,18 @@ }, "dependencies": { "@google-cloud/paginator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-3.0.0.tgz", - "integrity": "sha512-iPdxTujlZQlMGNLHPtYoVwRu8IuLFr6y0GJwsX9hKULMgqGXrP/z0MV4ROGpRAkNE1FIfa1aDfNlwZHfF2z4bQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-3.0.2.tgz", + "integrity": "sha512-kXK+Dbz4pNvv8bKU80Aw5HsIdgOe0WuMTd8/fI6tkANUxzvJOVJQQRsWVqcHSWK2RXHPTA9WBniUCwY6gAJDXw==", "requires": { "arrify": "^2.0.0", "extend": "^3.0.2" } }, "@google-cloud/projectify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-2.0.0.tgz", - "integrity": "sha512-7wZ+m4N3Imtb5afOPfqNFyj9cKrlfVQ+t5YRxLS7tUpn8Pn/i7QuVubZRTXllaWjO4T5t/gm/r2x7oy5ajjvFQ==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-2.0.1.tgz", + "integrity": "sha512-ZDG38U/Yy6Zr21LaR3BTiiLtpJl6RkPS/JwoRT453G+6Q1DhlV0waNf8Lfu+YVYGIIxgKnLayJRfYlFJfiI8iQ==" }, "@google-cloud/promisify": { "version": "2.0.1", @@ -176,18 +176,17 @@ "integrity": "sha512-82EQzwrNauw1fkbUSr3f+50Bcq7g4h0XvLOk8C5e9ABkXYHei7ZPi9tiMMD7Vh3SfcdH97d1ibJ3KBWp2o1J+w==" }, "@grpc/grpc-js": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.0.4.tgz", - "integrity": "sha512-Qawt6HUrEmljQMPWnLnIXpcjelmtIAydi3M9awiG02WWJ1CmIvFEx4IOC1EsWUWUlabOGksRbpfvoIeZKFTNXw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.1.2.tgz", + "integrity": "sha512-k2u86Bkm/3xrjUaSWeIyzXScBt/cC8uE7BznR0cpueQi11R33W6qfJdMrkrsmSHirp5likR55JSXUrcWG6ybHA==", "requires": { - "google-auth-library": "^6.0.0", "semver": "^6.2.0" } }, "gaxios": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.0.3.tgz", - "integrity": "sha512-PkzQludeIFhd535/yucALT/Wxyj/y2zLyrMwPcJmnLHDugmV49NvAi/vb+VUq/eWztATZCNcb8ue+ywPG+oLuw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.0.4.tgz", + "integrity": "sha512-97NmFuMETFQh6gqPUxkqjxRMjmY8aRKRMphIkgO/b90AbCt5wAVuXsp8oWjIXlLN2pIK/fsXD8edcM7ULkFMLg==", "requires": { "abort-controller": "^3.0.0", "extend": "^3.0.2", @@ -206,9 +205,9 @@ } }, "google-auth-library": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.0.1.tgz", - "integrity": "sha512-NWEM9W0o+fmUJMK/wEuJ1vAc8H/JAseOWB8tjOAAkz8yobU+5IDtO/rPCbbRwFF1obIOCe0lj1pkq9ld2OFZeg==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.0.4.tgz", + "integrity": "sha512-O1uT4F1mMu5OYnvH0ppg6mqP5pGQrqzg2nrzd7ay3DA+VD0mp9VM+Julf/bov2OuxgFs2DD+gWnp2nZPB4EflA==", "requires": { "arrify": "^2.0.0", "base64-js": "^1.3.0", @@ -222,11 +221,11 @@ } }, "google-gax": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-2.5.0.tgz", - "integrity": "sha512-Xqh+rinq93qSGOcs5aQdlrwBUR+/9AaFArLCvSGnx7Mye9p4u0dC98r2TO7wB4m1W138Swd6UPYGQyBg9BM/4g==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-2.6.3.tgz", + "integrity": "sha512-hqY6H53Qmaku8rE8dGAM89RSUc1nc4JYG81whrVJRmDQZ2jhJK8AwCd3pJQ3V48rgp9xiWBzBQsyeaxnb3Eikw==", "requires": { - "@grpc/grpc-js": "~1.0.0", + "@grpc/grpc-js": "~1.1.1", "@grpc/proto-loader": "^0.5.1", "@types/long": "^4.0.0", "abort-controller": "^3.0.0", @@ -265,17 +264,17 @@ } }, "google-p12-pem": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.1.tgz", - "integrity": "sha512-VlQgtozgNVVVcYTXS36eQz4PXPt9gIPqLOhHN0QiV6W6h4qSCNVKPtKC5INtJsaHHF2r7+nOIa26MJeJMTaZEQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.2.tgz", + "integrity": "sha512-tbjzndQvSIHGBLzHnhDs3cL4RBjLbLXc2pYvGH+imGVu5b4RMAttUTdnmW2UH0t11QeBTXZ7wlXPS7hrypO/tg==", "requires": { "node-forge": "^0.9.0" } }, "gtoken": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.1.tgz", - "integrity": "sha512-33w4FNDkUcyIOq/TqyC+drnKdI4PdXmWp9lZzssyEQKuvu9ZFN3KttaSnDKo52U3E51oujVGop93mKxmqO8HHg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.2.tgz", + "integrity": "sha512-lull70rHCTvRTmAt+R/6W5bTtx4MjHku7AwJwK5fGqhOmygcZud0nrZcX+QUNfBJwCzqy7S5i1Bc4NYnr5PMMA==", "requires": { "gaxios": "^3.0.0", "google-p12-pem": "^3.0.0", diff --git a/firebase/functions/package.json b/firebase/functions/package.json index f2d7964c9c..df0e8e92e7 100644 --- a/firebase/functions/package.json +++ b/firebase/functions/package.json @@ -12,7 +12,7 @@ "node": "10" }, "dependencies": { - "@google-cloud/pubsub": "2.1.0", + "@google-cloud/pubsub": "2.2.0", "@google-cloud/iot": "1.8.0", "firebase-admin": "8.12.1", "firebase-functions": "3.7.0", From cc715744dac7dc9dc3f7989d28b3e96652bfeb51 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Jul 2020 08:16:40 -0700 Subject: [PATCH 037/212] Update dependency com.github.jengelman.gradle.plugins:shadow to v6 (#483) --- mudacl/build.gradle | 2 +- subset/connection/mac_oui/build.gradle | 2 +- subset/security/security_passwords/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mudacl/build.gradle b/mudacl/build.gradle index 13f3fd4017..0246b206a0 100644 --- a/mudacl/build.gradle +++ b/mudacl/build.gradle @@ -5,7 +5,7 @@ buildscript { } } dependencies { - classpath "com.github.jengelman.gradle.plugins:shadow:5.2.0" + classpath "com.github.jengelman.gradle.plugins:shadow:6.0.0" } } diff --git a/subset/connection/mac_oui/build.gradle b/subset/connection/mac_oui/build.gradle index 476315bb29..0f0dc95fe6 100644 --- a/subset/connection/mac_oui/build.gradle +++ b/subset/connection/mac_oui/build.gradle @@ -3,7 +3,7 @@ buildscript { jcenter() } dependencies { - classpath "com.github.jengelman.gradle.plugins:shadow:5.2.0" + classpath "com.github.jengelman.gradle.plugins:shadow:6.0.0" } } diff --git a/subset/security/security_passwords/build.gradle b/subset/security/security_passwords/build.gradle index 942946cd45..d82a3535c6 100755 --- a/subset/security/security_passwords/build.gradle +++ b/subset/security/security_passwords/build.gradle @@ -3,7 +3,7 @@ buildscript { jcenter() } dependencies { - classpath "com.github.jengelman.gradle.plugins:shadow:5.2.0" + classpath "com.github.jengelman.gradle.plugins:shadow:6.0.0" } } apply plugin: 'com.github.johnrengelman.shadow' From 07b70d1cc65234b1c5b59e324ba4a379ead0221e Mon Sep 17 00:00:00 2001 From: Trevor Date: Tue, 21 Jul 2020 09:05:16 -0700 Subject: [PATCH 038/212] USI not to use background shell (#548) --- bin/physical_sec | 3 +++ cmd/exrun | 3 +-- cmd/usi | 18 +++++-------- config/system/default.yaml | 3 +++ daq/host.py | 11 ++++++++ firebase/public/protos.hash | 2 +- firebase/public/protos.html | 4 +-- libs/proto/system_config_pb2.py | 26 +++++++++---------- libs/proto/usi_pb2.py | 26 +++++++------------ proto/system_config.proto | 4 +-- .../main/java/daq/usi/ovs/OpenVSwitch.java | 2 +- .../resources/{ovs_output.txt => src.ofctl} | 0 12 files changed, 53 insertions(+), 49 deletions(-) rename usi/src/test/resources/{ovs_output.txt => src.ofctl} (100%) diff --git a/bin/physical_sec b/bin/physical_sec index 82463e474d..939d6c4d5c 100755 --- a/bin/physical_sec +++ b/bin/physical_sec @@ -119,6 +119,9 @@ else sudo ip addr flush dev $ext_ctrl fi +echo Warmup ping for $ext_addr +ping -n -c 2 $ext_addr || true + echo Checking external connection to $ext_addr if ! ping -n -c 2 $ext_addr; then echo diff --git a/cmd/exrun b/cmd/exrun index da511d373f..37cfc401fc 100755 --- a/cmd/exrun +++ b/cmd/exrun @@ -82,8 +82,7 @@ sudo rm -f $cleanup_file function autostart { tmp=`mktemp` echo DAQ autostart $@ - eval $@ > $tmp # Don't use "eval $@ | tee $tmp" here; breaks cmd/usi. - cat $tmp + eval $@ | tee $tmp grep -e '^\s*DAQ autoclean\s' $tmp >> $cleanup_file || true } diff --git a/cmd/usi b/cmd/usi index fe39673d89..79fa946d9a 100755 --- a/cmd/usi +++ b/cmd/usi @@ -1,18 +1,12 @@ #!/bin/bash -e -TMP_DIR=/tmp/usi -function dump_ovs_interfaces { - while true; do - sudo ovs-ofctl show sec > $TMP_DIR/ovs_output.txt || true - sleep 5 - done -} +ROOT=$(realpath $(dirname $0)/..) +USI_DIR=$ROOT/inst/network echo Starting USI -mkdir -p $TMP_DIR -dump_ovs_interfaces & -PID=$! -docker run -d -v /tmp/usi:/ovs --privileged --network=host --name daq-usi daqf/usi + +rm -rf $USI_DIR +mkdir -p $USI_DIR +docker run -d -v $USI_DIR:/ovs --privileged --network=host --name daq-usi daqf/usi echo DAQ autoclean docker kill daq-usi -echo DAQ autoclean kill $PID diff --git a/config/system/default.yaml b/config/system/default.yaml index 67daa36ba0..ad6eb37ed8 100644 --- a/config/system/default.yaml +++ b/config/system/default.yaml @@ -38,6 +38,9 @@ long_dhcp_response_sec: 105 # finish hook: executed at the end of every test finish_hook: bin/dump_network +# topology hook: executed when device topology changes +topology_hook: bin/dump_network + # usi url for DAQ to connect to usi_setup: url: localhost:5000 diff --git a/daq/host.py b/daq/host.py index ee1e1a7e21..bea977cac0 100644 --- a/daq/host.py +++ b/daq/host.py @@ -70,6 +70,7 @@ class ConnectedHost: _STARTUP_MIN_TIME_SEC = 5 _INST_DIR = "inst/" _DEVICE_PATH = "device/%s" + _NETWORK_DIR = "inst/network" _MODULE_CONFIG = "module_config.json" _CONTROL_PATH = "control/port-%s" _CORE_TESTS = ['pass', 'fail', 'ping', 'hold'] @@ -107,6 +108,7 @@ def __init__(self, runner, gateway, target, config): _default_timeout_sec = int(config.get('default_timeout_sec', 0)) self._default_timeout_sec = _default_timeout_sec if _default_timeout_sec else None self._finish_hook_script = config.get('finish_hook') + self._topology_hook_script = config.get('topology_hook') self._usi_url = config.get('usi_setup', {}).get('url') self._mirror_intf_name = None self._monitor_ref = None @@ -262,6 +264,7 @@ def initialize(self): self._initialize_config() network = self.runner.network self._mirror_intf_name = network.create_mirror_interface(self.target_port) + self._topology_hook() if self.config['test_list']: self._start_run() else: @@ -708,6 +711,14 @@ def _finish_hook(self): os.system('%s %s 2>&1 > %s/finish.out' % (self._finish_hook_script, finish_dir, finish_dir)) + def _topology_hook(self): + if self._topology_hook_script: + update_dir = self._NETWORK_DIR + self.logger.info('Executing topology_hook: %s %s', + self._topology_hook_script, update_dir) + os.system('%s %s 2>&1 > %s/update.out' % + (self._topology_hook_script, update_dir, update_dir)) + def _module_callback(self, return_code=None, exception=None): host_name = self._host_name() self.logger.info('Host callback %s/%s was %s with %s', diff --git a/firebase/public/protos.hash b/firebase/public/protos.hash index 786633c8a9..4aac4f8d1a 100644 --- a/firebase/public/protos.hash +++ b/firebase/public/protos.hash @@ -1 +1 @@ -b335b4bd73bb5242e822a9b72cf4de6bd010cea3 proto/system_config.proto +fcc9343150752d10ac303fde1caa833d19b0c263 proto/system_config.proto diff --git a/firebase/public/protos.html b/firebase/public/protos.html index 13290969b0..3e00a26efd 100644 --- a/firebase/public/protos.html +++ b/firebase/public/protos.html @@ -434,10 +434,10 @@

        DaqConfig

        - fail_hook + topology_hook string -

        Hook for failure diagnostics.

        +

        Hook for device topology updates.

        diff --git a/libs/proto/system_config_pb2.py b/libs/proto/system_config_pb2.py index d82945d1c4..99063d996d 100644 --- a/libs/proto/system_config_pb2.py +++ b/libs/proto/system_config_pb2.py @@ -18,7 +18,7 @@ package='', syntax='proto3', serialized_options=None, - serialized_pb=b'\n\x1d\x64\x61q/proto/system_config.proto\"\x99\x08\n\tDaqConfig\x12\x18\n\x10site_description\x18\x01 \x01(\t\x12\x18\n\x10monitor_scan_sec\x18\x02 \x01(\x05\x12\x1b\n\x13\x64\x65\x66\x61ult_timeout_sec\x18\x03 \x01(\x05\x12\x12\n\nsettle_sec\x18& \x01(\x05\x12\x11\n\tbase_conf\x18\x04 \x01(\t\x12\x11\n\tsite_path\x18\x05 \x01(\t\x12\x1f\n\x17initial_dhcp_lease_time\x18\x06 \x01(\t\x12\x17\n\x0f\x64hcp_lease_time\x18\x07 \x01(\t\x12\x19\n\x11\x64hcp_response_sec\x18\' \x01(\x05\x12\x1e\n\x16long_dhcp_response_sec\x18\x08 \x01(\x05\x12\"\n\x0cswitch_setup\x18\t \x01(\x0b\x32\x0c.SwitchSetup\x12\x12\n\nhost_tests\x18\x10 \x01(\t\x12\x13\n\x0b\x62uild_tests\x18$ \x01(\x08\x12\x11\n\trun_limit\x18\x11 \x01(\x05\x12\x11\n\tfail_mode\x18\x12 \x01(\x08\x12\x13\n\x0bsingle_shot\x18\" \x01(\x08\x12\x15\n\rresult_linger\x18\x13 \x01(\x08\x12\x0f\n\x07no_test\x18\x14 \x01(\x08\x12\x11\n\tkeep_hold\x18( \x01(\x08\x12\x14\n\x0c\x64\x61q_loglevel\x18\x15 \x01(\t\x12\x18\n\x10mininet_loglevel\x18\x16 \x01(\t\x12\x13\n\x0b\x66inish_hook\x18# \x01(\t\x12\x10\n\x08gcp_cred\x18\x17 \x01(\t\x12\x11\n\tgcp_topic\x18\x18 \x01(\t\x12\x13\n\x0bschema_path\x18\x19 \x01(\t\x12\x11\n\tmud_files\x18\x1a \x01(\t\x12\x14\n\x0c\x64\x65vice_specs\x18\x1b \x01(\t\x12\x13\n\x0btest_config\x18\x1c \x01(\t\x12\x19\n\x11port_debounce_sec\x18\x1d \x01(\x05\x12\x11\n\tfail_hook\x18\x1e \x01(\t\x12\x17\n\x0f\x64\x65vice_template\x18\x1f \x01(\t\x12\x14\n\x0csite_reports\x18 \x01(\t\x12\x1f\n\x17run_data_retention_days\x18! \x01(\x02\x12.\n\ninterfaces\x18% \x03(\x0b\x32\x1a.DaqConfig.InterfacesEntry\x12/\n\x0b\x66\x61il_module\x18/ \x03(\x0b\x32\x1a.DaqConfig.FailModuleEntry\x12\x1d\n\x15port_flap_timeout_sec\x18\x30 \x01(\x05\x12\x1c\n\tusi_setup\x18\x31 \x01(\x0b\x32\t.USISetup\x1a=\n\x0fInterfacesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x19\n\x05value\x18\x02 \x01(\x0b\x32\n.Interface:\x02\x38\x01\x1a\x31\n\x0f\x46\x61ilModuleEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x17\n\x08USISetup\x12\x0b\n\x03url\x18\x01 \x01(\t\"\xf4\x01\n\x0bSwitchSetup\x12\x11\n\tctrl_intf\x18\t \x01(\t\x12\x0f\n\x07ip_addr\x18\x0b \x01(\t\x12\x13\n\x0buplink_port\x18\r \x01(\x05\x12\x0f\n\x07lo_port\x18\x0e \x01(\x05\x12\x10\n\x08\x61lt_port\x18\x10 \x01(\x05\x12\x0f\n\x07lo_addr\x18\x12 \x01(\t\x12\x11\n\tmods_addr\x18\x14 \x01(\t\x12\x0f\n\x07of_dpid\x18) \x01(\t\x12\x11\n\tdata_intf\x18* \x01(\t\x12\x0e\n\x06\x65xt_br\x18+ \x01(\t\x12\r\n\x05model\x18, \x01(\t\x12\x10\n\x08username\x18- \x01(\t\x12\x10\n\x08password\x18. \x01(\t\"\'\n\tInterface\x12\x0c\n\x04opts\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05\x62\x06proto3' + serialized_pb=b'\n\x1d\x64\x61q/proto/system_config.proto\"\x9d\x08\n\tDaqConfig\x12\x18\n\x10site_description\x18\x01 \x01(\t\x12\x18\n\x10monitor_scan_sec\x18\x02 \x01(\x05\x12\x1b\n\x13\x64\x65\x66\x61ult_timeout_sec\x18\x03 \x01(\x05\x12\x12\n\nsettle_sec\x18& \x01(\x05\x12\x11\n\tbase_conf\x18\x04 \x01(\t\x12\x11\n\tsite_path\x18\x05 \x01(\t\x12\x1f\n\x17initial_dhcp_lease_time\x18\x06 \x01(\t\x12\x17\n\x0f\x64hcp_lease_time\x18\x07 \x01(\t\x12\x19\n\x11\x64hcp_response_sec\x18\' \x01(\x05\x12\x1e\n\x16long_dhcp_response_sec\x18\x08 \x01(\x05\x12\"\n\x0cswitch_setup\x18\t \x01(\x0b\x32\x0c.SwitchSetup\x12\x12\n\nhost_tests\x18\x10 \x01(\t\x12\x13\n\x0b\x62uild_tests\x18$ \x01(\x08\x12\x11\n\trun_limit\x18\x11 \x01(\x05\x12\x11\n\tfail_mode\x18\x12 \x01(\x08\x12\x13\n\x0bsingle_shot\x18\" \x01(\x08\x12\x15\n\rresult_linger\x18\x13 \x01(\x08\x12\x0f\n\x07no_test\x18\x14 \x01(\x08\x12\x11\n\tkeep_hold\x18( \x01(\x08\x12\x14\n\x0c\x64\x61q_loglevel\x18\x15 \x01(\t\x12\x18\n\x10mininet_loglevel\x18\x16 \x01(\t\x12\x13\n\x0b\x66inish_hook\x18# \x01(\t\x12\x10\n\x08gcp_cred\x18\x17 \x01(\t\x12\x11\n\tgcp_topic\x18\x18 \x01(\t\x12\x13\n\x0bschema_path\x18\x19 \x01(\t\x12\x11\n\tmud_files\x18\x1a \x01(\t\x12\x14\n\x0c\x64\x65vice_specs\x18\x1b \x01(\t\x12\x13\n\x0btest_config\x18\x1c \x01(\t\x12\x19\n\x11port_debounce_sec\x18\x1d \x01(\x05\x12\x15\n\rtopology_hook\x18\x1e \x01(\t\x12\x17\n\x0f\x64\x65vice_template\x18\x1f \x01(\t\x12\x14\n\x0csite_reports\x18 \x01(\t\x12\x1f\n\x17run_data_retention_days\x18! \x01(\x02\x12.\n\ninterfaces\x18% \x03(\x0b\x32\x1a.DaqConfig.InterfacesEntry\x12/\n\x0b\x66\x61il_module\x18/ \x03(\x0b\x32\x1a.DaqConfig.FailModuleEntry\x12\x1d\n\x15port_flap_timeout_sec\x18\x30 \x01(\x05\x12\x1c\n\tusi_setup\x18\x31 \x01(\x0b\x32\t.USISetup\x1a=\n\x0fInterfacesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x19\n\x05value\x18\x02 \x01(\x0b\x32\n.Interface:\x02\x38\x01\x1a\x31\n\x0f\x46\x61ilModuleEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x17\n\x08USISetup\x12\x0b\n\x03url\x18\x01 \x01(\t\"\xf4\x01\n\x0bSwitchSetup\x12\x11\n\tctrl_intf\x18\t \x01(\t\x12\x0f\n\x07ip_addr\x18\x0b \x01(\t\x12\x13\n\x0buplink_port\x18\r \x01(\x05\x12\x0f\n\x07lo_port\x18\x0e \x01(\x05\x12\x10\n\x08\x61lt_port\x18\x10 \x01(\x05\x12\x0f\n\x07lo_addr\x18\x12 \x01(\t\x12\x11\n\tmods_addr\x18\x14 \x01(\t\x12\x0f\n\x07of_dpid\x18) \x01(\t\x12\x11\n\tdata_intf\x18* \x01(\t\x12\x0e\n\x06\x65xt_br\x18+ \x01(\t\x12\r\n\x05model\x18, \x01(\t\x12\x10\n\x08username\x18- \x01(\t\x12\x10\n\x08password\x18. \x01(\t\"\'\n\tInterface\x12\x0c\n\x04opts\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05\x62\x06proto3' ) @@ -57,8 +57,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=971, - serialized_end=1032, + serialized_start=975, + serialized_end=1036, ) _DAQCONFIG_FAILMODULEENTRY = _descriptor.Descriptor( @@ -94,8 +94,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1034, - serialized_end=1083, + serialized_start=1038, + serialized_end=1087, ) _DAQCONFIG = _descriptor.Descriptor( @@ -309,7 +309,7 @@ is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( - name='fail_hook', full_name='DaqConfig.fail_hook', index=29, + name='topology_hook', full_name='DaqConfig.topology_hook', index=29, number=30, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, @@ -377,7 +377,7 @@ oneofs=[ ], serialized_start=34, - serialized_end=1083, + serialized_end=1087, ) @@ -407,8 +407,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1085, - serialized_end=1108, + serialized_start=1089, + serialized_end=1112, ) @@ -522,8 +522,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1111, - serialized_end=1355, + serialized_start=1115, + serialized_end=1359, ) @@ -560,8 +560,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1357, - serialized_end=1396, + serialized_start=1361, + serialized_end=1400, ) _DAQCONFIG_INTERFACESENTRY.fields_by_name['value'].message_type = _INTERFACE diff --git a/libs/proto/usi_pb2.py b/libs/proto/usi_pb2.py index 9414eb0416..c9189dc119 100644 --- a/libs/proto/usi_pb2.py +++ b/libs/proto/usi_pb2.py @@ -20,7 +20,7 @@ syntax='proto3', serialized_options=b'\n\004grpcB\010USIProtoP\001', create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\tusi.proto\x12\x03usi\"\'\n\x14SwitchActionResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\"\x9b\x01\n\rPowerResponse\x12!\n\x19\x63urrent_power_consumption\x18\x01 \x01(\x02\x12\x1d\n\x15max_power_consumption\x18\x02 \x01(\x02\x12$\n\x0bpoe_support\x18\x03 \x01(\x0e\x32\x0f.usi.POESupport\x12\"\n\npoe_status\x18\x04 \x01(\x0e\x32\x0e.usi.POEStatus\"]\n\x11InterfaceResponse\x12$\n\x0blink_status\x18\x01 \x01(\x0e\x32\x0f.usi.LinkStatus\x12\x12\n\nlink_speed\x18\x02 \x01(\x05\x12\x0e\n\x06\x64uplex\x18\x03 \x01(\t\"w\n\nSwitchInfo\x12\x0f\n\x07ip_addr\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65vice_port\x18\x03 \x01(\x05\x12\x1f\n\x05model\x18\x04 \x01(\x0e\x32\x10.usi.SwitchModel\x12\x10\n\x08username\x18\x05 \x01(\t\x12\x10\n\x08password\x18\x06 \x01(\t*W\n\x0bSwitchModel\x12\x17\n\x13\x41LLIED_TELESIS_X230\x10\x00\x12\x0e\n\nCISCO_9300\x10\x01\x12\x0e\n\nOVS_SWITCH\x10\x02\x12\x0f\n\x0b\x46\x41UX_SWITCH\x10\x03*\x1e\n\nLinkStatus\x12\x06\n\x02UP\x10\x00\x12\x08\n\x04\x44OWN\x10\x01*\'\n\nPOESupport\x12\x0b\n\x07\x45NABLED\x10\x00\x12\x0c\n\x08\x44ISABLED\x10\x01*1\n\tPOEStatus\x12\x06\n\x02ON\x10\x00\x12\x07\n\x03OFF\x10\x01\x12\t\n\x05\x46\x41ULT\x10\x02\x12\x08\n\x04\x44\x45NY\x10\x03\x32\xef\x01\n\nUSIService\x12\x31\n\x08GetPower\x12\x0f.usi.SwitchInfo\x1a\x12.usi.PowerResponse\"\x00\x12\x39\n\x0cGetInterface\x12\x0f.usi.SwitchInfo\x1a\x16.usi.InterfaceResponse\"\x00\x12:\n\ndisconnect\x12\x0f.usi.SwitchInfo\x1a\x19.usi.SwitchActionResponse\"\x00\x12\x37\n\x07\x63onnect\x12\x0f.usi.SwitchInfo\x1a\x19.usi.SwitchActionResponse\"\x00\x42\x12\n\x04grpcB\x08USIProtoP\x01\x62\x06proto3' + serialized_pb=b'\n\tusi.proto\x12\x03usi\"\'\n\x14SwitchActionResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\"\x9b\x01\n\rPowerResponse\x12!\n\x19\x63urrent_power_consumption\x18\x01 \x01(\x02\x12\x1d\n\x15max_power_consumption\x18\x02 \x01(\x02\x12$\n\x0bpoe_support\x18\x03 \x01(\x0e\x32\x0f.usi.POESupport\x12\"\n\npoe_status\x18\x04 \x01(\x0e\x32\x0e.usi.POEStatus\"]\n\x11InterfaceResponse\x12$\n\x0blink_status\x18\x01 \x01(\x0e\x32\x0f.usi.LinkStatus\x12\x12\n\nlink_speed\x18\x02 \x01(\x05\x12\x0e\n\x06\x64uplex\x18\x03 \x01(\t\"w\n\nSwitchInfo\x12\x0f\n\x07ip_addr\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65vice_port\x18\x03 \x01(\x05\x12\x1f\n\x05model\x18\x04 \x01(\x0e\x32\x10.usi.SwitchModel\x12\x10\n\x08username\x18\x05 \x01(\t\x12\x10\n\x08password\x18\x06 \x01(\t*F\n\x0bSwitchModel\x12\x17\n\x13\x41LLIED_TELESIS_X230\x10\x00\x12\x0e\n\nCISCO_9300\x10\x01\x12\x0e\n\nOVS_SWITCH\x10\x02*\x1e\n\nLinkStatus\x12\x06\n\x02UP\x10\x00\x12\x08\n\x04\x44OWN\x10\x01*\'\n\nPOESupport\x12\x0b\n\x07\x45NABLED\x10\x00\x12\x0c\n\x08\x44ISABLED\x10\x01*1\n\tPOEStatus\x12\x06\n\x02ON\x10\x00\x12\x07\n\x03OFF\x10\x01\x12\t\n\x05\x46\x41ULT\x10\x02\x12\x08\n\x04\x44\x45NY\x10\x03\x32\xef\x01\n\nUSIService\x12\x31\n\x08GetPower\x12\x0f.usi.SwitchInfo\x1a\x12.usi.PowerResponse\"\x00\x12\x39\n\x0cGetInterface\x12\x0f.usi.SwitchInfo\x1a\x16.usi.InterfaceResponse\"\x00\x12:\n\ndisconnect\x12\x0f.usi.SwitchInfo\x1a\x19.usi.SwitchActionResponse\"\x00\x12\x37\n\x07\x63onnect\x12\x0f.usi.SwitchInfo\x1a\x19.usi.SwitchActionResponse\"\x00\x42\x12\n\x04grpcB\x08USIProtoP\x01\x62\x06proto3' ) _SWITCHMODEL = _descriptor.EnumDescriptor( @@ -45,16 +45,11 @@ serialized_options=None, type=None, create_key=_descriptor._internal_create_key), - _descriptor.EnumValueDescriptor( - name='FAUX_SWITCH', index=3, number=3, - serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), ], containing_type=None, serialized_options=None, serialized_start=433, - serialized_end=520, + serialized_end=503, ) _sym_db.RegisterEnumDescriptor(_SWITCHMODEL) @@ -79,8 +74,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=522, - serialized_end=552, + serialized_start=505, + serialized_end=535, ) _sym_db.RegisterEnumDescriptor(_LINKSTATUS) @@ -105,8 +100,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=554, - serialized_end=593, + serialized_start=537, + serialized_end=576, ) _sym_db.RegisterEnumDescriptor(_POESUPPORT) @@ -141,8 +136,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=595, - serialized_end=644, + serialized_start=578, + serialized_end=627, ) _sym_db.RegisterEnumDescriptor(_POESTATUS) @@ -150,7 +145,6 @@ ALLIED_TELESIS_X230 = 0 CISCO_9300 = 1 OVS_SWITCH = 2 -FAUX_SWITCH = 3 UP = 0 DOWN = 1 ENABLED = 0 @@ -404,8 +398,8 @@ index=0, serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_start=647, - serialized_end=886, + serialized_start=630, + serialized_end=869, methods=[ _descriptor.MethodDescriptor( name='GetPower', diff --git a/proto/system_config.proto b/proto/system_config.proto index 1d1d3c6475..babf0abe45 100644 --- a/proto/system_config.proto +++ b/proto/system_config.proto @@ -94,8 +94,8 @@ message DaqConfig { // Set port-debounce for flaky connections. Zero to disable. int32 port_debounce_sec = 29; - // Hook for failure diagnostics. - string fail_hook = 30; + // Hook for device topology updates. + string topology_hook = 30; // Directory of defaults for new devices. string device_template = 31; diff --git a/usi/src/main/java/daq/usi/ovs/OpenVSwitch.java b/usi/src/main/java/daq/usi/ovs/OpenVSwitch.java index ba38631e7e..f95afe27d4 100644 --- a/usi/src/main/java/daq/usi/ovs/OpenVSwitch.java +++ b/usi/src/main/java/daq/usi/ovs/OpenVSwitch.java @@ -19,7 +19,7 @@ public class OpenVSwitch implements SwitchController { - private static final String OVS_OUTPUT_FILE = "ovs_output.txt"; + private static final String OVS_OUTPUT_FILE = "sec.ofctl"; protected String getInterfaceByPort(int devicePort) throws IOException { URL file = OpenVSwitch.class.getClassLoader().getResource(OVS_OUTPUT_FILE); diff --git a/usi/src/test/resources/ovs_output.txt b/usi/src/test/resources/src.ofctl similarity index 100% rename from usi/src/test/resources/ovs_output.txt rename to usi/src/test/resources/src.ofctl From f3ce97e8f699a97c7044d1ff6e9b608d0a068de4 Mon Sep 17 00:00:00 2001 From: Trevor Pering Date: Tue, 21 Jul 2020 09:35:39 -0700 Subject: [PATCH 039/212] Pin to UDMI version 1.0.0 --- cmd/build | 12 ++++++++++-- etc/UDMI_VERSION | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/cmd/build b/cmd/build index d9bdff7d86..5a2273d234 100755 --- a/cmd/build +++ b/cmd/build @@ -124,7 +124,11 @@ if [ "$1" == -f ]; then fi target_version=$(cat etc/FAUCET_VERSION) -target_commit=$(cd faucet; git rev-parse $target_version) +target_commit=$(cd faucet; git rev-list -n 1 $target_version) || true +if [ -z "$target_commit" ]; then + echo No valid faucet commit found, try running bin/setup_dev. + false +fi if [ "$target_commit" != "$local_version" ]; then echo Local faucet commit is at: $local_version echo Mismatch with etc/FAUCET_VERSION: $target_version @@ -134,7 +138,11 @@ fi local_version=$(cd udmi; git rev-list -n 1 HEAD) target_version=$(cat etc/UDMI_VERSION) -target_commit=$(cd udmi; git rev-parse $target_version) +target_commit=$(cd udmi; git rev-list -n 1 $target_version) || true +if [ -z "$target_commit" ]; then + echo No valid udmi commit found, try running bin/setup_dev. + false +fi if [ "$target_commit" != "$local_version" ]; then echo Local udmi commit is at: $local_version echo Mismatch with etc/UDMI_VERSION: $target_version diff --git a/etc/UDMI_VERSION b/etc/UDMI_VERSION index 50332690b1..3eefcb9dd5 100644 --- a/etc/UDMI_VERSION +++ b/etc/UDMI_VERSION @@ -1 +1 @@ -cdd9666f472b1e8be9e103d8f0429e7205689843 +1.0.0 From 00c7701c4a59bc3a715ae4ed15418d87a7536aa1 Mon Sep 17 00:00:00 2001 From: Trevor Pering Date: Tue, 21 Jul 2020 10:22:21 -0700 Subject: [PATCH 040/212] 1.8.0 release --- etc/docker_images.txt | 51 +++++++++++++++++++++++-------------------- etc/docker_images.ver | 2 +- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/etc/docker_images.txt b/etc/docker_images.txt index 78ef0f7a7d..3301febd41 100644 --- a/etc/docker_images.txt +++ b/etc/docker_images.txt @@ -1,24 +1,27 @@ -daqf/aardvark 13e07616906a -daqf/default 8547decf4b0c -daqf/faucet 0bd65761a824 -daqf/faux1 500fc556e362 -daqf/faux2 65be2e8aaff5 -daqf/gauge 399cf3f0cf26 -daqf/networking e7d0b7cea324 -daqf/switch 0a7b905f10fa -daqf/test_bacext 765b3fd4f471 -daqf/test_bacnet 1cdac0876850 -daqf/test_brute 9d046780449f -daqf/test_discover 6bb39aebc6d9 -daqf/test_fail 21b8d383d676 -daqf/test_hold 2c2dbda2fb23 -daqf/test_macoui 890bc044e327 -daqf/test_manual 156a1947c7f4 -daqf/test_mudgee 44a4ad7a9615 -daqf/test_nmap 6e97b5498219 -daqf/test_pass 95e9680cef60 -daqf/test_password 1bc14db7767e -daqf/test_ping 45e3f58e30a2 -daqf/test_switch 57cf3951b2e3 -daqf/test_tls f93b7fec95a4 -daqf/test_udmi 771e5969564d +daqf/aardvark 6fb0f6c52222 +daqf/default f8652a12fdd8 +daqf/faucet 380da46f6fda +daqf/faux1 befad911308a +daqf/faux2 588b260e9316 +daqf/gauge 157decf291db +daqf/networking 1b5d992ef9a9 +daqf/switch b2113d0aa5d9 +daqf/test_bacext 67df87afaf77 +daqf/test_bacnet 53c268d102eb +daqf/test_brute aa76b01d5eed +daqf/test_discover 0ca76d766349 +daqf/test_fail 8ef4103069a5 +daqf/test_hold 5c923cd1a464 +daqf/test_macoui a605473e0f8d +daqf/test_manual 8026fdd99a5b +daqf/test_mudgee 189aa0b635fd +daqf/test_nmap 2205363f02a4 +daqf/test_ntp a5b21e0039e6 +daqf/test_pass 62dd10381336 +daqf/test_password 486b405827b2 +daqf/test_ping fe8e4dd5ddc2 +daqf/test_ssh 054efbf1b3c3 +daqf/test_switch bfca153bb3fe +daqf/test_tls 50bf58dd9a6f +daqf/test_udmi 41c2ab08ec86 +daqf/usi e5b85be7cd9b diff --git a/etc/docker_images.ver b/etc/docker_images.ver index bd8bf882d0..27f9cd322b 100644 --- a/etc/docker_images.ver +++ b/etc/docker_images.ver @@ -1 +1 @@ -1.7.0 +1.8.0 From d5fb5acaddef9b6c6ac5734a821bf0b5aadae05c Mon Sep 17 00:00:00 2001 From: henry54809 Date: Tue, 21 Jul 2020 14:50:22 -0700 Subject: [PATCH 041/212] Restore gcp combine report test (#553) --- bin/python/combine_reports_from_date_range.py | 2 +- daq/ipaddr_test.py | 5 +++-- resources/setups/baseline/module_config.json | 2 +- testing/test_aux.out | 20 +++++++++---------- testing/test_dhcp.sh | 4 +++- testing/test_many.gcp | 4 ++++ testing/test_many.sh | 5 ++--- 7 files changed, 24 insertions(+), 18 deletions(-) diff --git a/bin/python/combine_reports_from_date_range.py b/bin/python/combine_reports_from_date_range.py index f5deb04b43..9b304c7e76 100644 --- a/bin/python/combine_reports_from_date_range.py +++ b/bin/python/combine_reports_from_date_range.py @@ -61,7 +61,7 @@ def _get_local_reports(device, reports_dir, start, end, count): LOGGER.info('Looking for reports locally') report_re = re.compile(r'^report_%s_(\d{4}-\d{2}-\d{2}T\d{6})\.json$' % device) json_files = [f for f in os.listdir(reports_dir) if report_re.match(f)] - json_files.sort() + json_files.sort(reverse=True) # Match gcp behavior if count and len(json_files) > count: json_files = json_files[len(json_files) - count:] for json_file in json_files: diff --git a/daq/ipaddr_test.py b/daq/ipaddr_test.py index 451192f75d..a7473925ce 100644 --- a/daq/ipaddr_test.py +++ b/daq/ipaddr_test.py @@ -66,8 +66,9 @@ def _multi_subnet_test(self): self._next_test() return dhcp_range = self.test_dhcp_ranges.pop(0) - self.log('Testing dhcp range: ' + ",".join([str(arg) for arg in dhcp_range])) - self.host.gateway.change_dhcp_range(*dhcp_range) + self.log('Testing dhcp range: ' + str(dhcp_range)) + args = (dhcp_range["start"], dhcp_range["end"], dhcp_range["prefix_length"]) + self.host.gateway.change_dhcp_range(*args) self._ip_callback = self._multi_subnet_test if self.test_dhcp_ranges else self._next_test def _ip_change_test(self): diff --git a/resources/setups/baseline/module_config.json b/resources/setups/baseline/module_config.json index 144c249ce2..be0cb97454 100644 --- a/resources/setups/baseline/module_config.json +++ b/resources/setups/baseline/module_config.json @@ -4,7 +4,7 @@ "enabled": false, "timeout_sec": 900, "port_flap_timeout_sec": 20, - "dhcp_ranges": [["192.168.0.1", "192.168.255.254", 16]] + "dhcp_ranges": [{"start": "192.168.0.1", "end": "192.168.255.254", "prefix_length": 16}] }, "pass": { "enabled": true diff --git a/testing/test_aux.out b/testing/test_aux.out index 75933922ee..3b0b5dd675 100644 --- a/testing/test_aux.out +++ b/testing/test_aux.out @@ -95,11 +95,11 @@ port-01 module_config modules }, "ipaddr": { "dhcp_ranges": [ - [ - "192.168.0.1", - "192.168.255.254", - 16 - ] + { + "end": "192.168.255.254", + "prefix_length": 16, + "start": "192.168.0.1" + } ], "enabled": false, "port_flap_timeout_sec": 20, @@ -158,11 +158,11 @@ port-02 module_config modules }, "ipaddr": { "dhcp_ranges": [ - [ - "192.168.0.1", - "192.168.255.254", - 16 - ] + { + "end": "192.168.255.254", + "prefix_length": 16, + "start": "192.168.0.1" + } ], "enabled": false, "port_flap_timeout_sec": 20, diff --git a/testing/test_dhcp.sh b/testing/test_dhcp.sh index 791b091669..44a7272be5 100755 --- a/testing/test_dhcp.sh +++ b/testing/test_dhcp.sh @@ -39,7 +39,9 @@ cat < local/site/mac_addrs/$intf_mac/module_config.json "ipaddr": { "enabled": true, "port_flap_timeout_sec": 20, - "dhcp_ranges": [["192.168.0.1", "192.168.255.254", 16], ["10.255.255.1", "10.255.255.255", 24], ["172.16.0.1", "172.16.0.200", 24]] + "dhcp_ranges": [{"start": "192.168.0.1", "end": "192.168.255.254", "prefix_length": 16}, + {"start": "10.255.255.1", "end": "10.255.255.255", "prefix_length": 24}, + {"start": "172.16.0.1", "end": "172.16.0.200", "prefix_length": 24}] } } } diff --git a/testing/test_many.gcp b/testing/test_many.gcp index eccaaa37a2..b24657de64 100644 --- a/testing/test_many.gcp +++ b/testing/test_many.gcp @@ -1,2 +1,6 @@ Running testing/test_many.sh GCP results diff +5c5 +< Source: gcp +--- +> Source: local diff --git a/testing/test_many.sh b/testing/test_many.sh index 3dd796452b..b3029e333e 100755 --- a/testing/test_many.sh +++ b/testing/test_many.sh @@ -80,7 +80,7 @@ echo DAQ stress test | tee -a $TEST_RESULTS start_time=`date -u -Isec` cmd/run -b run_limit=$RUN_LIMIT settle_sec=0 dhcp_lease_time=120s -end_time=`date -u -Isec` +end_time=`date -u -Isec --date="+5min"` # Adding additional time to account for slower cloud function calls for updating timestamp. cat inst/result.log results=$(fgrep [] inst/result.log | wc -l) @@ -126,8 +126,7 @@ if [ -f "$gcp_cred" ]; then bin/combine_reports device=9a:02:57:1e:8f:05 from_time=$start_time to_time=$end_time \ count=2 from_gcp=true echo GCP results diff | tee -a $GCP_RESULTS - # TODO: Re-enable as per b/161529445 - # diff inst/reports/combo_*.md out/report_local.md | tee -a $GCP_RESULTS + diff inst/reports/combo_*.md out/report_local.md | tee -a $GCP_RESULTS fi echo Done with many | tee -a $TEST_RESULTS From b0e83b323e8f64698bdcbf1a09d16736b6109062 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Jul 2020 14:56:39 -0700 Subject: [PATCH 042/212] Update dependency @google-cloud/pubsub to v2.3.0 (#554) --- firebase/functions/package-lock.json | 60 ++++++++++++++++++++-------- firebase/functions/package.json | 2 +- 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/firebase/functions/package-lock.json b/firebase/functions/package-lock.json index a4318bae57..5d8be24d18 100644 --- a/firebase/functions/package-lock.json +++ b/firebase/functions/package-lock.json @@ -136,9 +136,9 @@ "optional": true }, "@google-cloud/pubsub": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@google-cloud/pubsub/-/pubsub-2.2.0.tgz", - "integrity": "sha512-HOG6LbajfPgZPWEIEFz7TAjEa3OUJsksmtFCRyknnSY1fX4eKVvDq0PP2SSNe0HbG9WdfsJGOEfhCW1fOdqvKw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@google-cloud/pubsub/-/pubsub-2.3.0.tgz", + "integrity": "sha512-lWFwuzg+d7UN7YY6TGwIFPxiA2pFFHx1ApN0X5xIe0jtuUuF2iPaRNIJwZTOnvZ8xmOSpQqiaj/SwEDgr4b46A==", "requires": { "@google-cloud/paginator": "^3.0.0", "@google-cloud/precise-date": "^2.0.0", @@ -171,9 +171,9 @@ "integrity": "sha512-ZDG38U/Yy6Zr21LaR3BTiiLtpJl6RkPS/JwoRT453G+6Q1DhlV0waNf8Lfu+YVYGIIxgKnLayJRfYlFJfiI8iQ==" }, "@google-cloud/promisify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-2.0.1.tgz", - "integrity": "sha512-82EQzwrNauw1fkbUSr3f+50Bcq7g4h0XvLOk8C5e9ABkXYHei7ZPi9tiMMD7Vh3SfcdH97d1ibJ3KBWp2o1J+w==" + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-2.0.2.tgz", + "integrity": "sha512-EvuabjzzZ9E2+OaYf+7P9OAiiwbTxKYL0oGLnREQd+Su2NTQBpomkdlkBowFvyWsaV0d1sSGxrKpSNcrhPqbxg==" }, "@grpc/grpc-js": { "version": "1.1.2", @@ -183,6 +183,11 @@ "semver": "^6.2.0" } }, + "bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" + }, "gaxios": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.0.4.tgz", @@ -196,18 +201,18 @@ } }, "gcp-metadata": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.1.0.tgz", - "integrity": "sha512-r57SV28+olVsflPlKyVig3Muo/VDlcsObMtvDGOEtEJXj+DDE8bEl0coIkXh//hbkSDTvo+f5lbihZOndYXQQQ==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.1.4.tgz", + "integrity": "sha512-5J/GIH0yWt/56R3dNaNWPGQ/zXsZOddYECfJaqxFWgrZ9HC2Kvc5vl9upOgUUHKzURjAVf2N+f6tEJiojqXUuA==", "requires": { "gaxios": "^3.0.0", - "json-bigint": "^0.3.0" + "json-bigint": "^1.0.0" } }, "google-auth-library": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.0.4.tgz", - "integrity": "sha512-O1uT4F1mMu5OYnvH0ppg6mqP5pGQrqzg2nrzd7ay3DA+VD0mp9VM+Julf/bov2OuxgFs2DD+gWnp2nZPB4EflA==", + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.0.5.tgz", + "integrity": "sha512-Wj31lfTm2yR4g3WfOOB1Am1tt478Xq9OvzTPQJi17tn/I9R5IcsxjANBsE93nYmxYxtwDedhOdIb8l3vSPG49Q==", "requires": { "arrify": "^2.0.0", "base64-js": "^1.3.0", @@ -217,7 +222,7 @@ "gcp-metadata": "^4.1.0", "gtoken": "^5.0.0", "jws": "^4.0.0", - "lru-cache": "^5.0.0" + "lru-cache": "^6.0.0" } }, "google-gax": { @@ -242,9 +247,9 @@ }, "dependencies": { "protobufjs": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.9.0.tgz", - "integrity": "sha512-LlGVfEWDXoI/STstRDdZZKb/qusoAWUnmLg9R8OLSO473mBLWHowx8clbX5/+mKDEI+v7GzjoK9tRPZMMcoTrg==", + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.10.1.tgz", + "integrity": "sha512-pb8kTchL+1Ceg4lFd5XUpK8PdWacbvV5SK2ULH2ebrYtl4GjJmS24m6CKME67jzV53tbJxHlnNOSqQHbTsR9JQ==", "requires": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -281,6 +286,27 @@ "jws": "^4.0.0", "mime": "^2.2.0" } + }, + "json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "requires": { + "bignumber.js": "^9.0.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } } }, diff --git a/firebase/functions/package.json b/firebase/functions/package.json index df0e8e92e7..8a03a7717c 100644 --- a/firebase/functions/package.json +++ b/firebase/functions/package.json @@ -12,7 +12,7 @@ "node": "10" }, "dependencies": { - "@google-cloud/pubsub": "2.2.0", + "@google-cloud/pubsub": "2.3.0", "@google-cloud/iot": "1.8.0", "firebase-admin": "8.12.1", "firebase-functions": "3.7.0", From 537688bff4faf0cad0034932d3215feccad4e174 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Jul 2020 14:57:27 -0700 Subject: [PATCH 043/212] Update dependency firebase-admin to v9 (#535) --- firebase/functions/package-lock.json | 867 +++++++++++++-------------- firebase/functions/package.json | 2 +- 2 files changed, 416 insertions(+), 453 deletions(-) diff --git a/firebase/functions/package-lock.json b/firebase/functions/package-lock.json index 5d8be24d18..44afb953cc 100644 --- a/firebase/functions/package-lock.json +++ b/firebase/functions/package-lock.json @@ -14,26 +14,26 @@ "integrity": "sha512-88h74TMQ6wXChPA6h9Q3E1Jg6TkTHep2+k63OWg3s0ozyGVMeY+TTOti7PFPzq5RhszQPQOoCi59es4MaRvgCw==" }, "@firebase/component": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.1.13.tgz", - "integrity": "sha512-DuSIM96NQkE3Yo77IOa5BWw8VBdvCR5cbMLNiFT4X3dTU15Dm0zHjncQHt/6rQpABGNYWAfOCJmSU1v6vc3DFA==", + "version": "0.1.16", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.1.16.tgz", + "integrity": "sha512-FvffvFN0LWgv1H/FIyruTECOL69Dhy+JfwoTq+mV39V8Mz9lNpo41etonL5AOr7KmXxYJVbNwkx0L9Ei88i7JA==", "requires": { - "@firebase/util": "0.2.48", - "tslib": "1.11.1" + "@firebase/util": "0.2.50", + "tslib": "^1.11.1" } }, "@firebase/database": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.6.4.tgz", - "integrity": "sha512-m3jaElEEXhr3a9D+M/kbDuRCQG5EmrnSqyEq7iNk3s5ankIrALid0AYm2RZF764F/DIeMFtAzng4EyyEqsaQlQ==", + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.6.7.tgz", + "integrity": "sha512-vm0ch2zNSoHfXWnDG6WVjf0p/BdXOMBL1lAfkGu3DYH/Rkl4p97x57w0WNOURNfL4GY2LIqScSYKCidV7jqTog==", "requires": { "@firebase/auth-interop-types": "0.1.5", - "@firebase/component": "0.1.13", + "@firebase/component": "0.1.16", "@firebase/database-types": "0.5.1", - "@firebase/logger": "0.2.5", - "@firebase/util": "0.2.48", + "@firebase/logger": "0.2.6", + "@firebase/util": "0.2.50", "faye-websocket": "0.11.3", - "tslib": "1.11.1" + "tslib": "^1.11.1" } }, "@firebase/database-types": { @@ -45,48 +45,117 @@ } }, "@firebase/logger": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.2.5.tgz", - "integrity": "sha512-qqw3m0tWs/qrg7axTZG/QZq24DIMdSY6dGoWuBn08ddq7+GLF5HiqkRj71XznYeUUbfRq5W9C/PSFnN4JxX+WA==" + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.2.6.tgz", + "integrity": "sha512-KIxcUvW/cRGWlzK9Vd2KB864HlUnCfdTH0taHE0sXW5Xl7+W68suaeau1oKNEqmc3l45azkd4NzXTCWZRZdXrw==" }, "@firebase/util": { - "version": "0.2.48", - "resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.2.48.tgz", - "integrity": "sha512-6Wzq6IBF//3mrMTmTQ+JmceM0PMQpxV2GVfXhZn/4sMMkkhB0MA908nPDnatoHwUKyWE3BMw+uTLkyBnkuTu5A==", + "version": "0.2.50", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.2.50.tgz", + "integrity": "sha512-vFE6+Jfc25u0ViSpFxxq0q5s+XmuJ/y7CL3ud79RQe+WLFFg+j0eH1t23k0yNSG9vZNM7h3uHRIXbV97sYLAyw==", "requires": { - "tslib": "1.11.1" + "tslib": "^1.11.1" } }, "@google-cloud/common": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-2.4.0.tgz", - "integrity": "sha512-zWFjBS35eI9leAHhjfeOYlK5Plcuj/77EzstnrJIZbKgF/nkqjcQuGiMCpzCwOfPyUbz8ZaEOYgbHa759AKbjg==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-3.3.2.tgz", + "integrity": "sha512-W7JRLBEJWYtZQQuGQX06U6GBOSLrSrlvZxv6kGNwJtFrusu6AVgZltQ9Pajuz9Dh9aSXy9aTnBcyxn2/O0EGUw==", "optional": true, "requires": { - "@google-cloud/projectify": "^1.0.0", - "@google-cloud/promisify": "^1.0.0", - "arrify": "^2.0.0", - "duplexify": "^3.6.0", + "@google-cloud/projectify": "^2.0.0", + "@google-cloud/promisify": "^2.0.0", + "arrify": "^2.0.1", + "duplexify": "^4.1.1", "ent": "^2.2.0", "extend": "^3.0.2", - "google-auth-library": "^5.5.0", - "retry-request": "^4.0.0", - "teeny-request": "^6.0.0" - } - }, - "@google-cloud/firestore": { - "version": "3.8.4", - "resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-3.8.4.tgz", - "integrity": "sha512-LCZeqB6goNKzD5G/wcoqWaQ2uf3FV/dtU5OSypqOWl+vHMTEVh1ap2H21JXaEydxq53lCayGfqjhDQzs0J3Qew==", - "optional": true, - "requires": { - "deep-equal": "^2.0.0", - "functional-red-black-tree": "^1.0.1", - "google-gax": "^1.13.0", - "readable-stream": "^3.4.0", - "through2": "^3.0.0" + "google-auth-library": "^6.0.0", + "retry-request": "^4.1.1", + "teeny-request": "^7.0.0" }, "dependencies": { + "duplexify": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.1.tgz", + "integrity": "sha512-DY3xVEmVHTv1wSzKNbwoU6nVjzI369Y6sPoqfYr0/xlx3IdX2n94xIszTcjPO8W8ZIv0Wb0PXNcjuZyT4wiICA==", + "optional": true, + "requires": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.0" + } + }, + "gaxios": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.0.4.tgz", + "integrity": "sha512-97NmFuMETFQh6gqPUxkqjxRMjmY8aRKRMphIkgO/b90AbCt5wAVuXsp8oWjIXlLN2pIK/fsXD8edcM7ULkFMLg==", + "optional": true, + "requires": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.3.0" + } + }, + "gcp-metadata": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.1.0.tgz", + "integrity": "sha512-r57SV28+olVsflPlKyVig3Muo/VDlcsObMtvDGOEtEJXj+DDE8bEl0coIkXh//hbkSDTvo+f5lbihZOndYXQQQ==", + "optional": true, + "requires": { + "gaxios": "^3.0.0", + "json-bigint": "^0.3.0" + } + }, + "google-auth-library": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.0.5.tgz", + "integrity": "sha512-Wj31lfTm2yR4g3WfOOB1Am1tt478Xq9OvzTPQJi17tn/I9R5IcsxjANBsE93nYmxYxtwDedhOdIb8l3vSPG49Q==", + "optional": true, + "requires": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^3.0.0", + "gcp-metadata": "^4.1.0", + "gtoken": "^5.0.0", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + } + }, + "google-p12-pem": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.2.tgz", + "integrity": "sha512-tbjzndQvSIHGBLzHnhDs3cL4RBjLbLXc2pYvGH+imGVu5b4RMAttUTdnmW2UH0t11QeBTXZ7wlXPS7hrypO/tg==", + "optional": true, + "requires": { + "node-forge": "^0.9.0" + } + }, + "gtoken": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.2.tgz", + "integrity": "sha512-lull70rHCTvRTmAt+R/6W5bTtx4MjHku7AwJwK5fGqhOmygcZud0nrZcX+QUNfBJwCzqy7S5i1Bc4NYnr5PMMA==", + "optional": true, + "requires": { + "gaxios": "^3.0.0", + "google-p12-pem": "^3.0.0", + "jws": "^4.0.0", + "mime": "^2.2.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "optional": true, + "requires": { + "yallist": "^4.0.0" + } + }, "readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -97,6 +166,153 @@ "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + } + } + }, + "@google-cloud/firestore": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-4.1.1.tgz", + "integrity": "sha512-HFy2OEOrYJ7jYUir90Kg7+AWM6fsFoWYiHiryoseHfkL9//AnXm2sn0CiaOhsTsxphc69G8LBBvUj6ws0QDa7g==", + "optional": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "functional-red-black-tree": "^1.0.1", + "google-gax": "^2.2.0" + }, + "dependencies": { + "@grpc/grpc-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.1.2.tgz", + "integrity": "sha512-k2u86Bkm/3xrjUaSWeIyzXScBt/cC8uE7BznR0cpueQi11R33W6qfJdMrkrsmSHirp5likR55JSXUrcWG6ybHA==", + "optional": true, + "requires": { + "semver": "^6.2.0" + } + }, + "gaxios": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.0.4.tgz", + "integrity": "sha512-97NmFuMETFQh6gqPUxkqjxRMjmY8aRKRMphIkgO/b90AbCt5wAVuXsp8oWjIXlLN2pIK/fsXD8edcM7ULkFMLg==", + "optional": true, + "requires": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.3.0" + } + }, + "gcp-metadata": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.1.0.tgz", + "integrity": "sha512-r57SV28+olVsflPlKyVig3Muo/VDlcsObMtvDGOEtEJXj+DDE8bEl0coIkXh//hbkSDTvo+f5lbihZOndYXQQQ==", + "optional": true, + "requires": { + "gaxios": "^3.0.0", + "json-bigint": "^0.3.0" + } + }, + "google-auth-library": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.0.5.tgz", + "integrity": "sha512-Wj31lfTm2yR4g3WfOOB1Am1tt478Xq9OvzTPQJi17tn/I9R5IcsxjANBsE93nYmxYxtwDedhOdIb8l3vSPG49Q==", + "optional": true, + "requires": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^3.0.0", + "gcp-metadata": "^4.1.0", + "gtoken": "^5.0.0", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + } + }, + "google-gax": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-2.6.3.tgz", + "integrity": "sha512-hqY6H53Qmaku8rE8dGAM89RSUc1nc4JYG81whrVJRmDQZ2jhJK8AwCd3pJQ3V48rgp9xiWBzBQsyeaxnb3Eikw==", + "optional": true, + "requires": { + "@grpc/grpc-js": "~1.1.1", + "@grpc/proto-loader": "^0.5.1", + "@types/long": "^4.0.0", + "abort-controller": "^3.0.0", + "duplexify": "^3.6.0", + "google-auth-library": "^6.0.0", + "is-stream-ended": "^0.1.4", + "lodash.at": "^4.6.0", + "lodash.has": "^4.5.2", + "node-fetch": "^2.6.0", + "protobufjs": "^6.9.0", + "retry-request": "^4.0.0", + "semver": "^6.0.0", + "walkdir": "^0.4.0" + } + }, + "google-p12-pem": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.2.tgz", + "integrity": "sha512-tbjzndQvSIHGBLzHnhDs3cL4RBjLbLXc2pYvGH+imGVu5b4RMAttUTdnmW2UH0t11QeBTXZ7wlXPS7hrypO/tg==", + "optional": true, + "requires": { + "node-forge": "^0.9.0" + } + }, + "gtoken": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.2.tgz", + "integrity": "sha512-lull70rHCTvRTmAt+R/6W5bTtx4MjHku7AwJwK5fGqhOmygcZud0nrZcX+QUNfBJwCzqy7S5i1Bc4NYnr5PMMA==", + "optional": true, + "requires": { + "gaxios": "^3.0.0", + "google-p12-pem": "^3.0.0", + "jws": "^4.0.0", + "mime": "^2.2.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "optional": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "protobufjs": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.10.0.tgz", + "integrity": "sha512-Hdz1+CXkrlmGDKkP6DczxysdnUyUuhM1mjeaydnBxOcjxQPbJldLZ8eGE1gX0UTsgv+0QkFfn6dioo5yt9XORw==", + "optional": true, + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": "^13.7.0", + "long": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true } } }, @@ -109,9 +325,9 @@ } }, "@google-cloud/paginator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-2.0.3.tgz", - "integrity": "sha512-kp/pkb2p/p0d8/SKUu4mOq8+HGwF8NPzHWkj+VKrIPQPyMRw8deZtrO/OcSiy9C/7bpfU5Txah5ltUNfPkgEXg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-3.0.2.tgz", + "integrity": "sha512-kXK+Dbz4pNvv8bKU80Aw5HsIdgOe0WuMTd8/fI6tkANUxzvJOVJQQRsWVqcHSWK2RXHPTA9WBniUCwY6gAJDXw==", "optional": true, "requires": { "arrify": "^2.0.0", @@ -124,15 +340,15 @@ "integrity": "sha512-eEnWN8vzy4Gji9dOlcr8rsX0Oz52eI6ZZZj0AIrUbqTXM8JFPqKzx53DpWIYuXW6c8AfiyY1txjOsg1cXvsoyQ==" }, "@google-cloud/projectify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-1.0.4.tgz", - "integrity": "sha512-ZdzQUN02eRsmTKfBj9FDL0KNDIFNjBn/d6tHQmA/+FImH5DO6ZV8E7FzxMgAUiVAUq41RFAkb25p1oHOZ8psfg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-2.0.1.tgz", + "integrity": "sha512-ZDG38U/Yy6Zr21LaR3BTiiLtpJl6RkPS/JwoRT453G+6Q1DhlV0waNf8Lfu+YVYGIIxgKnLayJRfYlFJfiI8iQ==", "optional": true }, "@google-cloud/promisify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-1.0.4.tgz", - "integrity": "sha512-VccZDcOql77obTnFh0TbNED/6ZbbmHDf8UMNnzO1d5g9V0Htfm4k5cllY8P1tJsRKC3zWYGRLaViiupcgVjBoQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-2.0.1.tgz", + "integrity": "sha512-82EQzwrNauw1fkbUSr3f+50Bcq7g4h0XvLOk8C5e9ABkXYHei7ZPi9tiMMD7Vh3SfcdH97d1ibJ3KBWp2o1J+w==", "optional": true }, "@google-cloud/pubsub": { @@ -311,14 +527,14 @@ } }, "@google-cloud/storage": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-4.7.0.tgz", - "integrity": "sha512-f0guAlbeg7Z0m3gKjCfBCu7FG9qS3M3oL5OQQxlvGoPtK7/qg3+W+KQV73O2/sbuS54n0Kh2mvT5K2FWzF5vVQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-5.1.2.tgz", + "integrity": "sha512-j2blsBVv6Tt5Z7ff6kOSIg5zVQPdlcTQh/4zMb9h7xMj4ekwndQA60le8c1KEa+Y6SR3EM6ER2AvKYK53P7vdQ==", "optional": true, "requires": { - "@google-cloud/common": "^2.1.1", - "@google-cloud/paginator": "^2.0.0", - "@google-cloud/promisify": "^1.0.0", + "@google-cloud/common": "^3.0.0", + "@google-cloud/paginator": "^3.0.0", + "@google-cloud/promisify": "^2.0.0", "arrify": "^2.0.0", "compressible": "^2.0.12", "concat-stream": "^2.0.0", @@ -326,24 +542,24 @@ "duplexify": "^3.5.0", "extend": "^3.0.2", "gaxios": "^3.0.0", - "gcs-resumable-upload": "^2.2.4", + "gcs-resumable-upload": "^3.0.0", "hash-stream-validation": "^0.2.2", "mime": "^2.2.0", "mime-types": "^2.0.8", "onetime": "^5.1.0", - "p-limit": "^2.2.0", + "p-limit": "^3.0.1", "pumpify": "^2.0.0", "readable-stream": "^3.4.0", "snakeize": "^0.1.0", "stream-events": "^1.0.1", - "through2": "^3.0.0", + "through2": "^4.0.0", "xdg-basedir": "^4.0.0" }, "dependencies": { "gaxios": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.0.3.tgz", - "integrity": "sha512-PkzQludeIFhd535/yucALT/Wxyj/y2zLyrMwPcJmnLHDugmV49NvAi/vb+VUq/eWztATZCNcb8ue+ywPG+oLuw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.0.4.tgz", + "integrity": "sha512-97NmFuMETFQh6gqPUxkqjxRMjmY8aRKRMphIkgO/b90AbCt5wAVuXsp8oWjIXlLN2pIK/fsXD8edcM7ULkFMLg==", "optional": true, "requires": { "abort-controller": "^3.0.0", @@ -363,6 +579,15 @@ "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } + }, + "through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "optional": true, + "requires": { + "readable-stream": "3" + } } } }, @@ -555,12 +780,6 @@ "debug": "4" } }, - "array-filter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz", - "integrity": "sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=", - "optional": true - }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -571,15 +790,6 @@ "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" }, - "available-typed-arrays": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz", - "integrity": "sha512-XWX3OX8Onv97LMk/ftVyBibpGwY5a8SmuxZPzeOxqmuEqUCOM9ZE+uIaD1VNJ5QnvU2UQusvmKbuM1FR8QWGfQ==", - "optional": true, - "requires": { - "array-filter": "^1.0.0" - } - }, "base64-js": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", @@ -750,44 +960,6 @@ "ms": "^2.1.1" } }, - "deep-equal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.0.3.tgz", - "integrity": "sha512-Spqdl4H+ky45I9ByyJtXteOm9CaIrPmnIPmOhrkKGNYWeDgCvJ8jNYVCTjChxW4FqGuZnLHADc8EKRMX6+CgvA==", - "optional": true, - "requires": { - "es-abstract": "^1.17.5", - "es-get-iterator": "^1.1.0", - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.2", - "is-regex": "^1.0.5", - "isarray": "^2.0.5", - "object-is": "^1.1.2", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "regexp.prototype.flags": "^1.3.0", - "side-channel": "^1.0.2", - "which-boxed-primitive": "^1.0.1", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.2" - }, - "dependencies": { - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "optional": true - } - } - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "requires": { - "object-keys": "^1.0.12" - } - }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -858,57 +1030,6 @@ "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", "optional": true }, - "es-abstract": { - "version": "1.17.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", - "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.1.5", - "is-regex": "^1.0.5", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimleft": "^2.1.1", - "string.prototype.trimright": "^2.1.1" - } - }, - "es-get-iterator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.0.tgz", - "integrity": "sha512-UfrmHuWQlNMTs35e1ypnvikg6jCz3SK8v8ImvmDsh36fCVUR1MqoFDiyn0/k52C8NqO3YsO8Oe0azeesNuqSsQ==", - "optional": true, - "requires": { - "es-abstract": "^1.17.4", - "has-symbols": "^1.0.1", - "is-arguments": "^1.0.4", - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-string": "^1.0.5", - "isarray": "^2.0.5" - }, - "dependencies": { - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "optional": true - } - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -986,6 +1107,12 @@ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "optional": true + }, "fast-text-encoding": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.1.tgz", @@ -1029,28 +1156,23 @@ } }, "firebase-admin": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-8.12.1.tgz", - "integrity": "sha512-DZ4Q7QQJYaO2BhnhZLrhL+mGRTCLS5WrxjbJtuKGmbKRBepwMhx++EQA5yhnGnIXgDHnp5SrZnVKygNdXtH8BQ==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-9.0.0.tgz", + "integrity": "sha512-LP4xD+JxfEZ+e1kBIKT2kbDa9UFChwgL4488NexvTjhynNcJsKCGmawl2FMvZ2UPwXKgWBpLXJ07cYp6gk5lcw==", "requires": { "@firebase/database": "^0.6.0", - "@google-cloud/firestore": "^3.0.0", - "@google-cloud/storage": "^4.1.2", - "@types/node": "^8.10.59", + "@google-cloud/firestore": "^4.0.0", + "@google-cloud/storage": "^5.0.0", + "@types/node": "^10.10.0", "dicer": "^0.3.0", - "jsonwebtoken": "8.1.0", - "node-forge": "0.7.4" + "jsonwebtoken": "^8.5.1", + "node-forge": "^0.9.1" }, "dependencies": { "@types/node": { - "version": "8.10.61", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.61.tgz", - "integrity": "sha512-l+zSbvT8TPRaCxL1l9cwHCb0tSqGAGcjPJFItGGYat5oCTiq1uQQKYg5m7AF1mgnEBzFXGLJ2LRmNjtreRX76Q==" - }, - "node-forge": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.4.tgz", - "integrity": "sha512-8Df0906+tq/omxuCZD6PqhPaQDYuyJ1d+VITgxoIA8zvQd1ru+nMJcDChHH324MWitIgbVkAkQoGEEVJNpn/PA==" + "version": "10.17.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.27.tgz", + "integrity": "sha512-J0oqm9ZfAXaPdwNXMMgAhylw5fhmXkToJd06vuDUSAgEDZ/n/69/69UmyBZbc+zT34UnShuDSBqvim3SPnozJg==" } } }, @@ -1065,12 +1187,6 @@ "lodash": "^4.17.14" } }, - "foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", - "optional": true - }, "forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", @@ -1081,11 +1197,6 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, "functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", @@ -1114,17 +1225,96 @@ } }, "gcs-resumable-upload": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/gcs-resumable-upload/-/gcs-resumable-upload-2.3.3.tgz", - "integrity": "sha512-sf896I5CC/1AxeaGfSFg3vKMjUq/r+A3bscmVzZm10CElyRanN0XwPu/MxeIO4LSP+9uF6yKzXvNsaTsMXUG6Q==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/gcs-resumable-upload/-/gcs-resumable-upload-3.1.1.tgz", + "integrity": "sha512-RS1osvAicj9+MjCc6jAcVL1Pt3tg7NK2C2gXM5nqD1Gs0klF2kj5nnAFSBy97JrtslMIQzpb7iSuxaG8rFWd2A==", "optional": true, "requires": { "abort-controller": "^3.0.0", "configstore": "^5.0.0", - "gaxios": "^2.0.0", - "google-auth-library": "^5.0.0", + "extend": "^3.0.2", + "gaxios": "^3.0.0", + "google-auth-library": "^6.0.0", "pumpify": "^2.0.0", "stream-events": "^1.0.4" + }, + "dependencies": { + "gaxios": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.0.4.tgz", + "integrity": "sha512-97NmFuMETFQh6gqPUxkqjxRMjmY8aRKRMphIkgO/b90AbCt5wAVuXsp8oWjIXlLN2pIK/fsXD8edcM7ULkFMLg==", + "optional": true, + "requires": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.3.0" + } + }, + "gcp-metadata": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.1.0.tgz", + "integrity": "sha512-r57SV28+olVsflPlKyVig3Muo/VDlcsObMtvDGOEtEJXj+DDE8bEl0coIkXh//hbkSDTvo+f5lbihZOndYXQQQ==", + "optional": true, + "requires": { + "gaxios": "^3.0.0", + "json-bigint": "^0.3.0" + } + }, + "google-auth-library": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.0.5.tgz", + "integrity": "sha512-Wj31lfTm2yR4g3WfOOB1Am1tt478Xq9OvzTPQJi17tn/I9R5IcsxjANBsE93nYmxYxtwDedhOdIb8l3vSPG49Q==", + "optional": true, + "requires": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^3.0.0", + "gcp-metadata": "^4.1.0", + "gtoken": "^5.0.0", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + } + }, + "google-p12-pem": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.2.tgz", + "integrity": "sha512-tbjzndQvSIHGBLzHnhDs3cL4RBjLbLXc2pYvGH+imGVu5b4RMAttUTdnmW2UH0t11QeBTXZ7wlXPS7hrypO/tg==", + "optional": true, + "requires": { + "node-forge": "^0.9.0" + } + }, + "gtoken": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.2.tgz", + "integrity": "sha512-lull70rHCTvRTmAt+R/6W5bTtx4MjHku7AwJwK5fGqhOmygcZud0nrZcX+QUNfBJwCzqy7S5i1Bc4NYnr5PMMA==", + "optional": true, + "requires": { + "gaxios": "^3.0.0", + "google-p12-pem": "^3.0.0", + "jws": "^4.0.0", + "mime": "^2.2.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "optional": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + } } }, "google-auth-library": { @@ -1190,19 +1380,6 @@ "mime": "^2.2.0" } }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" - }, "hash-stream-validation": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/hash-stream-validation/-/hash-stream-validation-0.2.3.tgz", @@ -1292,66 +1469,12 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, - "is-arguments": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", - "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", - "optional": true - }, - "is-bigint": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.0.tgz", - "integrity": "sha512-t5mGUXC/xRheCK431ylNiSkGGpBp8bHENBcENTkDT6ppwPzEVxNGZRvgvmOEfbWkFhA7D2GEuE2mmQTr78sl2g==", - "optional": true - }, - "is-boolean-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.0.1.tgz", - "integrity": "sha512-TqZuVwa/sppcrhUCAYkGBk7w0yxfQQnxq28fjkO53tnK9FQXmdwz2JS5+GjsWQ6RByES1K40nI+yDic5c9/aAQ==", - "optional": true - }, - "is-callable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", - "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==" - }, - "is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" - }, - "is-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.1.tgz", - "integrity": "sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw==", - "optional": true - }, - "is-number-object": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz", - "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==", - "optional": true - }, "is-obj": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", "optional": true }, - "is-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", - "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", - "requires": { - "has-symbols": "^1.0.1" - } - }, - "is-set": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.1.tgz", - "integrity": "sha512-eJEzOtVyenDs1TMzSQ3kU3K+E0GUS9sno+F0OBT97xsgcJsF9nXMBtkT9/kut5JEpM7oL7X/0qxR17K3mcwIAA==", - "optional": true - }, "is-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", @@ -1362,50 +1485,12 @@ "resolved": "https://registry.npmjs.org/is-stream-ended/-/is-stream-ended-0.1.4.tgz", "integrity": "sha512-xj0XPvmr7bQFTvirqnFr50o0hQIh6ZItDqloxt5aJrR4NQsYeSsyFQERYGCAzfindAcnKjINnwEEgLx4IqVzQw==" }, - "is-string": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", - "optional": true - }, - "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "requires": { - "has-symbols": "^1.0.1" - } - }, - "is-typed-array": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.3.tgz", - "integrity": "sha512-BSYUBOK/HJibQ30wWkWold5txYwMUXQct9YHAQJr8fSwvZoiglcqB0pd7vEN23+Tsi9IUEjztdOSzl4qLVYGTQ==", - "optional": true, - "requires": { - "available-typed-arrays": "^1.0.0", - "es-abstract": "^1.17.4", - "foreach": "^2.0.5", - "has-symbols": "^1.0.1" - } - }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "optional": true }, - "is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", - "optional": true - }, - "is-weakset": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.1.tgz", - "integrity": "sha512-pi4vhbhVHGLxohUw7PhGsueT4vRGFoXhP7+RGN0jKIv9+8PWYCQTqtADngrxOm2g46hoH0+g8uZZBzMrvVGDmw==", - "optional": true - }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -1420,11 +1505,11 @@ } }, "jsonwebtoken": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.1.0.tgz", - "integrity": "sha1-xjl80uX9WD1lwAeoPce7eOaYK4M=", + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", "requires": { - "jws": "^3.1.4", + "jws": "^3.2.2", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", "lodash.isinteger": "^4.0.4", @@ -1432,8 +1517,8 @@ "lodash.isplainobject": "^4.0.6", "lodash.isstring": "^4.0.1", "lodash.once": "^4.0.0", - "ms": "^2.0.0", - "xtend": "^4.0.1" + "ms": "^2.1.1", + "semver": "^5.6.0" }, "dependencies": { "jwa": { @@ -1454,6 +1539,11 @@ "jwa": "^1.4.1", "safe-buffer": "^5.0.1" } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" } } }, @@ -1622,37 +1712,6 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, - "object-inspect": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", - "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==" - }, - "object-is": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.2.tgz", - "integrity": "sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==", - "optional": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -1684,9 +1743,9 @@ "integrity": "sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw==" }, "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz", + "integrity": "sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==", "optional": true, "requires": { "p-try": "^2.0.0" @@ -1837,16 +1896,6 @@ } } }, - "regexp.prototype.flags": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", - "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", - "optional": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - } - }, "retry-request": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-4.1.1.tgz", @@ -1934,16 +1983,6 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" }, - "side-channel": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.2.tgz", - "integrity": "sha512-7rL9YlPHg7Ancea1S96Pa8/QWb4BtXL/TZvS6B8XFetGBeuhAsfmUspK6DokBeZ64+Kj9TCNRD/30pVz1BvQNA==", - "optional": true, - "requires": { - "es-abstract": "^1.17.0-next.1", - "object-inspect": "^1.7.0" - } - }, "signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", @@ -1980,44 +2019,6 @@ "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" }, - "string.prototype.trimend": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", - "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "string.prototype.trimleft": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", - "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5", - "string.prototype.trimstart": "^1.0.0" - } - }, - "string.prototype.trimright": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", - "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5", - "string.prototype.trimend": "^1.0.0" - } - }, - "string.prototype.trimstart": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", - "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -2040,16 +2041,16 @@ "optional": true }, "teeny-request": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-6.0.3.tgz", - "integrity": "sha512-TZG/dfd2r6yeji19es1cUIwAlVD8y+/svB1kAC2Y0bjEyysrfbO8EZvJBRwIE6WkwmUoB7uvWLwTIhJbMXZ1Dw==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-7.0.0.tgz", + "integrity": "sha512-kWD3sdGmIix6w7c8ZdVKxWq+3YwVPGWz+Mq0wRZXayEKY/YHb63b8uphfBzcFDmyq8frD9+UTc3wLyOhltRbtg==", "optional": true, "requires": { "http-proxy-agent": "^4.0.0", "https-proxy-agent": "^5.0.0", "node-fetch": "^2.2.0", "stream-events": "^1.0.5", - "uuid": "^7.0.0" + "uuid": "^8.0.0" } }, "through2": { @@ -2066,9 +2067,9 @@ "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, "tslib": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", - "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==" + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==" }, "type-is": { "version": "1.6.18", @@ -2119,9 +2120,9 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", - "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.2.0.tgz", + "integrity": "sha512-CYpGiFTUrmI6OBMkAdjSDM0k5h8SkkiTP4WAjQgDgNB1S3Ou9VBEvr6q0Kv2H1mMk7IWfxYGpMH5sd5AvcIV2Q==", "optional": true }, "vary": { @@ -2149,45 +2150,6 @@ "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==" }, - "which-boxed-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.1.tgz", - "integrity": "sha512-7BT4TwISdDGBgaemWU0N0OU7FeAEJ9Oo2P1PHRm/FCWoEi2VLWC9b6xvxAA3C/NMpxg3HXVgi0sMmGbNUbNepQ==", - "optional": true, - "requires": { - "is-bigint": "^1.0.0", - "is-boolean-object": "^1.0.0", - "is-number-object": "^1.0.3", - "is-string": "^1.0.4", - "is-symbol": "^1.0.2" - } - }, - "which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", - "optional": true, - "requires": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" - } - }, - "which-typed-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.2.tgz", - "integrity": "sha512-KT6okrd1tE6JdZAy3o2VhMoYPh3+J6EMZLyrxBQsZflI1QCZIxMrIYLkosd8Twf+YfknVIHmYQPgJt238p8dnQ==", - "optional": true, - "requires": { - "available-typed-arrays": "^1.0.2", - "es-abstract": "^1.17.5", - "foreach": "^2.0.5", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.1", - "is-typed-array": "^1.1.3" - } - }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -2214,7 +2176,8 @@ "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "optional": true }, "yallist": { "version": "3.1.1", diff --git a/firebase/functions/package.json b/firebase/functions/package.json index 8a03a7717c..bf39e403f5 100644 --- a/firebase/functions/package.json +++ b/firebase/functions/package.json @@ -14,7 +14,7 @@ "dependencies": { "@google-cloud/pubsub": "2.3.0", "@google-cloud/iot": "1.8.0", - "firebase-admin": "8.12.1", + "firebase-admin": "9.0.0", "firebase-functions": "3.7.0", "extend": "3.0.2" }, From 338cada75c1ae5b46f0f00c37f18fa8bed28cdc1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Jul 2020 16:21:50 -0700 Subject: [PATCH 044/212] Update dependency com.github.johnrengelman.shadow:com.github.johnrengelman.shadow.gradle.plugin to v6 (#484) --- mudacl/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mudacl/build.gradle b/mudacl/build.gradle index 0246b206a0..afe8ce0675 100644 --- a/mudacl/build.gradle +++ b/mudacl/build.gradle @@ -10,7 +10,7 @@ buildscript { } plugins { - id 'com.github.johnrengelman.shadow' version '5.2.0' + id 'com.github.johnrengelman.shadow' version '6.0.0' id 'java' id 'maven' } From 845b12c3ad6df8e46b320ceec5081e7b2efdb833 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Jul 2020 16:25:03 -0700 Subject: [PATCH 045/212] Update dependency io.grpc:grpc-netty-shaded to v1.30.2 (#512) --- usi/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usi/pom.xml b/usi/pom.xml index 623acc4d95..803d78baac 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -38,7 +38,7 @@ io.grpc grpc-netty-shaded - 1.30.0 + 1.30.2 io.grpc From c216cd2b577dacd9430aedcf0fe128f80352905f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Jul 2020 17:18:30 -0700 Subject: [PATCH 046/212] Update dependency com.fasterxml.jackson.dataformat:jackson-dataformat-yaml to v2.11.1 (#504) --- mudacl/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mudacl/build.gradle b/mudacl/build.gradle index afe8ce0675..204a99cf9f 100644 --- a/mudacl/build.gradle +++ b/mudacl/build.gradle @@ -33,6 +33,6 @@ repositories { dependencies { compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.11.0' - compile group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: '2.11.0' + compile group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: '2.11.1' testCompile group: 'junit', name: 'junit', version: '4.13' } From 5407413c0de94774d0442d3814e2f9d2fd0e1c4f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Jul 2020 17:19:13 -0700 Subject: [PATCH 047/212] Update dependency io.grpc:grpc-bom to v1.30.2 (#511) --- usi/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usi/pom.xml b/usi/pom.xml index 803d78baac..2b5d27de2a 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -16,7 +16,7 @@ io.grpc grpc-bom - 1.30.0 + 1.30.2 pom import From 2c32e9076f53c7c4159e831c8a7dc0917d72af10 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Jul 2020 17:20:30 -0700 Subject: [PATCH 048/212] Update dependency io.grpc:grpc-protobuf to v1.30.2 (#513) --- usi/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usi/pom.xml b/usi/pom.xml index 2b5d27de2a..090fcb822f 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -43,7 +43,7 @@ io.grpc grpc-protobuf - 1.30.0 + 1.30.2 io.grpc From 098b315cd16672aa42594a4d33eef7fcb6f06320 Mon Sep 17 00:00:00 2001 From: Trevor Pering Date: Tue, 21 Jul 2020 19:21:16 -0700 Subject: [PATCH 049/212] Updating changelog --- docs/changelog.md | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index e3a796f4a1..6d703a78a4 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,10 +1,22 @@ # Changelog +* 1.8.0 + * add security.ssh.version test (#523) + * Refactor UDMI to external repo (#544) + * Additional DHCP test part 3: IP change test (#543) + * Additional DHCP test part 2: Multisubnet test (#539) + * Additional DHCP test part 1 (#532) + * Support for alternate sec switch (not managed by DAQ) (#531) + * Add troubleshooting script (#529) + * Using usi in daq (#520) + * Use trunk rather than stack between switches (#526) + * NTPv4 support (#487) + * Feature/usi OVS switch (#521) * 1.7.0 - * Add DAQ version to origin summary (#522) - * Add check for git version tag in Travis (#519) - * Minor UDMI updates for pubber keygen - * Update Minimum Send Test (#498) - * Universal Switch Interface (USI) (#496) + * Add DAQ version to origin summary (#522) + * Add check for git version tag in Travis (#519) + * Minor UDMI updates for pubber keygen + * Update Minimum Send Test (#498) + * Universal Switch Interface (USI) (#496) * 1.6.1 * fix image pull in cmd/build (#503) * 1.6.0 From 123316f32fa616137300ba3b7583a65afbff503d Mon Sep 17 00:00:00 2001 From: Trevor Pering Date: Tue, 21 Jul 2020 19:56:22 -0700 Subject: [PATCH 050/212] 1.8.1 release --- etc/docker_images.txt | 2 +- etc/docker_images.ver | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/etc/docker_images.txt b/etc/docker_images.txt index 3301febd41..b72bc23d9d 100644 --- a/etc/docker_images.txt +++ b/etc/docker_images.txt @@ -24,4 +24,4 @@ daqf/test_ssh 054efbf1b3c3 daqf/test_switch bfca153bb3fe daqf/test_tls 50bf58dd9a6f daqf/test_udmi 41c2ab08ec86 -daqf/usi e5b85be7cd9b +daqf/usi 7c759bd7b941 diff --git a/etc/docker_images.ver b/etc/docker_images.ver index 27f9cd322b..a8fdfda1c7 100644 --- a/etc/docker_images.ver +++ b/etc/docker_images.ver @@ -1 +1 @@ -1.8.0 +1.8.1 From c7a5eaffe3c203a13be4ecad85abfced1705870d Mon Sep 17 00:00:00 2001 From: henry54809 Date: Tue, 21 Jul 2020 20:29:59 -0700 Subject: [PATCH 051/212] GRPC timeouts + usi first command wait fix. (#555) --- config/system/default.yaml | 1 + daq/host.py | 10 +- firebase/public/protos.hash | 2 +- firebase/public/protos.html | 7 + libs/proto/system_config_pb2.py | 140 +++++++++--------- proto/system_config.proto | 1 + .../daq/usi/allied/AlliedTelesisX230.java | 2 + .../main/java/daq/usi/cisco/Cisco9300.java | 2 + .../test/resources/{src.ofctl => sec.ofctl} | 0 9 files changed, 94 insertions(+), 71 deletions(-) rename usi/src/test/resources/{src.ofctl => sec.ofctl} (100%) diff --git a/config/system/default.yaml b/config/system/default.yaml index ad6eb37ed8..538ae0090f 100644 --- a/config/system/default.yaml +++ b/config/system/default.yaml @@ -44,3 +44,4 @@ topology_hook: bin/dump_network # usi url for DAQ to connect to usi_setup: url: localhost:5000 + rpc_timeout_sec: 10 diff --git a/daq/host.py b/daq/host.py index bea977cac0..16562b929a 100644 --- a/daq/host.py +++ b/daq/host.py @@ -68,6 +68,7 @@ class ConnectedHost: """Class managing a device-under-test""" _STARTUP_MIN_TIME_SEC = 5 + _RPC_TIMEOUT_SEC = 10 _INST_DIR = "inst/" _DEVICE_PATH = "device/%s" _NETWORK_DIR = "inst/network" @@ -108,8 +109,8 @@ def __init__(self, runner, gateway, target, config): _default_timeout_sec = int(config.get('default_timeout_sec', 0)) self._default_timeout_sec = _default_timeout_sec if _default_timeout_sec else None self._finish_hook_script = config.get('finish_hook') + self._usi_config = config.get('usi_setup', {}) self._topology_hook_script = config.get('topology_hook') - self._usi_url = config.get('usi_setup', {}).get('url') self._mirror_intf_name = None self._monitor_ref = None self._monitor_start = None @@ -330,12 +331,13 @@ def connect_port(self, connect): self.logger.info('No switch model found, skipping port connect') return False try: - with grpc.insecure_channel(self._usi_url) as channel: + with grpc.insecure_channel(self._usi_config.get('url')) as channel: + timeout = self._usi_config.get('rpc_timeout_sec', self._RPC_TIMEOUT_SEC) stub = usi_service.USIServiceStub(channel) if connect: - res = stub.connect(switch_info) + res = stub.connect(switch_info, timeout=timeout) else: - res = stub.disconnect(switch_info) + res = stub.disconnect(switch_info, timeout=timeout) self.logger.info('Target port %s %s successful? %s', self.target_port, "connect" if connect else "disconnect", res.success) except Exception as e: diff --git a/firebase/public/protos.hash b/firebase/public/protos.hash index 4aac4f8d1a..5d00da6704 100644 --- a/firebase/public/protos.hash +++ b/firebase/public/protos.hash @@ -1 +1 @@ -fcc9343150752d10ac303fde1caa833d19b0c263 proto/system_config.proto +1f6e7f1a7517da9544eab551d16b7bd650c2d4ae proto/system_config.proto diff --git a/firebase/public/protos.html b/firebase/public/protos.html index 3e00a26efd..b0929b316a 100644 --- a/firebase/public/protos.html +++ b/firebase/public/protos.html @@ -714,6 +714,13 @@

        USISetup

        + + rpc_timeout_sec + int32 + +

        + + diff --git a/libs/proto/system_config_pb2.py b/libs/proto/system_config_pb2.py index 99063d996d..89ee2bc00b 100644 --- a/libs/proto/system_config_pb2.py +++ b/libs/proto/system_config_pb2.py @@ -1,7 +1,8 @@ -# -*- coding: utf-8 -*- # Generated by the protocol buffer compiler. DO NOT EDIT! # source: daq/proto/system_config.proto +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection @@ -18,7 +19,7 @@ package='', syntax='proto3', serialized_options=None, - serialized_pb=b'\n\x1d\x64\x61q/proto/system_config.proto\"\x9d\x08\n\tDaqConfig\x12\x18\n\x10site_description\x18\x01 \x01(\t\x12\x18\n\x10monitor_scan_sec\x18\x02 \x01(\x05\x12\x1b\n\x13\x64\x65\x66\x61ult_timeout_sec\x18\x03 \x01(\x05\x12\x12\n\nsettle_sec\x18& \x01(\x05\x12\x11\n\tbase_conf\x18\x04 \x01(\t\x12\x11\n\tsite_path\x18\x05 \x01(\t\x12\x1f\n\x17initial_dhcp_lease_time\x18\x06 \x01(\t\x12\x17\n\x0f\x64hcp_lease_time\x18\x07 \x01(\t\x12\x19\n\x11\x64hcp_response_sec\x18\' \x01(\x05\x12\x1e\n\x16long_dhcp_response_sec\x18\x08 \x01(\x05\x12\"\n\x0cswitch_setup\x18\t \x01(\x0b\x32\x0c.SwitchSetup\x12\x12\n\nhost_tests\x18\x10 \x01(\t\x12\x13\n\x0b\x62uild_tests\x18$ \x01(\x08\x12\x11\n\trun_limit\x18\x11 \x01(\x05\x12\x11\n\tfail_mode\x18\x12 \x01(\x08\x12\x13\n\x0bsingle_shot\x18\" \x01(\x08\x12\x15\n\rresult_linger\x18\x13 \x01(\x08\x12\x0f\n\x07no_test\x18\x14 \x01(\x08\x12\x11\n\tkeep_hold\x18( \x01(\x08\x12\x14\n\x0c\x64\x61q_loglevel\x18\x15 \x01(\t\x12\x18\n\x10mininet_loglevel\x18\x16 \x01(\t\x12\x13\n\x0b\x66inish_hook\x18# \x01(\t\x12\x10\n\x08gcp_cred\x18\x17 \x01(\t\x12\x11\n\tgcp_topic\x18\x18 \x01(\t\x12\x13\n\x0bschema_path\x18\x19 \x01(\t\x12\x11\n\tmud_files\x18\x1a \x01(\t\x12\x14\n\x0c\x64\x65vice_specs\x18\x1b \x01(\t\x12\x13\n\x0btest_config\x18\x1c \x01(\t\x12\x19\n\x11port_debounce_sec\x18\x1d \x01(\x05\x12\x15\n\rtopology_hook\x18\x1e \x01(\t\x12\x17\n\x0f\x64\x65vice_template\x18\x1f \x01(\t\x12\x14\n\x0csite_reports\x18 \x01(\t\x12\x1f\n\x17run_data_retention_days\x18! \x01(\x02\x12.\n\ninterfaces\x18% \x03(\x0b\x32\x1a.DaqConfig.InterfacesEntry\x12/\n\x0b\x66\x61il_module\x18/ \x03(\x0b\x32\x1a.DaqConfig.FailModuleEntry\x12\x1d\n\x15port_flap_timeout_sec\x18\x30 \x01(\x05\x12\x1c\n\tusi_setup\x18\x31 \x01(\x0b\x32\t.USISetup\x1a=\n\x0fInterfacesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x19\n\x05value\x18\x02 \x01(\x0b\x32\n.Interface:\x02\x38\x01\x1a\x31\n\x0f\x46\x61ilModuleEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x17\n\x08USISetup\x12\x0b\n\x03url\x18\x01 \x01(\t\"\xf4\x01\n\x0bSwitchSetup\x12\x11\n\tctrl_intf\x18\t \x01(\t\x12\x0f\n\x07ip_addr\x18\x0b \x01(\t\x12\x13\n\x0buplink_port\x18\r \x01(\x05\x12\x0f\n\x07lo_port\x18\x0e \x01(\x05\x12\x10\n\x08\x61lt_port\x18\x10 \x01(\x05\x12\x0f\n\x07lo_addr\x18\x12 \x01(\t\x12\x11\n\tmods_addr\x18\x14 \x01(\t\x12\x0f\n\x07of_dpid\x18) \x01(\t\x12\x11\n\tdata_intf\x18* \x01(\t\x12\x0e\n\x06\x65xt_br\x18+ \x01(\t\x12\r\n\x05model\x18, \x01(\t\x12\x10\n\x08username\x18- \x01(\t\x12\x10\n\x08password\x18. \x01(\t\"\'\n\tInterface\x12\x0c\n\x04opts\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05\x62\x06proto3' + serialized_pb=_b('\n\x1d\x64\x61q/proto/system_config.proto\"\x9d\x08\n\tDaqConfig\x12\x18\n\x10site_description\x18\x01 \x01(\t\x12\x18\n\x10monitor_scan_sec\x18\x02 \x01(\x05\x12\x1b\n\x13\x64\x65\x66\x61ult_timeout_sec\x18\x03 \x01(\x05\x12\x12\n\nsettle_sec\x18& \x01(\x05\x12\x11\n\tbase_conf\x18\x04 \x01(\t\x12\x11\n\tsite_path\x18\x05 \x01(\t\x12\x1f\n\x17initial_dhcp_lease_time\x18\x06 \x01(\t\x12\x17\n\x0f\x64hcp_lease_time\x18\x07 \x01(\t\x12\x19\n\x11\x64hcp_response_sec\x18\' \x01(\x05\x12\x1e\n\x16long_dhcp_response_sec\x18\x08 \x01(\x05\x12\"\n\x0cswitch_setup\x18\t \x01(\x0b\x32\x0c.SwitchSetup\x12\x12\n\nhost_tests\x18\x10 \x01(\t\x12\x13\n\x0b\x62uild_tests\x18$ \x01(\x08\x12\x11\n\trun_limit\x18\x11 \x01(\x05\x12\x11\n\tfail_mode\x18\x12 \x01(\x08\x12\x13\n\x0bsingle_shot\x18\" \x01(\x08\x12\x15\n\rresult_linger\x18\x13 \x01(\x08\x12\x0f\n\x07no_test\x18\x14 \x01(\x08\x12\x11\n\tkeep_hold\x18( \x01(\x08\x12\x14\n\x0c\x64\x61q_loglevel\x18\x15 \x01(\t\x12\x18\n\x10mininet_loglevel\x18\x16 \x01(\t\x12\x13\n\x0b\x66inish_hook\x18# \x01(\t\x12\x10\n\x08gcp_cred\x18\x17 \x01(\t\x12\x11\n\tgcp_topic\x18\x18 \x01(\t\x12\x13\n\x0bschema_path\x18\x19 \x01(\t\x12\x11\n\tmud_files\x18\x1a \x01(\t\x12\x14\n\x0c\x64\x65vice_specs\x18\x1b \x01(\t\x12\x13\n\x0btest_config\x18\x1c \x01(\t\x12\x19\n\x11port_debounce_sec\x18\x1d \x01(\x05\x12\x15\n\rtopology_hook\x18\x1e \x01(\t\x12\x17\n\x0f\x64\x65vice_template\x18\x1f \x01(\t\x12\x14\n\x0csite_reports\x18 \x01(\t\x12\x1f\n\x17run_data_retention_days\x18! \x01(\x02\x12.\n\ninterfaces\x18% \x03(\x0b\x32\x1a.DaqConfig.InterfacesEntry\x12/\n\x0b\x66\x61il_module\x18/ \x03(\x0b\x32\x1a.DaqConfig.FailModuleEntry\x12\x1d\n\x15port_flap_timeout_sec\x18\x30 \x01(\x05\x12\x1c\n\tusi_setup\x18\x31 \x01(\x0b\x32\t.USISetup\x1a=\n\x0fInterfacesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x19\n\x05value\x18\x02 \x01(\x0b\x32\n.Interface:\x02\x38\x01\x1a\x31\n\x0f\x46\x61ilModuleEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"0\n\x08USISetup\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x17\n\x0frpc_timeout_sec\x18\x02 \x01(\x05\"\xf4\x01\n\x0bSwitchSetup\x12\x11\n\tctrl_intf\x18\t \x01(\t\x12\x0f\n\x07ip_addr\x18\x0b \x01(\t\x12\x13\n\x0buplink_port\x18\r \x01(\x05\x12\x0f\n\x07lo_port\x18\x0e \x01(\x05\x12\x10\n\x08\x61lt_port\x18\x10 \x01(\x05\x12\x0f\n\x07lo_addr\x18\x12 \x01(\t\x12\x11\n\tmods_addr\x18\x14 \x01(\t\x12\x0f\n\x07of_dpid\x18) \x01(\t\x12\x11\n\tdata_intf\x18* \x01(\t\x12\x0e\n\x06\x65xt_br\x18+ \x01(\t\x12\r\n\x05model\x18, \x01(\t\x12\x10\n\x08username\x18- \x01(\t\x12\x10\n\x08password\x18. \x01(\t\"\'\n\tInterface\x12\x0c\n\x04opts\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05\x62\x06proto3') ) @@ -34,7 +35,7 @@ _descriptor.FieldDescriptor( name='key', full_name='DaqConfig.InterfacesEntry.key', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -51,7 +52,7 @@ nested_types=[], enum_types=[ ], - serialized_options=b'8\001', + serialized_options=_b('8\001'), is_extendable=False, syntax='proto3', extension_ranges=[], @@ -71,14 +72,14 @@ _descriptor.FieldDescriptor( name='key', full_name='DaqConfig.FailModuleEntry.key', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='value', full_name='DaqConfig.FailModuleEntry.value', index=1, number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -88,7 +89,7 @@ nested_types=[], enum_types=[ ], - serialized_options=b'8\001', + serialized_options=_b('8\001'), is_extendable=False, syntax='proto3', extension_ranges=[], @@ -108,7 +109,7 @@ _descriptor.FieldDescriptor( name='site_description', full_name='DaqConfig.site_description', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -136,28 +137,28 @@ _descriptor.FieldDescriptor( name='base_conf', full_name='DaqConfig.base_conf', index=4, number=4, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='site_path', full_name='DaqConfig.site_path', index=5, number=5, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='initial_dhcp_lease_time', full_name='DaqConfig.initial_dhcp_lease_time', index=6, number=6, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='dhcp_lease_time', full_name='DaqConfig.dhcp_lease_time', index=7, number=7, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -185,7 +186,7 @@ _descriptor.FieldDescriptor( name='host_tests', full_name='DaqConfig.host_tests', index=11, number=16, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -241,63 +242,63 @@ _descriptor.FieldDescriptor( name='daq_loglevel', full_name='DaqConfig.daq_loglevel', index=19, number=21, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='mininet_loglevel', full_name='DaqConfig.mininet_loglevel', index=20, number=22, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='finish_hook', full_name='DaqConfig.finish_hook', index=21, number=35, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='gcp_cred', full_name='DaqConfig.gcp_cred', index=22, number=23, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='gcp_topic', full_name='DaqConfig.gcp_topic', index=23, number=24, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='schema_path', full_name='DaqConfig.schema_path', index=24, number=25, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='mud_files', full_name='DaqConfig.mud_files', index=25, number=26, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='device_specs', full_name='DaqConfig.device_specs', index=26, number=27, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='test_config', full_name='DaqConfig.test_config', index=27, number=28, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -311,21 +312,21 @@ _descriptor.FieldDescriptor( name='topology_hook', full_name='DaqConfig.topology_hook', index=29, number=30, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='device_template', full_name='DaqConfig.device_template', index=30, number=31, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='site_reports', full_name='DaqConfig.site_reports', index=31, number=32, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -391,7 +392,14 @@ _descriptor.FieldDescriptor( name='url', full_name='USISetup.url', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='rpc_timeout_sec', full_name='USISetup.rpc_timeout_sec', index=1, + number=2, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -408,7 +416,7 @@ oneofs=[ ], serialized_start=1089, - serialized_end=1112, + serialized_end=1137, ) @@ -422,14 +430,14 @@ _descriptor.FieldDescriptor( name='ctrl_intf', full_name='SwitchSetup.ctrl_intf', index=0, number=9, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='ip_addr', full_name='SwitchSetup.ip_addr', index=1, number=11, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -457,56 +465,56 @@ _descriptor.FieldDescriptor( name='lo_addr', full_name='SwitchSetup.lo_addr', index=5, number=18, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='mods_addr', full_name='SwitchSetup.mods_addr', index=6, number=20, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='of_dpid', full_name='SwitchSetup.of_dpid', index=7, number=41, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='data_intf', full_name='SwitchSetup.data_intf', index=8, number=42, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='ext_br', full_name='SwitchSetup.ext_br', index=9, number=43, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='model', full_name='SwitchSetup.model', index=10, number=44, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='username', full_name='SwitchSetup.username', index=11, number=45, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='password', full_name='SwitchSetup.password', index=12, number=46, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -522,8 +530,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1115, - serialized_end=1359, + serialized_start=1140, + serialized_end=1384, ) @@ -537,7 +545,7 @@ _descriptor.FieldDescriptor( name='opts', full_name='Interface.opts', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -560,8 +568,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1361, - serialized_end=1400, + serialized_start=1386, + serialized_end=1425, ) _DAQCONFIG_INTERFACESENTRY.fields_by_name['value'].message_type = _INTERFACE @@ -577,48 +585,48 @@ DESCRIPTOR.message_types_by_name['Interface'] = _INTERFACE _sym_db.RegisterFileDescriptor(DESCRIPTOR) -DaqConfig = _reflection.GeneratedProtocolMessageType('DaqConfig', (_message.Message,), { +DaqConfig = _reflection.GeneratedProtocolMessageType('DaqConfig', (_message.Message,), dict( - 'InterfacesEntry' : _reflection.GeneratedProtocolMessageType('InterfacesEntry', (_message.Message,), { - 'DESCRIPTOR' : _DAQCONFIG_INTERFACESENTRY, - '__module__' : 'daq.proto.system_config_pb2' + InterfacesEntry = _reflection.GeneratedProtocolMessageType('InterfacesEntry', (_message.Message,), dict( + DESCRIPTOR = _DAQCONFIG_INTERFACESENTRY, + __module__ = 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:DaqConfig.InterfacesEntry) - }) + )) , - 'FailModuleEntry' : _reflection.GeneratedProtocolMessageType('FailModuleEntry', (_message.Message,), { - 'DESCRIPTOR' : _DAQCONFIG_FAILMODULEENTRY, - '__module__' : 'daq.proto.system_config_pb2' + FailModuleEntry = _reflection.GeneratedProtocolMessageType('FailModuleEntry', (_message.Message,), dict( + DESCRIPTOR = _DAQCONFIG_FAILMODULEENTRY, + __module__ = 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:DaqConfig.FailModuleEntry) - }) + )) , - 'DESCRIPTOR' : _DAQCONFIG, - '__module__' : 'daq.proto.system_config_pb2' + DESCRIPTOR = _DAQCONFIG, + __module__ = 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:DaqConfig) - }) + )) _sym_db.RegisterMessage(DaqConfig) _sym_db.RegisterMessage(DaqConfig.InterfacesEntry) _sym_db.RegisterMessage(DaqConfig.FailModuleEntry) -USISetup = _reflection.GeneratedProtocolMessageType('USISetup', (_message.Message,), { - 'DESCRIPTOR' : _USISETUP, - '__module__' : 'daq.proto.system_config_pb2' +USISetup = _reflection.GeneratedProtocolMessageType('USISetup', (_message.Message,), dict( + DESCRIPTOR = _USISETUP, + __module__ = 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:USISetup) - }) + )) _sym_db.RegisterMessage(USISetup) -SwitchSetup = _reflection.GeneratedProtocolMessageType('SwitchSetup', (_message.Message,), { - 'DESCRIPTOR' : _SWITCHSETUP, - '__module__' : 'daq.proto.system_config_pb2' +SwitchSetup = _reflection.GeneratedProtocolMessageType('SwitchSetup', (_message.Message,), dict( + DESCRIPTOR = _SWITCHSETUP, + __module__ = 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:SwitchSetup) - }) + )) _sym_db.RegisterMessage(SwitchSetup) -Interface = _reflection.GeneratedProtocolMessageType('Interface', (_message.Message,), { - 'DESCRIPTOR' : _INTERFACE, - '__module__' : 'daq.proto.system_config_pb2' +Interface = _reflection.GeneratedProtocolMessageType('Interface', (_message.Message,), dict( + DESCRIPTOR = _INTERFACE, + __module__ = 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:Interface) - }) + )) _sym_db.RegisterMessage(Interface) diff --git a/proto/system_config.proto b/proto/system_config.proto index babf0abe45..5c334e728b 100644 --- a/proto/system_config.proto +++ b/proto/system_config.proto @@ -124,6 +124,7 @@ message DaqConfig { **/ message USISetup { string url = 1; + int32 rpc_timeout_sec = 2; } /* diff --git a/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java b/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java index 1b36d26fab..15af00f907 100644 --- a/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java +++ b/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java @@ -65,6 +65,7 @@ public AlliedTelesisX230( super(remoteIpAddress, user, password, debug); this.username = user == null ? "manager" : user; this.password = password == null ? "friend" : password; + commandPending = true; } @Override @@ -248,6 +249,7 @@ private Map processPowerStatusInline(String response) { public void handleEnableMessage(String consoleData) throws Exception { if (containsPrompt(consoleData)) { userEnabled = true; + commandPending = false; } } diff --git a/usi/src/main/java/daq/usi/cisco/Cisco9300.java b/usi/src/main/java/daq/usi/cisco/Cisco9300.java index b63ae64285..fded5d6041 100644 --- a/usi/src/main/java/daq/usi/cisco/Cisco9300.java +++ b/usi/src/main/java/daq/usi/cisco/Cisco9300.java @@ -50,6 +50,7 @@ public Cisco9300( super(remoteIpAddress, user, password); this.username = user == null ? "admin" : user; this.password = password == null ? "password" : password; + commandPending = true; } /** @@ -95,6 +96,7 @@ public void handleEnableMessage(String consoleData) throws Exception { telnetClientSocket.writeData(password + "\n"); } else if (containsPrompt(consoleData)) { userEnabled = true; + commandPending = false; } else if (consoleData.contains("% Bad passwords")) { telnetClientSocket.disposeConnection(); throw new Exception("Could not Enable the User, Bad Password"); diff --git a/usi/src/test/resources/src.ofctl b/usi/src/test/resources/sec.ofctl similarity index 100% rename from usi/src/test/resources/src.ofctl rename to usi/src/test/resources/sec.ofctl From c3164948be24d31697f713548165295ea0c4e936 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Jul 2020 20:43:11 -0700 Subject: [PATCH 052/212] Update dependency jsoneditor to v9.0.3 (#501) --- firebase/public/config.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firebase/public/config.html b/firebase/public/config.html index f94216c57f..3149596f26 100644 --- a/firebase/public/config.html +++ b/firebase/public/config.html @@ -11,8 +11,8 @@ - - + +
        From 29f168e98ae89c133689e3877451349792d30fbf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Jul 2020 20:45:46 -0700 Subject: [PATCH 053/212] Update dependency io.grpc:grpc-stub to v1.30.2 (#514) --- usi/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usi/pom.xml b/usi/pom.xml index 090fcb822f..59cf28ad1a 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -48,7 +48,7 @@ io.grpc grpc-stub - 1.30.0 + 1.30.2 org.apache.tomcat From b26d5d9e38fb201e21d3e84e2468e0398cf0e981 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Jul 2020 20:46:46 -0700 Subject: [PATCH 054/212] Update dependency firebase-functions to v3.8.0 (#533) --- firebase/functions/package-lock.json | 12 ++++++------ firebase/functions/package.json | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/firebase/functions/package-lock.json b/firebase/functions/package-lock.json index 44afb953cc..0ed8a55711 100644 --- a/firebase/functions/package-lock.json +++ b/firebase/functions/package-lock.json @@ -704,9 +704,9 @@ } }, "@types/express-serve-static-core": { - "version": "4.17.7", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.7.tgz", - "integrity": "sha512-EMgTj/DF9qpgLXyc+Btimg+XoH7A2liE8uKul8qSmMTHCeNYzydDKFdsJskDvw42UsesCnhO63dO0Grbj8J4Dw==", + "version": "4.17.8", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.8.tgz", + "integrity": "sha512-1SJZ+R3Q/7mLkOD9ewCBDYD2k0WyZQtWYqF/2VvoNN2/uhI49J9CDN4OAm+wGMA0DbArA4ef27xl4+JwMtGggw==", "requires": { "@types/node": "*", "@types/qs": "*", @@ -1177,9 +1177,9 @@ } }, "firebase-functions": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-3.7.0.tgz", - "integrity": "sha512-+ROj2Gs2/KyM+T8jYo7AKaHynFsN49sXbgZMll3zuGa9/8oiDsXp9e1Iy2JMkFmSZg67jeYw5Ue2OSpz0XiqFQ==", + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-3.8.0.tgz", + "integrity": "sha512-RFvoS7ZcXrk2sQ918czsjv94p4hnSoD0/e4cZ86XFpa1HbNZBI7ZuSgBCzRvlv6dJ1ArytAL13NpB1Bp2tJ6Yg==", "requires": { "@types/express": "4.17.3", "cors": "^2.8.5", diff --git a/firebase/functions/package.json b/firebase/functions/package.json index bf39e403f5..d75ce0b03f 100644 --- a/firebase/functions/package.json +++ b/firebase/functions/package.json @@ -15,7 +15,7 @@ "@google-cloud/pubsub": "2.3.0", "@google-cloud/iot": "1.8.0", "firebase-admin": "9.0.0", - "firebase-functions": "3.7.0", + "firebase-functions": "3.8.0", "extend": "3.0.2" }, "private": true From 56af1e4b0e9fb6d28f00b0e9c76bf3503e3c1828 Mon Sep 17 00:00:00 2001 From: Trevor Pering Date: Tue, 21 Jul 2020 21:40:51 -0700 Subject: [PATCH 055/212] Adding more changelog items --- docs/changelog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index 6d703a78a4..54c014b97a 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,4 +1,7 @@ # Changelog +* 1.8.2 + * GRPC timeouts + usi first command wait fix. (#555) + * Numerous renovate bot updates. * 1.8.0 * add security.ssh.version test (#523) * Refactor UDMI to external repo (#544) From 097ea2dd0df6656df86fd4a4f5cbb691b3cf8b2e Mon Sep 17 00:00:00 2001 From: Trevor Pering Date: Tue, 21 Jul 2020 22:04:12 -0700 Subject: [PATCH 056/212] 1.8.2 release --- etc/docker_images.txt | 2 +- etc/docker_images.ver | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/etc/docker_images.txt b/etc/docker_images.txt index b72bc23d9d..a4b7dc8af8 100644 --- a/etc/docker_images.txt +++ b/etc/docker_images.txt @@ -24,4 +24,4 @@ daqf/test_ssh 054efbf1b3c3 daqf/test_switch bfca153bb3fe daqf/test_tls 50bf58dd9a6f daqf/test_udmi 41c2ab08ec86 -daqf/usi 7c759bd7b941 +daqf/usi ab9976d57693 diff --git a/etc/docker_images.ver b/etc/docker_images.ver index a8fdfda1c7..53adb84c82 100644 --- a/etc/docker_images.ver +++ b/etc/docker_images.ver @@ -1 +1 @@ -1.8.1 +1.8.2 From 368db70952262e60e2c936da0a7b6118b1db81d7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Jul 2020 22:42:37 -0700 Subject: [PATCH 057/212] Update dependency com.fasterxml.jackson.core:jackson-databind to v2.11.1 (#507) --- mudacl/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mudacl/build.gradle b/mudacl/build.gradle index 204a99cf9f..f3667604bb 100644 --- a/mudacl/build.gradle +++ b/mudacl/build.gradle @@ -32,7 +32,7 @@ repositories { } dependencies { - compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.11.0' + compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.11.1' compile group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: '2.11.1' testCompile group: 'junit', name: 'junit', version: '4.13' } From 336710bcde9f281c3604a46b3de6e0f21a6c1460 Mon Sep 17 00:00:00 2001 From: Trevor Date: Thu, 23 Jul 2020 06:44:10 -0700 Subject: [PATCH 058/212] Automatic build script (#557) --- bin/build_release | 82 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100755 bin/build_release diff --git a/bin/build_release b/bin/build_release new file mode 100755 index 0000000000..ac035a50bf --- /dev/null +++ b/bin/build_release @@ -0,0 +1,82 @@ +#!/bin/bash -e + +if [ $# != 1 ]; then + echo $0 RELEASE_VERSION + false +fi + +VERSION=$1 +shift + +ROOT=$(realpath $(dirname $0)/..) +cd $ROOT + +changes=`git status --porcelain` +if [ -n "$changes" ]; then + echo Working tree not clean. + false +fi + +git checkout master + +changed=`git diff --name-only release_stable docs/changelog.md` +if [ -z "$changed" ]; then + git log release_stable..HEAD --pretty=oneline | sed -e 's/[a-z0-9]+/\*/g' + echo docs/changelog.md has not been updated since last release_stable + echo Use the log lines above for inspiration. + false +fi + +tagged=`git rev-list -n 1 $VERSION 2>/dev/null` || true +if [ -n "$tagged" ]; then + echo Tag $VERSION already exists. Try the next version. + false +fi + +source etc/config_base.sh + +if [ "$host_tests" != config/modules/all.conf ]; then + echo Configure your system with host_tests=config/modules/all.conf + false +fi + +cmd/build force $VERSION + +cmd/build push + +cat > /tmp/git_expected.expected < /tmp/git_status.found + +if ! diff /tmp/git_status.expected /tmp/git_status.found; then + echo Expected build images not found. Something went wrong. + false +fi +rm -f /tmp/git_status.* + +git commit -a -m "$VERSION release" +git tag -a $VERSION -m "$VERSION release" +git push +git push --tags + +# Check to see if a remote 'faucet' is defined, and if so, also update that. +faucetgit=`git config remote.faucet.url` +if [ -n "$faucetgit" ]; then + git push faucet + git push faucet --tags +fi + +firebase/deploy.sh bos-daq-testing +git checkout release_testing && git reset --hard $VERSION + +if [ -n "$faucetgit" ]; then + git push faucet +fi + +# QA pass to make sure everything is ok. +# `firebase/deploy.sh daq-qualification-labs` +# `git checkout release_stable && git reset --hard $VERSION` +# `git push` From e38c4a2eebba7e3c7eb0a66a42164b7f98fdb695 Mon Sep 17 00:00:00 2001 From: frgitdaq <62390501+frgitdaq@users.noreply.github.com> Date: Tue, 28 Jul 2020 14:32:03 +0100 Subject: [PATCH 059/212] 27 NTP Update (#525) 27 NTP update test --- docker/include/bin/start_faux | 16 +- docker/modules/Dockerfile.faux1 | 2 +- docs/device_report.md | 9 +- .../qualification/system_module_config.json | 5 + .../remediation/system_module_config.json | 5 + subset/ntp/Dockerfile.test_ntp | 2 +- .../.idea/codeStyles/codeStyleConfig.xml | 5 + subset/ntp/NTPClient/.idea/gradle.xml | 19 ++ .../ntp/NTPClient/.idea/jarRepositories.xml | 20 ++ subset/ntp/NTPClient/.idea/misc.xml | 5 + subset/ntp/NTPClient/.idea/vcs.xml | 6 + subset/ntp/NTPClient/build.gradle | 22 ++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 55190 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + subset/ntp/NTPClient/gradlew | 172 +++++++++++++++ subset/ntp/NTPClient/gradlew.bat | 84 ++++++++ subset/ntp/NTPClient/settings.gradle | 2 + .../src/main/java/META-INF/MANIFEST.MF | 3 + subset/ntp/NTPClient/src/main/java/Main.java | 92 ++++++++ .../NTPClient/src/main/java/NtpMessage.java | 203 ++++++++++++++++++ subset/ntp/README.md | 16 +- subset/ntp/ntp_tests.py | 117 +++++++++- subset/ntp/test_ntp | 5 +- testing/test_aux.out | 3 + 24 files changed, 791 insertions(+), 27 deletions(-) create mode 100644 subset/ntp/NTPClient/.idea/codeStyles/codeStyleConfig.xml create mode 100644 subset/ntp/NTPClient/.idea/gradle.xml create mode 100644 subset/ntp/NTPClient/.idea/jarRepositories.xml create mode 100644 subset/ntp/NTPClient/.idea/misc.xml create mode 100644 subset/ntp/NTPClient/.idea/vcs.xml create mode 100644 subset/ntp/NTPClient/build.gradle create mode 100644 subset/ntp/NTPClient/gradle/wrapper/gradle-wrapper.jar create mode 100644 subset/ntp/NTPClient/gradle/wrapper/gradle-wrapper.properties create mode 100755 subset/ntp/NTPClient/gradlew create mode 100644 subset/ntp/NTPClient/gradlew.bat create mode 100644 subset/ntp/NTPClient/settings.gradle create mode 100644 subset/ntp/NTPClient/src/main/java/META-INF/MANIFEST.MF create mode 100644 subset/ntp/NTPClient/src/main/java/Main.java create mode 100644 subset/ntp/NTPClient/src/main/java/NtpMessage.java diff --git a/docker/include/bin/start_faux b/docker/include/bin/start_faux index d00bacc623..bd1cb160a1 100755 --- a/docker/include/bin/start_faux +++ b/docker/include/bin/start_faux @@ -149,18 +149,16 @@ fi # NTPv3 query to the IP of time.google.com (since resolv.conf is modified by other tests) STATIC_NTP_SERVER=216.239.35.8 if [ -n "${options[ntpv4]}" ]; then - (while date; do - dhcp_ntp=$(fgrep NTPSERVERS= /run/ntpdate.dhcp) - ntp_server=`echo $dhcp_ntp | cut -d "'" -f 2` - echo Transmitting NTP query to $ntp_server using NTPv4 - ntpdate -q -o 4 $ntp_server - sleep 5 - done) & + dhcp_ntp=$(fgrep NTPSERVERS= /run/ntpdate.dhcp) + ntp_server=`echo $dhcp_ntp | cut -d "'" -f 2` + echo Transmitting NTP query to $ntp_server using NTPv4 + java -jar NTPClient/build/libs/NTPClient-1.0-SNAPSHOT.jar $ntp_server 123 4 2 & + sleep 5 elif [ -n "${options[ntpv3]}" ]; then (while date; do echo Transmitting NTP query to $STATIC_NTP_SERVER using NTPv3 - ntpdate -q -o 3 $STATIC_NTP_SERVER - sleep 5 + java -jar NTPClient/build/libs/NTPClient-1.0-SNAPSHOT.jar $STATIC_NTP_SERVER 123 3 2 & + sleep 5 done) & fi diff --git a/docker/modules/Dockerfile.faux1 b/docker/modules/Dockerfile.faux1 index be9c483e0c..c6e76a865b 100644 --- a/docker/modules/Dockerfile.faux1 +++ b/docker/modules/Dockerfile.faux1 @@ -39,7 +39,7 @@ RUN $AG update && $AG install isc-dhcp-client ethtool network-manager netcat cur # Additional OS dependencies RUN $AG update && $AG install -y telnetd && $AG install xinetd nginx -COPY subset/network/NTPClient NTPClient +COPY subset/ntp/NTPClient NTPClient RUN cd NTPClient && ./gradlew build COPY subset/network/TransportClient TransportClient diff --git a/docs/device_report.md b/docs/device_report.md index 4a5be26839..74d7445460 100644 --- a/docs/device_report.md +++ b/docs/device_report.md @@ -56,7 +56,7 @@ Overall device result FAIL |---|---|---|---|---| |Required|1|0|0|0| |Recommended|2|0|0|0| -|Other|2|2|22|2| +|Other|3|2|22|2| |Result|Test|Category|Expectation|Notes| |---|---|---|---|---| @@ -68,6 +68,7 @@ Overall device result FAIL |skip|cloud.udmi.system|Other|Other|No device id| |fail|connection.mac_oui|Other|Other|Manufacturer prefix not found!| |pass|connection.network.ntp_support|Other|Other|Using NTPv4.| +|pass|connection.network.ntp_update|Other|Other|Device clock synchronized.| |skip|connection.port_duplex|Other|Other|No local IP has been set, check system config| |skip|connection.port_link|Other|Other|No local IP has been set, check system config| |skip|connection.port_speed|Other|Other|No local IP has been set, check system config| @@ -571,6 +572,12 @@ connection.network.ntp_support Device supports NTP version 4. -------------------- RESULT pass connection.network.ntp_support Using NTPv4. +-------------------- +connection.network.ntp_update +-------------------- +Device synchronizes its time to the NTP server. +-------------------- +RESULT pass connection.network.ntp_update Device clock synchronized. ``` #### Module Config diff --git a/resources/setups/qualification/system_module_config.json b/resources/setups/qualification/system_module_config.json index 8b1926a3f1..be6d1bf2ef 100644 --- a/resources/setups/qualification/system_module_config.json +++ b/resources/setups/qualification/system_module_config.json @@ -93,6 +93,11 @@ "required": "pass", "expected": "Required Pass" }, + "connection.network.ntp_update": { + "category": "Network Time", + "required": "pass", + "expected": "Required Pass" + }, "connection.network.communication_type": { "category": "Communication", "required": "info", diff --git a/resources/setups/remediation/system_module_config.json b/resources/setups/remediation/system_module_config.json index 754145aa9e..58fb3fa9f4 100644 --- a/resources/setups/remediation/system_module_config.json +++ b/resources/setups/remediation/system_module_config.json @@ -89,6 +89,11 @@ "required": "pass", "expected": "Recommended Pass" }, + "connection.network.ntp_update": { + "category": "Network Time", + "required": "pass", + "expected": "Recommended Pass" + }, "connection.network.communication_type": { "category": "Communication", "required": "info", diff --git a/subset/ntp/Dockerfile.test_ntp b/subset/ntp/Dockerfile.test_ntp index 2bfedf5a18..017828d203 100644 --- a/subset/ntp/Dockerfile.test_ntp +++ b/subset/ntp/Dockerfile.test_ntp @@ -4,7 +4,7 @@ RUN $AG update && $AG install python python-setuptools python-pip netcat RUN pip install scapy -COPY subset/ntp/ntp_tests.py . COPY subset/ntp/test_ntp . +COPY subset/ntp/ntp_tests.py . CMD ["./test_ntp"] diff --git a/subset/ntp/NTPClient/.idea/codeStyles/codeStyleConfig.xml b/subset/ntp/NTPClient/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000000..a55e7a179b --- /dev/null +++ b/subset/ntp/NTPClient/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/subset/ntp/NTPClient/.idea/gradle.xml b/subset/ntp/NTPClient/.idea/gradle.xml new file mode 100644 index 0000000000..5c0b931b2c --- /dev/null +++ b/subset/ntp/NTPClient/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/subset/ntp/NTPClient/.idea/jarRepositories.xml b/subset/ntp/NTPClient/.idea/jarRepositories.xml new file mode 100644 index 0000000000..fdc392fe87 --- /dev/null +++ b/subset/ntp/NTPClient/.idea/jarRepositories.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/subset/ntp/NTPClient/.idea/misc.xml b/subset/ntp/NTPClient/.idea/misc.xml new file mode 100644 index 0000000000..aecc2806d9 --- /dev/null +++ b/subset/ntp/NTPClient/.idea/misc.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/subset/ntp/NTPClient/.idea/vcs.xml b/subset/ntp/NTPClient/.idea/vcs.xml new file mode 100644 index 0000000000..c2365ab11f --- /dev/null +++ b/subset/ntp/NTPClient/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/subset/ntp/NTPClient/build.gradle b/subset/ntp/NTPClient/build.gradle new file mode 100644 index 0000000000..8a3dd211ff --- /dev/null +++ b/subset/ntp/NTPClient/build.gradle @@ -0,0 +1,22 @@ +plugins { + id 'java' +} + +group 'ntp_client' +version '1.0-SNAPSHOT' + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + +dependencies { + testCompile group: 'junit', name: 'junit', version: '4.13' +} + +jar { + manifest { + attributes 'Main-Class': 'Main' + } +} diff --git a/subset/ntp/NTPClient/gradle/wrapper/gradle-wrapper.jar b/subset/ntp/NTPClient/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..87b738cbd051603d91cc39de6cb000dd98fe6b02 GIT binary patch literal 55190 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 z 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 \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/subset/ntp/NTPClient/gradlew.bat b/subset/ntp/NTPClient/gradlew.bat new file mode 100644 index 0000000000..0f8d5937c4 --- /dev/null +++ b/subset/ntp/NTPClient/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/subset/ntp/NTPClient/settings.gradle b/subset/ntp/NTPClient/settings.gradle new file mode 100644 index 0000000000..a6b059db39 --- /dev/null +++ b/subset/ntp/NTPClient/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'NTPClient' + diff --git a/subset/ntp/NTPClient/src/main/java/META-INF/MANIFEST.MF b/subset/ntp/NTPClient/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..37197ef4e8 --- /dev/null +++ b/subset/ntp/NTPClient/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: Main + diff --git a/subset/ntp/NTPClient/src/main/java/Main.java b/subset/ntp/NTPClient/src/main/java/Main.java new file mode 100644 index 0000000000..0bfe635d31 --- /dev/null +++ b/subset/ntp/NTPClient/src/main/java/Main.java @@ -0,0 +1,92 @@ +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.text.DecimalFormat; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +public class Main { + + static final double SECONDS_FROM_01_01_1900_TO_01_01_1970 = 2208988800.0; + static String serverName = "time.google.com"; + static byte version = 3; + static int port = 123; + static int timerPeriod = 10; + static byte leapIndicator = 3; + + /** + * Constructs and sends NTP packets to target NTP server. + */ + + public static void main(String[] args) { + if (args.length < 2) { + throw new IllegalArgumentException("Usage: server_name port version timerPeriod"); + } + serverName = args[0]; + port = Integer.parseInt(args[1]); + version = Byte.parseByte(args[2]); + timerPeriod = Integer.parseInt(args[3]); + + Runnable senderRunnable = new Runnable() { + @Override + public void run() { + try { + sendRequest(); + } catch (IOException e) { + System.out.println(e.getMessage()); + } + } + }; + ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); + executor.scheduleAtFixedRate(senderRunnable, 0, timerPeriod, TimeUnit.SECONDS); + } + + private static void sendRequest() throws IOException { + DatagramSocket socket = new DatagramSocket(); + InetAddress address = InetAddress.getByName(serverName); + byte[] buf = new NtpMessage(SECONDS_FROM_01_01_1900_TO_01_01_1970, leapIndicator, version).toByteArray(); + DatagramPacket packet = new DatagramPacket(buf, buf.length, address, port); + + // Set the transmit timestamp *just* before sending the packet + NtpMessage.encodeTimestamp(packet.getData(), 40, + (System.currentTimeMillis() / 1000.0) + SECONDS_FROM_01_01_1900_TO_01_01_1970); + sendPacket(socket, packet, buf); + } + + private static void sendPacket(DatagramSocket socket, DatagramPacket packet, byte[] buf) throws IOException { + socket.send(packet); + + // Get response + System.out.println("NTP request sent, waiting for response...\n"); + packet = new DatagramPacket(buf, buf.length); + socket.receive(packet); + + // Display response + System.out.println("NTP server: " + serverName); + + // Process response + NtpMessage msg = new NtpMessage(packet.getData()); + + // Immediately record the incoming timestamp + double destinationTimestamp = + (System.currentTimeMillis() / 1000.0) + SECONDS_FROM_01_01_1900_TO_01_01_1970; + System.out.println(msg.toString()); + System.out.println("Dest. timestamp: " + + NtpMessage.timestampToString(destinationTimestamp)); + + double roundTripDelay = (destinationTimestamp - msg.originateTimestamp) + - (msg.transmitTimestamp - msg.receiveTimestamp); + System.out.println("Round-trip delay: " + + new DecimalFormat("0.00").format(roundTripDelay * 1000) + " ms"); + double localClockOffset = + ((msg.receiveTimestamp - msg.originateTimestamp) + + (msg.transmitTimestamp - destinationTimestamp)) / 2; + System.out.println("Local clock offset: " + + new DecimalFormat("0.00").format(localClockOffset * 1000) + " ms"); + if (localClockOffset * 1000 < 128) { + leapIndicator = 0; + } + } +} diff --git a/subset/ntp/NTPClient/src/main/java/NtpMessage.java b/subset/ntp/NTPClient/src/main/java/NtpMessage.java new file mode 100644 index 0000000000..a441b14959 --- /dev/null +++ b/subset/ntp/NTPClient/src/main/java/NtpMessage.java @@ -0,0 +1,203 @@ +import java.text.DecimalFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +public class NtpMessage { + public byte leapIndicator = 3; + public byte version = 0; + public byte mode = 0; + public short stratum = 0; + public byte pollInterval = 0; + public byte precision = 0; + public double rootDelay = 0; + public double rootDispersion = 0; + public byte[] referenceIdentifier = {0, 0, 0, 0}; + public double referenceTimestamp = 0; + public double originateTimestamp = 0; + public double receiveTimestamp = 0; + public double transmitTimestamp = 0; + + /** + * Constructs a new NtpMessage from an array of bytes. + */ + public NtpMessage(byte[] array) { + leapIndicator = (byte)((array[0] >> 6) & 0x3); + version = (byte)((array[0] >> 3) & 0x7); + mode = (byte)(array[0] & 0x7); + stratum = unsignedByteToShort(array[1]); + pollInterval = array[2]; + precision = array[3]; + + rootDelay = (array[4] * 256.0) + + unsignedByteToShort(array[5]) + + (unsignedByteToShort(array[6]) / 256.0) + + (unsignedByteToShort(array[7]) / 65536.0); + + rootDispersion = (unsignedByteToShort(array[8]) * 256.0) + + unsignedByteToShort(array[9]) + + (unsignedByteToShort(array[10]) / 256.0) + + (unsignedByteToShort(array[11]) / 65536.0); + + referenceIdentifier[0] = array[12]; + referenceIdentifier[1] = array[13]; + referenceIdentifier[2] = array[14]; + referenceIdentifier[3] = array[15]; + + referenceTimestamp = decodeTimestamp(array, 16); + originateTimestamp = decodeTimestamp(array, 24); + receiveTimestamp = decodeTimestamp(array, 32); + transmitTimestamp = decodeTimestamp(array, 40); + } + + /** + * Constructs a new NtpMessage in client -> server mode, and sets the + * transmit timestamp to the current time. + */ + public NtpMessage(double secondsDiff, byte leapIndicator, byte version) { + this.mode = 3; + this.leapIndicator = leapIndicator; + this.version = version; + this.transmitTimestamp = (System.currentTimeMillis() / 1000.0) + secondsDiff; + } + + /** + * This method constructs the data bytes of a raw NTP packet. + */ + public byte[] toByteArray() { + byte[] p = new byte[48]; + + p[0] = (byte)(leapIndicator << 6 | version << 3 | mode); + p[1] = (byte) stratum; + p[2] = (byte) pollInterval; + p[3] = (byte) precision; + + // root delay is a signed 16.16-bit FP, in Java an int is 32-bits + int l = (int)(rootDelay * 65536.0); + p[4] = (byte)((l >> 24) & 0xFF); + p[5] = (byte)((l >> 16) & 0xFF); + p[6] = (byte)((l >> 8) & 0xFF); + p[7] = (byte)(l & 0xFF); + + // root dispersion is an unsigned 16.16-bit FP, in Java there are no + // unsigned primitive types, so we use a long which is 64-bits + long ul = (long)(rootDispersion * 65536.0); + p[8] = (byte)((ul >> 24) & 0xFF); + p[9] = (byte)((ul >> 16) & 0xFF); + p[10] = (byte)((ul >> 8) & 0xFF); + p[11] = (byte)(ul & 0xFF); + + p[12] = referenceIdentifier[0]; + p[13] = referenceIdentifier[1]; + p[14] = referenceIdentifier[2]; + p[15] = referenceIdentifier[3]; + + encodeTimestamp(p, 16, referenceTimestamp); + encodeTimestamp(p, 24, originateTimestamp); + encodeTimestamp(p, 32, receiveTimestamp); + encodeTimestamp(p, 40, transmitTimestamp); + + return p; + } + + /** + * Returns a string representation of a NtpMessage. + */ + public String toString() { + String precisionStr = + new DecimalFormat("0.#E0").format(Math.pow(2, precision)); + + return "Leap indicator: " + leapIndicator + "\n" + + "Version: " + version + "\n" + + "Mode: " + mode + "\n" + + "Stratum: " + stratum + "\n" + + "Poll: " + pollInterval + "\n" + + "Precision: " + precision + " (" + precisionStr + " seconds)\n" + + "Root delay: " + new DecimalFormat("0.00").format(rootDelay * 1000) + " ms\n" + + "Root dispersion: " + new DecimalFormat("0.00").format(rootDispersion * 1000) + " ms\n" + + "Reference identifier: " + referenceIdentifierToString(referenceIdentifier, stratum, version) + "\n" + + "Reference timestamp: " + timestampToString(referenceTimestamp) + "\n" + + "Originate timestamp: " + timestampToString(originateTimestamp) + "\n" + + "Receive timestamp: " + timestampToString(receiveTimestamp) + "\n" + + "Transmit timestamp: " + timestampToString(transmitTimestamp); + } + + /** + * Converts an unsigned byte to a short. By default, Java assumes that + * a byte is signed. + */ + public static short unsignedByteToShort(byte b) { + if ((b & 0x80) == 0x80) { + return (short)(128 + (b & 0x7f)); + } else { + return (short) b; + } + } + + /** + * Will read 8 bytes of a message beginning at pointer + * and return it as a double, according to the NTP 64-bit timestamp + * format. + */ + public static double decodeTimestamp(byte[] array, int pointer) { + double r = 0.0; + + for (int i = 0; i < 8; i++) { + r += unsignedByteToShort(array[pointer + i]) * Math.pow(2, (3 - i) * 8); + } + + return r; + } + + /** + * Encodes a timestamp in the specified position in the message. + */ + public static void encodeTimestamp(byte[] array, int pointer, double timestamp) { + // Converts a double into a 64-bit fixed point + for (int i = 0; i < 8; i++) { + // 2^24, 2^16, 2^8, .. 2^-32 + double base = Math.pow(2, (3 - i) * 8); + // Capture byte value + array[pointer + i] = (byte)(timestamp / base); + // Subtract captured value from remaining total + timestamp = timestamp - (double)(unsignedByteToShort(array[pointer + i]) * base); + } + array[7] = (byte)(Math.random() * 255.0); + } + + /** + * Returns a timestamp (number of seconds since 00:00 1-Jan-1900) as a + * formatted date/time string. + */ + public static String timestampToString(double timestamp) { + if (timestamp == 0) { + return "0"; + } + double utc = timestamp - (2208988800.0); + long ms = (long)(utc * 1000.0); + String date = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss").format(new Date(ms)); + double fraction = timestamp - ((long) timestamp); + String fractionSting = new DecimalFormat(".000000").format(fraction); + return date + fractionSting; + } + + /** + * Returns a string representation of a reference identifier according + * to the rules set out in RFC 2030. + */ + public static String referenceIdentifierToString(byte[] ref, short stratum, byte version) { + if (stratum == 0 || stratum == 1) { + return new String(ref); + } else if (version == 3) { + return unsignedByteToShort(ref[0]) + "." + + unsignedByteToShort(ref[1]) + "." + + unsignedByteToShort(ref[2]) + "." + + unsignedByteToShort(ref[3]); + } else if (version == 4) { + return "" + ((unsignedByteToShort(ref[0]) / 256.0) + + (unsignedByteToShort(ref[1]) / 65536.0) + + (unsignedByteToShort(ref[2]) / 16777216.0) + + (unsignedByteToShort(ref[3]) / 4294967296.0)); + } + return ""; + } +} diff --git a/subset/ntp/README.md b/subset/ntp/README.md index b6b4bc3a8e..d4a9496524 100644 --- a/subset/ntp/README.md +++ b/subset/ntp/README.md @@ -1,12 +1,12 @@ # NTP testing ## test_ntp -The NTP test inspects client NTP support and version. +The NTP tests inspect the client NTP version and the device's ability to update its clock precisely. ### Note for test developers The functional test code is included in the `ntp_tests.py` file. -The test reads packets from startup.pcap. +The test reads packets from startup.pcap and monitor.pcap. If the python code needs debugging, the pip module `scapy` is required (`pip install scapy`). @@ -14,4 +14,16 @@ If the python code needs debugging, the pip module `scapy` is required (`pip ins | Test ID | Info | Pass | Fail | Skip | |---|---|---|---|---| | connection.network.ntp_support | Are the received NTP packets using NTP v4? | NTP version is 4 | NTP version is not 4 | No NTP packets are received | +| connection.network.ntp_update | Does the device demonstrate updating its clock using NTP? | Device clock is synchronized | Device clock is not synchronized | Not enough NTP packets are received | +#### NTP Support #### +The version of NTP used by the client is extracted from the fist client (outbound) NTP packets discovered in startup.pcap. + +#### NTP Update #### +The following criteria are used to determine whether a DUT has synced its clock with the NTP server provided by DAQ: + - A minimum of 2 NTP packets are present in startup.pcap and monitor.pcap (one potential poll). + - A minimum of 2 NTP packets have been exchanged between the DUT and the DAQ-provided NTP server. + - A valid NTP poll is present. Consisting of a client-server exchange. + - The calculated offset is less than 0.128 seconds and the final poll does not have a leap indicator of 3 (unsynchronized). + +When calculating the offset, the latest valid poll is inspected. A value of 0.128s is the maximum offset used to determine whether a device is considered in-sync with the NTP server because NTPv4 is capable of accuracy of tens of milliseconds. diff --git a/subset/ntp/ntp_tests.py b/subset/ntp/ntp_tests.py index 2a774f1124..37430656b6 100644 --- a/subset/ntp/ntp_tests.py +++ b/subset/ntp/ntp_tests.py @@ -1,11 +1,13 @@ -from __future__ import absolute_import -import sys +from __future__ import absolute_import, division from scapy.all import NTP, rdpcap +import sys +import os arguments = sys.argv test_request = str(arguments[1]) -cap_pcap_file = str(arguments[2]) +startup_pcap_file = str(arguments[2]) +monitor_pcap_file = str(arguments[3]) report_filename = 'report.txt' ignore = '%%' @@ -13,7 +15,17 @@ result = 'fail' dash_break_line = '--------------------\n' description_ntp_support = 'Device supports NTP version 4.' - +description_ntp_update = 'Device synchronizes its time to the NTP server.' + +NTP_VERSION_PASS = 4 +LOCAL_PREFIX = '10.20.' +NTP_SERVER_SUFFIX = '.2' +MODE_CLIENT = 3 +MODE_SERVER = 4 +YEAR_2500 = 16725225600 +SECONDS_BETWEEN_1900_1970 = 2208988800 +OFFSET_ALLOWANCE = 0.128 +LEAP_ALARM = 3 def write_report(string_to_append): with open(report_filename, 'a+') as file_open: @@ -22,10 +34,10 @@ def write_report(string_to_append): # Extracts the NTP version from the first client NTP packet def ntp_client_version(capture): - client_packets = ntp_packets(capture, 3) + client_packets = ntp_packets(capture, MODE_CLIENT) if len(client_packets) == 0: return None - return client_packets[0].version + return ntp_payload(client_packets[0]).version # Filters the packets by type (NTP) @@ -37,28 +49,108 @@ def ntp_packets(capture, mode=None): udp = ip.payload ntp = udp.payload if mode is None or mode == ntp.mode: - packets.append(ntp) + packets.append(packet) return packets +# Extracts the NTP payload from a packet of type NTP +def ntp_payload(packet): + ip = packet.payload + udp = ip.payload + ntp = udp.payload + return ntp + + def test_ntp_support(): - capture = rdpcap(cap_pcap_file) + capture = rdpcap(startup_pcap_file) if len(capture) > 0: version = ntp_client_version(capture) if version is None: add_summary("No NTP packets received.") return 'skip' - if version == 4: - add_summary("Using NTPv4.") + if version == NTP_VERSION_PASS: + add_summary("Using NTPv" + str(NTP_VERSION_PASS) + ".") return 'pass' else: - add_summary("Not using NTPv4.") + add_summary("Not using NTPv" + str(NTP_VERSION_PASS) + ".") return 'fail' else: add_summary("No NTP packets received.") return 'skip' +def test_ntp_update(): + startup_capture = rdpcap(startup_pcap_file) + packets = ntp_packets(startup_capture) + if os.path.isfile(monitor_pcap_file): + monitor_capture = rdpcap(monitor_pcap_file) + packets += ntp_packets(monitor_capture) + if len(packets) < 2: + add_summary("Not enough NTP packets received.") + return 'skip' + # Check that DAQ NTP server has been used + using_local_server = False + local_ntp_packets = [] + for packet in packets: + # Packet is to or from local NTP server + if ((packet.payload.dst.startswith(LOCAL_PREFIX) and + packet.payload.dst.endswith(NTP_SERVER_SUFFIX)) or + (packet.payload.src.startswith(LOCAL_PREFIX) and + packet.payload.src.endswith(NTP_SERVER_SUFFIX))): + using_local_server = True + local_ntp_packets.append(packet) + if not using_local_server or len(local_ntp_packets) < 2: + add_summary("Device clock not synchronized with local NTP server.") + return 'fail' + # Obtain the latest NTP poll + p1 = p2 = p3 = p4 = None + for i in range(len(local_ntp_packets)): + if p1 is None: + if ntp_payload(local_ntp_packets[i]).mode == MODE_CLIENT: + p1 = local_ntp_packets[i] + elif p2 is None: + if ntp_payload(local_ntp_packets[i]).mode == MODE_SERVER: + p2 = local_ntp_packets[i] + else: + p1 = local_ntp_packets[i] + elif p3 is None: + if ntp_payload(local_ntp_packets[i]).mode == MODE_CLIENT: + p3 = local_ntp_packets[i] + elif p4 is None: + if ntp_payload(local_ntp_packets[i]).mode == MODE_SERVER: + p4 = local_ntp_packets[i] + p1 = p3 + p2 = p4 + p3 = p4 = None + else: + p3 = local_ntp_packets[i] + if p1 is None or p2 is None: + add_summary("Device clock not synchronized with local NTP server.") + return 'fail' + t1 = ntp_payload(p1).sent + t2 = ntp_payload(p1).time + t3 = ntp_payload(p2).sent + t4 = ntp_payload(p2).time + + # Timestamps are inconsistenly either from 1900 or 1970 + if t1 > YEAR_2500: + t1 = t1 - SECONDS_BETWEEN_1900_1970 + if t2 > YEAR_2500: + t2 = t2 - SECONDS_BETWEEN_1900_1970 + if t3 > YEAR_2500: + t3 = t3 - SECONDS_BETWEEN_1900_1970 + if t4 > YEAR_2500: + t4 = t4 - SECONDS_BETWEEN_1900_1970 + + offset = abs((t2 - t1) + (t3 - t4))/2 + if offset < OFFSET_ALLOWANCE and not ntp_payload(p1).leap == LEAP_ALARM: + add_summary("Device clock synchronized.") + return 'pass' + else: + add_summary("Device clock not synchronized with local NTP server.") + return 'fail' + + def add_summary(text): global summary_text summary_text = summary_text + " " + text if summary_text else text @@ -70,5 +162,8 @@ def add_summary(text): if test_request == 'connection.network.ntp_support': write_report("{d}\n{b}".format(b=dash_break_line, d=description_ntp_support)) result = test_ntp_support() +elif test_request == 'connection.network.ntp_update': + write_report("{d}\n{b}".format(b=dash_break_line, d=description_ntp_update)) + result = test_ntp_update() write_report("RESULT {r} {t} {s}\n".format(r=result, t=test_request, s=summary_text.strip())) diff --git a/subset/ntp/test_ntp b/subset/ntp/test_ntp index 7521f9d74d..fa7d950189 100755 --- a/subset/ntp/test_ntp +++ b/subset/ntp/test_ntp @@ -1,9 +1,10 @@ #!/bin/bash -e REPORT=/tmp/report.txt - STARTUP=/scans/startup.pcap +MONITOR=/scans/monitor.pcap -python ntp_tests.py connection.network.ntp_support $STARTUP +python ntp_tests.py connection.network.ntp_support $STARTUP $MONITOR +python ntp_tests.py connection.network.ntp_update $STARTUP $MONITOR cat report.txt >> $REPORT diff --git a/testing/test_aux.out b/testing/test_aux.out index 3b0b5dd675..f3c091c87a 100644 --- a/testing/test_aux.out +++ b/testing/test_aux.out @@ -58,8 +58,11 @@ RESULT pass security.passwords.ssh Default passwords have been changed. RESULT skip security.firmware Could not retrieve a firmware version with nmap. Check bacnet port. RESULT pass security.firmware version found: ?\xFF\xFF\x19,>u\x08\x00no RESULT pass connection.network.ntp_support Using NTPv4. +RESULT pass connection.network.ntp_update Device clock synchronized. RESULT fail connection.network.ntp_support Not using NTPv4. +RESULT fail connection.network.ntp_update Device clock not synchronized with local NTP server. RESULT skip connection.network.ntp_support No NTP packets received. +RESULT skip connection.network.ntp_update Not enough NTP packets received. dhcp requests 1 1 1 1 01: [] 02: ['02:macoui:TimeoutError', '02:ping:TimeoutError'] From 2ee7ea5fe850439aba4ac40eee9739002a2e74f1 Mon Sep 17 00:00:00 2001 From: Noureddine Date: Thu, 30 Jul 2020 00:29:41 +0100 Subject: [PATCH 060/212] Incorporate manual test comments (#499) * incorporate comments on PR #481 for manual tests --- docs/device_report.md | 6 +++--- resources/test_site/module_config.json | 2 +- subset/manual/readme.md | 12 ++++++++---- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/docs/device_report.md b/docs/device_report.md index 74d7445460..a3e4f1736f 100644 --- a/docs/device_report.md +++ b/docs/device_report.md @@ -72,7 +72,7 @@ Overall device result FAIL |skip|connection.port_duplex|Other|Other|No local IP has been set, check system config| |skip|connection.port_link|Other|Other|No local IP has been set, check system config| |skip|connection.port_speed|Other|Other|No local IP has been set, check system config| -|pass|manual.test.travis|Security|Recommended|Manual test - for testing| +|pass|manual.test.name|Security|Recommended|Manual test - for testing| |skip|poe.negotiation|Other|Other|No local IP has been set, check system config| |skip|poe.power|Other|Other|No local IP has been set, check system config| |skip|poe.support|Other|Other|No local IP has been set, check system config| @@ -544,13 +544,13 @@ RESULT skip cloud.udmi.system No device id ``` -------------------- -manual.test.travis +manual.test.name -------------------- -------------------- No additional information provided -------------------- -RESULT pass manual.test.travis Manual test - for testing +RESULT pass manual.test.name Manual test - for testing ``` diff --git a/resources/test_site/module_config.json b/resources/test_site/module_config.json index ac17f224b1..7971fca2a4 100644 --- a/resources/test_site/module_config.json +++ b/resources/test_site/module_config.json @@ -50,7 +50,7 @@ "category": "Security", "expected": "Recommended" }, - "manual.test.travis": { + "manual.test.name": { "required": "pass", "category": "Security", "expected": "Recommended", diff --git a/subset/manual/readme.md b/subset/manual/readme.md index ea2056eff6..a5b300a370 100644 --- a/subset/manual/readme.md +++ b/subset/manual/readme.md @@ -2,10 +2,14 @@ ## Manual Tests -Some tests cannot be automated with DAQ although these may be required. To facilitate a single test report which incorporates all tests undertaken on a device, the `manual` test can be used to input the results into reports produced by DAQ. +Some tests cannot be automated with DAQ although these may be required. +To facilitate a single test report which incorporates all tests +undertaken on a device, the `manual` test can be used to input +the results into reports produced by DAQ. ## Configuration -Manual tests including results are inserted into the device's `module_config.json` and marked by `"type": "manual"`. +Manual tests including results are inserted into the device's +`module_config.json` and marked by `"type": "manual"`. ``` "tests": { @@ -14,7 +18,7 @@ Manual tests including results are inserted into the device's `module_config.jso "enabled": true, "type": "manual", "result": "required", - "outcome": "pass" + "outcome": "pass", "summary" : "summary note in results table", "test_log" : "additional information in report appendix" } @@ -38,4 +42,4 @@ Test description Test description -------------------- RESULT pass manual.test.name Manual test - Test summary -``` \ No newline at end of file +``` From c49a1d1a044090d1f830d5d9d19d93fc0a5b8696 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 30 Jul 2020 18:23:28 -0700 Subject: [PATCH 061/212] Update dependency io.grpc:grpc-bom to v1.31.0 (#561) --- usi/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usi/pom.xml b/usi/pom.xml index 59cf28ad1a..6c057282ed 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -16,7 +16,7 @@ io.grpc grpc-bom - 1.30.2 + 1.31.0 pom import From 673550adffff924d0531e93c67aeb9674e57616d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 30 Jul 2020 18:23:57 -0700 Subject: [PATCH 062/212] Update dependency io.grpc:grpc-stub to v1.31.0 (#566) --- usi/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usi/pom.xml b/usi/pom.xml index 6c057282ed..e9311d7289 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -48,7 +48,7 @@ io.grpc grpc-stub - 1.30.2 + 1.31.0 org.apache.tomcat From 898111a7e064e22fec4e4494088e8cc001cd3286 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 30 Jul 2020 18:24:21 -0700 Subject: [PATCH 063/212] Update dependency io.grpc:grpc-protobuf to v1.31.0 (#564) --- usi/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usi/pom.xml b/usi/pom.xml index e9311d7289..497fbe1cd0 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -43,7 +43,7 @@ io.grpc grpc-protobuf - 1.30.2 + 1.31.0 io.grpc From 820f101d6e6f79c89fa82661f353e9900c699cfd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 30 Jul 2020 18:24:44 -0700 Subject: [PATCH 064/212] Update dependency io.grpc:grpc-netty-shaded to v1.31.0 (#562) --- usi/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usi/pom.xml b/usi/pom.xml index 497fbe1cd0..0a9138e922 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -38,7 +38,7 @@ io.grpc grpc-netty-shaded - 1.30.2 + 1.31.0 io.grpc From 63cde4738541f971509a9249075c031e078a9108 Mon Sep 17 00:00:00 2001 From: pbatta Date: Thu, 30 Jul 2020 22:36:55 -0700 Subject: [PATCH 065/212] misc updates to docs (#568) --- docs/cloud_tests.md | 19 ++++++++++++------- docs/service.md | 2 +- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/docs/cloud_tests.md b/docs/cloud_tests.md index 6ed8a9efed..2bbc212097 100644 --- a/docs/cloud_tests.md +++ b/docs/cloud_tests.md @@ -11,8 +11,8 @@ understand the manual test pipeline before engaging with the automated setup. The overall device-to-cloud pipeline looks something like the following: * Device sends data to the cloud. There's two kinds of devices: - * A faux _reference design_ device called [pubber](pubber.md), which is a completely contained - software device. + * A faux _reference design_ device called [pubber](https://github.com/faucetsdn/udmi/blob/master/docs/pubber.md), + which is a completely contained software device. * An actual physical device. The setup and configuration of that device will be manufacturer dependent and so is out of scope for this (DAQ) documentation. * A configured GCP IoT Core project, registry, and device entry. The @@ -22,12 +22,16 @@ cloud device entry. * The IoT Core registry is configured with a _PubSub topic_ (not to be confused with an _MQTT topic_), that provides the bridge between incoming data and consumers of that data. See the GCP documentation on PubSub for more details. +* (optional) Some devices might need a gateway that communicates with IoT Core + on their behalf. In this case the Gateway should be added to the IoT Core as + well and the devices bound to it. * (optional) The `gcloud` command line can be used to validate that data is being sent from the device to the cloud. Something like `gcloud pubsub subscriptions pull --auto-ack projects/{project}/subscriptions/{sub_id}`. (Complete documentation for how to use `gcloud` commands is out of scope of this documentation.) -* The [validator tool](validator.md) is what programmatically validates a device data stream, and -is what is ultimately used by `test_udmi` to validate device-cloud communication. +* The [validator tool](https://github.com/faucetsdn/udmi/blob/master/docs/validator.md) is what +programmatically validates a device data stream, and is what is ultimately used by `test_udmi` +to validate device-cloud communication. ## Base Local Test Setup @@ -54,7 +58,8 @@ This contains all the site-specific information about devices needed for testing * `{site_path}/mac_addrs/{mac_addr}/module_config.json` needs to have a `device_id` defined, e.g. as in `resources/test_site/mac_addrs/3c5ab41e8f0b/module_config.json`. * The GCP IoT Core setup needs to have a proper registry and device configred. This can either -be done manually or using the [registrar tool](registrar.md) tool. +be done manually or using the [registrar +tool](https://github.com/faucetsdn/udmi/blob/master/docs/registrar.md) tool. ## Integration Testing @@ -76,12 +81,12 @@ iOiAiaHR0cHM6Ly93LWRhcS10ZXN0aW5nLmlhbS5nc2VydmljZWFjY291bnQuY29tIgp9Cg== ### Travis CI Testing -* Run the [registrar tool](registrar.md) to properly configure the cloud project. +* Run the [registrar tool](https://github.com/faucetsdn/udmi/blob/master/docs/registrar.md) to properly configure the cloud project. * `gcp_topic` config to `local/system.conf` as described in this doc. * Configure test subsystem with proper cloud endpoint in `{test_site}/cloud_iot_config.json`. * Configure the DUT with the proper cloud device credentials (device specific). For _faux_ devices, this means copying the associated `rsa_private.pkcs8` file to something like `inst/faux/daq-faux-2/local/` (exact path depends on which faux). -* Test with `bin/registrar`, `pubber/bin/run`, and `bin/validate` manually, before integrated testing through DAQ. +* Test with `udmi/bin/registrar`, `udmi/pubber/bin/run`, and `udmi/bin/validator` manually, before integrated testing through DAQ. ### Is my Travis set up correctly? diff --git a/docs/service.md b/docs/service.md index 02bf501c79..4bace1de28 100644 --- a/docs/service.md +++ b/docs/service.md @@ -4,7 +4,7 @@ Many functions of DAQ require a standard GCP service account, rather than person Once created, there's a limited set of permissions that can be granted to enable various bits and pieces of functionality. -Each individual install of DAQ should have it's own service account. The accound name is +Each individual install of DAQ should have it's own service account. The account name is assumed to be unique, and having multiple installs with the same account will cause confusion and unpredictable results. From 9a36bae15147b0613aab89ac512880ba4f735892 Mon Sep 17 00:00:00 2001 From: henry54809 Date: Sun, 2 Aug 2020 12:43:02 -0700 Subject: [PATCH 066/212] Github actions (#558) --- .github/workflows/tests.yml | 53 ++++++++++++++++++++++++++++ .github/workflows/usi.yml | 21 +++++++++++ .travis.yml | 30 ---------------- README.md | 3 ++ bin/setup_base | 2 +- bin/setup_dev | 6 +--- bin/test_daq | 4 +-- daq/utils.py | 3 +- docker/modules/Dockerfile.networking | 2 +- docs/add_test.md | 10 +++--- docs/build.md | 20 +++-------- docs/cloud_tests.md | 53 ++++------------------------ docs/developing.md | 50 ++++++++++++-------------- docs/module_test.md | 2 +- subset/cloud/Dockerfile.test_udmi | 2 ++ subset/cloud/test_udmi | 11 +++--- testing/test_aux.out | 2 -- testing/test_aux.sh | 11 ++---- testing/test_base.sh | 6 ++-- testing/test_modules.sh | 2 -- 20 files changed, 137 insertions(+), 156 deletions(-) create mode 100644 .github/workflows/tests.yml create mode 100644 .github/workflows/usi.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000000..c65e0a6c13 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,53 @@ +# This workflow will install Python dependencies, run tests and lint with a single version of Python +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions + +name: DAQ main tests + +on: [push, pull_request] + +jobs: + integration_tests: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + test: [base, many, aux, topo, modules, dhcp] + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Set up Python 3.7 + uses: actions/setup-python@v2 + with: + python-version: 3.7 + - name: Set up JDK 1.11 + uses: actions/setup-java@v1 + with: + java-version: 1.11 + - name: Installing dependencies + run: | + bin/setup_daq + - name: Running ${{ matrix.test }} test + env: + DOCKER_STARTUP_TIMEOUT_MS: 60000 + GCP_BASE64_CRED: ${{ secrets.GCP_BASE64_CRED }} + run: | + DAQ_TEST=${{ matrix.test }} bin/test_daq + + unit_tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up Python 3.7 + uses: actions/setup-python@v2 + with: + python-version: 3.7 + - name: Install dependencies + run: | + bin/setup_dev + - name: Check style + run: | + bin/check_style + - name: Unit test + run: | + testing/run_unit_tests.sh \ No newline at end of file diff --git a/.github/workflows/usi.yml b/.github/workflows/usi.yml new file mode 100644 index 0000000000..550fc9d815 --- /dev/null +++ b/.github/workflows/usi.yml @@ -0,0 +1,21 @@ + +# This workflow will build a Java project with Maven +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven + +name: USI Java CI with Maven + +on: [push, pull_request] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 1.11 + uses: actions/setup-java@v1 + with: + java-version: 1.11 + - name: Build with Maven + run: mvn -B clean compile test assembly:single --file usi/pom.xml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index bf7e2b9b6d..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,30 +0,0 @@ -os: linux -dist: bionic -services: - - docker -language: python -python: - - "3.7" -cache: - pip: true -addons: - apt: - update: true - packages: - - openvswitch-switch -install: - - set -e - - bin/setup_daq -script: - - set -e - - bin/test_daq -env: - global: - - DOCKER_STARTUP_TIMEOUT_MS=60000 - jobs: - - DAQ_TEST=base - - DAQ_TEST=many - - DAQ_TEST=aux - - DAQ_TEST=topo - - DAQ_TEST=modules - - DAQ_TEST=dhcp diff --git a/README.md b/README.md index 7cc5495b1e..7fcde011ef 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ +![Main tests](https://github.com/faucetsdn/daq/workflows/DAQ%20main%20tests/badge.svg?branch=master) +![USI Java CI with Maven](https://github.com/faucetsdn/daq/workflows/USI%20Java%20CI%20with%20Maven/badge.svg?branch=master) + # DAQ: Device Automated Qualification for IoT Devices. DAQ is a framework designed to test and operate IoT devices in an enterprise IoT environment. diff --git a/bin/setup_base b/bin/setup_base index b965fa934f..2df5826d96 100755 --- a/bin/setup_base +++ b/bin/setup_base @@ -61,7 +61,7 @@ echo Adding username to docker group... sudo groupadd docker || true sudo usermod -aG docker $user -DEF_IFACE=`sudo route -n | fgrep UG | awk '{print $8}'` +DEF_IFACE=`sudo route -n | egrep '\sUG\s' | awk '{print $8}'` if [ -n "$DEF_IFACE" ]; then echo Allowing docker external access through interface $DEF_IFACE... sudo iptables -o docker0 -i $DEF_IFACE -A FORWARD -j ACCEPT diff --git a/bin/setup_dev b/bin/setup_dev index 65c9441987..7ae8b1aef0 100755 --- a/bin/setup_dev +++ b/bin/setup_dev @@ -53,10 +53,6 @@ if [ -z "$PIP" ]; then PIP="python$PVERSION -m pip" fi -if [ -n "$TRAVIS" ]; then - DAQ_CONTAINER=travis -fi - echo AG is $AG echo PIP is $PIP echo Setup root is $PWD @@ -112,7 +108,7 @@ else fi # Can't use venv inside of containers because of absolute paths. -if [ -n "$DAQ_CONTAINER" ]; then +if [ -n "$CI" ]; then echo Skipping venv activation. mkdir -p venv/bin touch venv/bin/activate diff --git a/bin/test_daq b/bin/test_daq index 779cef8998..a389500482 100755 --- a/bin/test_daq +++ b/bin/test_daq @@ -13,7 +13,7 @@ function delay_finish { sleep 10 } -if [ -n "$TRAVIS" ]; then +if [ -n "$CI" ]; then trap delay_finish EXIT fi @@ -71,7 +71,7 @@ CRED_FILE=inst/config/gcp_service_account.json echo Running test script $TEST_SCRIPT # Combine stderr & stdout b/c travis has problems processing both. sudo PATH=$PATH TEST_RESULTS=$TEST_RESULTS GCP_RESULTS=$GCP_RESULTS \ - DAQ_CODECOV=y $TEST_SCRIPT 2>&1 + DAQ_CODECOV=y GCP_BASE64_CRED="$GCP_BASE64_CRED" $TEST_SCRIPT 2>&1 if [ -f .coverage ]; then codecov_tag=${DAQ_TEST##*/} diff --git a/daq/utils.py b/daq/utils.py index 1bc3a75c1d..6bb093d484 100644 --- a/daq/utils.py +++ b/daq/utils.py @@ -1,8 +1,7 @@ """Utility functions for DAQ""" -import yaml - from google.protobuf import json_format +import yaml def yaml_proto(file_name, proto_func): diff --git a/docker/modules/Dockerfile.networking b/docker/modules/Dockerfile.networking index 2001cf1f03..db07f600fd 100644 --- a/docker/modules/Dockerfile.networking +++ b/docker/modules/Dockerfile.networking @@ -5,7 +5,7 @@ FROM daqf/aardvark:latest -RUN $AG update && $AG install dnsmasq ethtool iptables netcat ntp python +RUN $AG update && $AG install dnsmasq ethtool iptables netcat ntp python curl COPY docker/include/networking_scripts/* ./ RUN mkdir -p /etc diff --git a/docs/add_test.md b/docs/add_test.md index e460137584..79592f0d24 100644 --- a/docs/add_test.md +++ b/docs/add_test.md @@ -112,7 +112,7 @@ However, with great flexibility comes great responsibility. Tests should: - Test _one_ thing well -- Include an integration test for Travis CI +- Include an integration test for [Github actions](https://github.com/faucetsdn/daq/actions) - Adhere to the Google style guide of your chosen language: https://google.github.io/styleguide/ - Have the smallest amount of code possible for the greatest utility for the framework. Keep docker images lean! - Not add things like the following to the repository: @@ -124,9 +124,9 @@ Tests should: - Include the test name and a description of the test in the report output - Include an informative line in the summary table -Integration tests don't need to be tedious and, if you're developing one test and seeing a consistent failure on Travis CI, isolate your problem and run _just that part_ of the integration test both locally and on Travis CI. +Integration tests don't need to be tedious and, if you're developing one test and seeing a consistent failure on Github actions, isolate your problem and run _just that part_ of the integration test both locally and on Github actions. -The pass/fail state of an integration test corresponds to the result of a `diff` between expected and actual device report output. You can follow the steps in the _Integration Testing Workflow_ section below to mimic the exact process that Travis CI follows. Or, if your local machine builds Docker images slowly, simply modify the test_*.out by hand, amending it to what your report should look like. Then, see if Travis CI agrees. +The pass/fail state of an integration test corresponds to the result of a `diff` between expected and actual device report output. You can follow the steps in the _Integration Testing Workflow_ section below to mimic the exact process that Github actions follows. Or, if your local machine builds Docker images slowly, simply modify the test_*.out by hand, amending it to what your report should look like. Then, see if Github actions agrees. Similarly, if you're writing one test and running it within DAQ locally, run _only the test you're developing_. Try not to bloat your precious development hours by waiting for tests to run that you don't care about. Building unnecessary tests is a very efficient time sink. @@ -145,7 +145,7 @@ All of the commands in these steps are run as the root user by typing "sudo -i" 6. Run `testing/test_x.sh` 7. Copy `out/test_x.out` to `testing/test_x.out` 8. Run `testing/test_x.sh` to check the integration tests now execute successfully in the local machine. -9. Commit to GitHub to sync local codebase with remote codebase and to trigger the final Travis CI tests -10. Test should now pass the Travis CI integration tests. +9. Commit to GitHub to sync local codebase with remote codebase and to trigger the final [Github actions](https://github.com/faucetsdn/daq/actions) tests +10. Test should now pass the [Github actions](https://github.com/faucetsdn/daq/actions) integration tests. TODO: write note about hold_tests diff --git a/docs/build.md b/docs/build.md index 40e40aa20e..6ff2287518 100644 --- a/docs/build.md +++ b/docs/build.md @@ -22,23 +22,11 @@ different dependencies. See `cmd/build help` for more details on different image ## Tests, Tests, and More Tests In a whirlwind of flagrant appropriateness, the baseline for DAQ development is... testing. Specifically, -there is a suite of continuous integration tests that run on [Travis CI](https://travis-ci.com/faucetsdn/daq) +there is a suite of continuous integration tests that run using [Github actions](https://github.com/faucetsdn/daq/actions) that puts the system through a barrage of tests to make sure all is good. Any PR submission will -require that these tests pass. It's recommended (but not required) that you set up Travis CI on -your personal development branch to test your commits in the full Travis CI environment before relying -on the automatic PR test mechanism. - -The `.travis.yml` file contains the information for the tests themselves, primarily listed under the `matrix:` -subsection that shows all the various tested configurations. Note that this assumes a fully installed environment -(as setup with `bin/setup_daq`). From there, individual tests can be run locally by -appending `bin/test_daq` to a `sudo` line of shell environment settings, e.g. as taken from one matrix entry: -
        -~/daq$ sudo DAQ_TEST=base bin/test_daq
        -…
        -or directly with:
        -~/daq$ sudo testing/test_base.sh
        -…
        -
        +require that these tests pass. + +For more information, please see [developing docs](https://github.com/faucetsdn/daq/blob/master/docs/developing.md). ## Incremental Builds diff --git a/docs/cloud_tests.md b/docs/cloud_tests.md index 2bbc212097..ff982de80f 100644 --- a/docs/cloud_tests.md +++ b/docs/cloud_tests.md @@ -64,13 +64,8 @@ tool](https://github.com/faucetsdn/udmi/blob/master/docs/registrar.md) tool. ## Integration Testing If developing cloud-tests, then the CI build system also needs to have a service account configured -pointing at a suitable GCP project. To run cloud-based tests, setup the Travis `GCP_BASE64_CRED` -env variable with a `base64` encoded service account key for your project. It's recommended to -use a dedicated key with a nice name like `daq-travis`, but not required. Encode the key value -as per below, and cut/paste the resulting string into a -[Travis environment variable](https://docs.travis-ci.com/user/environment-variables/#defining-variables-in-repository-settings) -for a `GCP_BASE64_CRED` variable. Note the `-w 0` option is required for proper parsing/formatting, -as there can't be any newlines in the copied string. +pointing at a suitable GCP project. To run cloud-based tests, setup the [Github Secrets](https://docs.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets) `GCP_BASE64_CRED` +env variable with a `base64` encoded service account key for your project. It's recommended to use a dedicated key with a nice name like `daq-ci`, but not required. Note that on linux `-w 0` option is required for proper parsing/formatting, as there can't be any newlines in the copied string. $ base64 -w 0 local/gcp_service_account.json @@ -79,7 +74,7 @@ ewoICJ1eXBlIjogInNlcnZpY2VfYWNjb3VudCIsCiAgInByb2plY3RfaWQiOiAiYm9zLWRhcS10ZXN0a iOiAiaHR0cHM6Ly93LWRhcS10ZXN0aW5nLmlhbS5nc2VydmljZWFjY291bnQuY29tIgp9Cg== -### Travis CI Testing +### Github Actions CI Testing * Run the [registrar tool](https://github.com/faucetsdn/udmi/blob/master/docs/registrar.md) to properly configure the cloud project. * `gcp_topic` config to `local/system.conf` as described in this doc. @@ -88,51 +83,15 @@ iOiAiaHR0cHM6Ly93LWRhcS10ZXN0aW5nLmlhbS5nc2VydmljZWFjY291bnQuY29tIgp9Cg== the associated `rsa_private.pkcs8` file to something like `inst/faux/daq-faux-2/local/` (exact path depends on which faux). * Test with `udmi/bin/registrar`, `udmi/pubber/bin/run`, and `udmi/bin/validator` manually, before integrated testing through DAQ. -### Is my Travis set up correctly? +### Is my Github Actions set up correctly? -If Travis is set up correctly, you should see messages at the beginning of the log file: -``` -Setting environment variables from repository settings -$ export DOCKER_USERNAME=[secure] -$ export DOCKER_PASSWORD=[secure] -$ export GCP_BASE64_CRED=[secure] -``` - -Further down there would be more details about the cred itself: +If Github Actions is set up correctly, you should see logs similar to the one below: ``` Running test script testing/test_aux.sh Writing test results to inst/test_aux.out and inst/test_aux.gcp Decoding GCP_BASE64_CRED to inst/config/gcp_service_account.json base64 wc: 1 1 3097 -GCP service account is "daq-travis@daq-testing.iam.gserviceaccount.com" +GCP service account is "daq-ci@daq-testing.iam.gserviceaccount.com" ``` If the `3097` character count is wildly off, then likely something went wrong with the newlines. - -### Travis Build For "External" Pull Requests - -Travis will not use encrypted environment variables when testing against pull requests -from foreign github repositories, even if you've forked from another repository that you -have full control of via Github. Travis authorization != Github authorization, even if -you sign into Travis using Github! This is as it should be b/c security. see the following -for more info: - -- https://docs.travis-ci.com/user/environment-variables/#defining-variables-in-repository-settings -- https://docs.travis-ci.com/user/pull-requests/#pull-requests-and-security-restrictions - -If your test is failing from a PR, you'll see something like in a similar log location: - -``` -Encrypted environment variables have been removed for security reasons. -See https://docs.travis-ci.com/user/pull-requests/#pull-requests-and-security-restrictions -Setting environment variables from .travis.yml -$ export DOCKER_STARTUP_TIMEOUT_MS=60000 -$ export DAQ_TEST=aux -``` - -### Other Travis Caveats - -Take note the URL in your browser's address bar when running Travis. You might be on either -travis-ci.com or travis-ci.org. Any particular setup -may end up across both sites for undetermined reasons. Please consult with your browser's -exact URL for more clarity. diff --git a/docs/developing.md b/docs/developing.md index 77848125ef..e4c025a9e5 100644 --- a/docs/developing.md +++ b/docs/developing.md @@ -28,16 +28,9 @@ faster than continually working with physical components (unless actively debugg problems that only manifest themselves physically). If there is a problem in the 'real' world, then the first step is typically to try and reproduce it virtually. -## Travis CI +## Github Actions CI -Travis is used as the primary CI testing point for DAQ. The -[facuetsdn/daq dashboard](https://travis-ci.com/faucetsdn/daq/branches) shows the -status of the current master branch. It is generally recommended to set up -Travis on your personal repos to test any branches you push/commit. PRs will -automatically be tested under the destination repo. - -Travis runs a suite of tests defined in the `.travis.yml` file. Each `DAQ_TEST` -entry triggers a separate run through the `bin/test_daq` script. E.g. `DAQ_TEST=many` +The `.github/workflows` folder contains information for the tests themselves. There are 2 workflows currently in place -- one for main DAQ integration tests and unit tests, and the other for USI related tests. Each workflow file is further broken down into jobs. In the case of tests.yml, there are the `integration_tests` and `unit_tests` jobs. Primarily listed under the `matrix:` subsection shows all the various tested configurations for the `integration_tests`. Each matrix entry triggers a separate run through the `bin/test_daq` script. E.g. `DAQ_TEST=many` ultimately runs `testing/test_many.sh`. The test output results are compared against the golden `.out` file (e.g. `testing/test_many.out`) and the tests pass if there is no difference. (Look in `bin/test_daq` to see exactly what it's doing.) @@ -45,25 +38,26 @@ is no difference. (Look in `bin/test_daq` to see exactly what it's doing.) If there are unexplained differences in the `.out` file, then the test output log itself should be checked to see what actually went wrong, since there's likely not enough information in the `.out` files to diagnose effectively. The complete -log output is avaliable from a Travis run (or locally when you run locally), and -the triggering line from the `.out` difference should be there as well (search for it!). +log output is avaliable from a [Github actions](https://github.com/faucetsdn/daq/actions) run (or locally when you run locally), and the triggering line from the `.out` difference should be there as well (search for it!). + +Note all integration tests assume a fully installed environment (as setup with `bin/setup_daq`). ## Local Integration Tests -Tests can be run locally with something like `sudo testing/test_aux.sh`, and the output -will be generated into, e.g., `out/test_aux.out`, that can be compared against the -corresponding golden `.out` file, e.g., `testing/test_aux.out`. Running tests locally is -not always 100% exactly the same as running things in a real (against physical devices +Individual integration tests can be run locally by +appending `bin/test_daq` to a `sudo` line of shell environment settings, e.g. as taken from one matrix entry: +
        +~/daq$ sudo DAQ_TEST=base bin/test_daq
        +…
        +or directly with:
        +~/daq$ sudo testing/test_base.sh
        +…
        +
        + +Running tests locally is not always 100% exactly the same as running things in a real (against physical devices on a physical switch) or CI environment, but in most cases it provides a workable method. -It is recommended to start from a clear DAQ configuration by running `rm -rf local` -from the main DAQ folder before running the local integration tests. - -When developing a new test, the output should appear in the corresponding `.out` file, -which should be updated appropriatley. The easiest way to migrate in new changes is to -just copy the `out/` file to `testing/`, but care must be taken that only expected -changes are included with a new PR. Ultimately the Travis CI tests must pass, not the -local tests, to guard against any local filesystem changes. +When developing a new test, the output should appear in the corresponding `.out` file, which should be updated appropriatley. The easiest way to migrate in new changes is to just copy the `out/` file to `testing/`, but care must be taken that only expected changes are included with a new PR. Ultimately the [Github actions](https://github.com/faucetsdn/daq/actions) tests must pass, not the local tests, to guard against any local filesystem changes. ## Aux Golden Device Report @@ -85,7 +79,9 @@ as the new golden file (i.e., copy it from `out/report_9a02571e8f01_???.md` to ## Lint Checks -Lint checks are performed as part of the `testing/test_aux.sh` script. They are extra -tricky because they are typically very sensitive to the exact version of every package -installed, so they're somewhat unreliable except when run through a pristine environment -on Travis. +To make sure changes to DAQ adheres to the existing code checkstyle, a pre commit hook can be setup to run [bin/check_style](https://github.com/faucetsdn/daq/blob/master/bin/check_style) before a commit. To enable this, simply run the following line under your daq root directory. +
        +~/daq$ echo "bin/check_style" > .git/hooks/pre-commit && chmod +x .git/hooks/pre-commit
        +
        + +Lint checks are performed as part of the unit_test job on [Github actions](https://github.com/faucetsdn/daq/actions) as well as on [stickler-ci](https://stickler-ci.com/repositories/51649-faucetsdn-daq) when for every PR. diff --git a/docs/module_test.md b/docs/module_test.md index d337e45749..ce600c8885 100644 --- a/docs/module_test.md +++ b/docs/module_test.md @@ -80,7 +80,7 @@ RESULT fail security.x509 ## Continous Testing Continuous testing of module-specific builds is handled through the `testing/test_modules.sh` -script (as invoked by Travis). Execution results are compared against the +script (as invoked by [Github actions](https://github.com/faucetsdn/daq/actions)). Execution results are compared against the `testing/test_modules.out` file. To add a new test, add a few lines to the top of the test script and expected results to the output file. Every test module is required to be continously tested somewhere, either as part of `test_modules.sh` or elsewhere. diff --git a/subset/cloud/Dockerfile.test_udmi b/subset/cloud/Dockerfile.test_udmi index e0e78a3a13..ee5fa4c721 100644 --- a/subset/cloud/Dockerfile.test_udmi +++ b/subset/cloud/Dockerfile.test_udmi @@ -9,6 +9,8 @@ FROM daqf/aardvark:latest RUN $AG update && $AG install openjdk-11-jre RUN $AG update && $AG install openjdk-11-jdk git +RUN $AG update && $AG install curl + COPY udmi/validator/ validator/ RUN validator/bin/build diff --git a/subset/cloud/test_udmi b/subset/cloud/test_udmi index 2edaaf82ac..0f016e18e6 100755 --- a/subset/cloud/test_udmi +++ b/subset/cloud/test_udmi @@ -8,10 +8,10 @@ LOG=/tmp/udmi.log # Necessary to reach gcp. Should be done by framework but this works for now. route add default gw $GATEWAY_IP +ip addr route -n -ping -c 2 172.217.164.106 || true +ping -c 2 $GATEWAY_IP arp -n -ip addr gcp_cred=/config/inst/gcp_service_account.json gcp_topic=target @@ -22,10 +22,13 @@ message_types="state pointset system" device_id=`jq -r .device_id /config/device/module_config.json` # Do basic network connectivity check +echo "nameserver 8.8.8.8" >> /etc/resolv.conf cat /etc/resolv.conf -ping -c 2 172.217.164.106 -ping -c 2 pubsub.googleapis.com +ping -c 2 google.com || true # blocked on github actions +echo "********GOOGLE PAGE********" +curl google.com +echo "***************************" if [ "$device_id" == null ]; then skip="No device id" elif [ ! -f $gcp_cred ]; then diff --git a/testing/test_aux.out b/testing/test_aux.out index f3c091c87a..e5aa8a21ac 100644 --- a/testing/test_aux.out +++ b/testing/test_aux.out @@ -1,7 +1,5 @@ Running testing/test_aux.sh Aux Tests -Lint checks -check_style exit code 0 RESULT pass base.startup.dhcp RESULT skip base.switch.ping No local IP has been set, check system config RESULT pass base.target.ping target reached diff --git a/testing/test_aux.sh b/testing/test_aux.sh index 94a12f8612..aa7c97470f 100755 --- a/testing/test_aux.sh +++ b/testing/test_aux.sh @@ -4,11 +4,6 @@ source testing/test_preamble.sh echo Aux Tests >> $TEST_RESULTS -# Runs lint checks and some similar things -echo Lint checks | tee -a $TEST_RESULTS -bin/check_style -echo check_style exit code $? | tee -a $TEST_RESULTS - # Function to create pubber config files (for use in cloud tests) function make_pubber { @@ -126,9 +121,9 @@ echo dhcp requests $((dhcp_done > 1)) $((dhcp_done < 3)) \ sort inst/result.log | tee -a $TEST_RESULTS # Show partial logs from each test -head inst/gw*/nodes/gw*/activate.log -head inst/run-port-*/nodes/*/activate.log -head inst/run-port-*/nodes/*/tmp/report.txt +head -20 inst/gw*/nodes/gw*/activate.log +head -20 inst/run-port-*/nodes/*/activate.log +haed -20 inst/run-port-*/nodes/*/tmp/report.txt ls inst/run-port-01/finish/fail01/ | tee -a $TEST_RESULTS # Add the port-01 and port-02 module config into the file diff --git a/testing/test_base.sh b/testing/test_base.sh index 3a4363e93a..cf4bf4aed7 100755 --- a/testing/test_base.sh +++ b/testing/test_base.sh @@ -19,7 +19,7 @@ MARKER=inst/run-port-01/nodes/hold01/activate.log monitor_marker $MARKER "sudo ip link set pri-eth1 down" cmd/run -b -k -s site_path=inst/tmp_site echo DAQ result code $? | tee -a $TEST_RESULTS -more inst/result.log | tee -a $TEST_RESULTS +cat inst/result.log | tee -a $TEST_RESULTS echo Redacted report for 9a02571e8f00: cat inst/reports/report_9a02571e8f00_*.md | redact | tee -a $TEST_RESULTS @@ -29,7 +29,7 @@ echo %%%%%%%%%%%%%%%%%%%%%% Telnet fail | tee -a $TEST_RESULTS docker rmi daqf/test_hold:latest # Check case of missing image cmd/run -s -k interfaces.faux.opts=telnet echo DAQ result code $? | tee -a $TEST_RESULTS -more inst/result.log | tee -a $TEST_RESULTS +cat inst/result.log | tee -a $TEST_RESULTS cat inst/run-port-01/nodes/nmap01/activate.log fgrep 'security.ports.nmap' inst/reports/report_9a02571e8f00_*.md | tee -a $TEST_RESULTS DAQ_TARGETS=test_hold cmd/build @@ -38,7 +38,7 @@ DAQ_TARGETS=test_hold cmd/build echo %%%%%%%%%%%%%%%%%%%%%% Default MUD | tee -a $TEST_RESULTS cmd/run -s interfaces.faux.opts=telnet device_specs=resources/device_specs/simple.json echo DAQ result code $? | tee -a $TEST_RESULTS -more inst/result.log | tee -a $TEST_RESULTS +cat inst/result.log | tee -a $TEST_RESULTS fgrep 'security.ports.nmap' inst/reports/report_9a02571e8f00_*.md | tee -a $TEST_RESULTS cat inst/run-port-01/nodes/nmap01/activate.log diff --git a/testing/test_modules.sh b/testing/test_modules.sh index f703b75c77..88ab08fa0e 100755 --- a/testing/test_modules.sh +++ b/testing/test_modules.sh @@ -40,7 +40,5 @@ cat $TEST_LIST | while read module args; do fi done -testing/run_unit_tests.sh || exit 1 - echo echo Testing complete. | tee -a $TEST_RESULTS From 83172aa85401462ed5989dcdfaf031268164d456 Mon Sep 17 00:00:00 2001 From: Noureddine Date: Mon, 3 Aug 2020 11:28:35 +0100 Subject: [PATCH 067/212] Remove faux dependencies from subset directory (#567) * move faux dependencies out of the subset directory --- .../bacnetFaux/.idea/google-java-format.xml | 6 + .../bacnet/bacnetFaux/.idea/gradle.xml | 18 + .../bacnetFaux/.idea/libraries/bacnet4j.xml | 9 + .../include/bacnet/bacnetFaux/.idea/misc.xml | 7 + docker/include/bacnet/bacnetFaux/build.gradle | 41 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 56177 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + docker/include/bacnet/bacnetFaux/gradlew | 172 ++++ docker/include/bacnet/bacnetFaux/gradlew.bat | 84 ++ .../include/bacnet/bacnetFaux/settings.gradle | 2 + .../main/java/FauxDeviceEngine/Analog.java | 0 .../main/java/FauxDeviceEngine/Binary.java | 0 .../java/FauxDeviceEngine/EntryPoint.java | 0 .../src/main/java/FauxDeviceEngine/JSON.java | 0 .../java/FauxDeviceEngine/helper/Device.java | 0 .../FauxDeviceEngine/helper/FileManager.java | 74 ++ .../src/main/resources/Faux-Device-Fail.json | 184 ++++ .../src/main/resources/Faux-Device-Pass.json | 185 ++++ .../bacnetFaux/src/main/resources/pics.csv | 486 +++++++++ docker/include/bin/start_faux | 4 +- .../include}/pentests/brute_server.py | 0 .../security/nginx-site/html/index.html | 0 .../include}/security/nginxfail.conf | 0 .../include}/security/nginxpass.conf | 0 .../include}/security/sshfaux/ssh_build.sh | 0 .../include}/security/sshfaux/ssh_privsep.sh | 0 .../security/tlsfaux/absolute_filepath.py | 0 .../security/tlsfaux/certs/server.crt | 0 .../security/tlsfaux/certs/server.csr | 0 .../security/tlsfaux/certs/server.key | 0 .../security/tlsfaux/expcerts/server.crt | 0 .../security/tlsfaux/expcerts/server.csr | 0 .../security/tlsfaux/expcerts/server.key | 0 .../security/tlsfaux/generate_certs.py | 0 .../include}/security/tlsfaux/server.py | 0 docker/modules/Dockerfile.faux1 | 22 +- docker/modules/Dockerfile.faux2 | 8 +- .../src/main/java/helper/FileManager.java | 106 +- .../bacnetTests/src/main/resources/pics.csv | 970 +++++++++--------- 39 files changed, 1833 insertions(+), 550 deletions(-) create mode 100644 docker/include/bacnet/bacnetFaux/.idea/google-java-format.xml create mode 100644 docker/include/bacnet/bacnetFaux/.idea/gradle.xml create mode 100644 docker/include/bacnet/bacnetFaux/.idea/libraries/bacnet4j.xml create mode 100644 docker/include/bacnet/bacnetFaux/.idea/misc.xml create mode 100644 docker/include/bacnet/bacnetFaux/build.gradle create mode 100644 docker/include/bacnet/bacnetFaux/gradle/wrapper/gradle-wrapper.jar create mode 100644 docker/include/bacnet/bacnetFaux/gradle/wrapper/gradle-wrapper.properties create mode 100755 docker/include/bacnet/bacnetFaux/gradlew create mode 100644 docker/include/bacnet/bacnetFaux/gradlew.bat create mode 100644 docker/include/bacnet/bacnetFaux/settings.gradle rename {subset/bacnet/bacnetTests => docker/include/bacnet/bacnetFaux}/src/main/java/FauxDeviceEngine/Analog.java (100%) rename {subset/bacnet/bacnetTests => docker/include/bacnet/bacnetFaux}/src/main/java/FauxDeviceEngine/Binary.java (100%) rename {subset/bacnet/bacnetTests => docker/include/bacnet/bacnetFaux}/src/main/java/FauxDeviceEngine/EntryPoint.java (100%) rename {subset/bacnet/bacnetTests => docker/include/bacnet/bacnetFaux}/src/main/java/FauxDeviceEngine/JSON.java (100%) rename {subset/bacnet/bacnetTests => docker/include/bacnet/bacnetFaux}/src/main/java/FauxDeviceEngine/helper/Device.java (100%) create mode 100644 docker/include/bacnet/bacnetFaux/src/main/java/FauxDeviceEngine/helper/FileManager.java create mode 100644 docker/include/bacnet/bacnetFaux/src/main/resources/Faux-Device-Fail.json create mode 100644 docker/include/bacnet/bacnetFaux/src/main/resources/Faux-Device-Pass.json create mode 100644 docker/include/bacnet/bacnetFaux/src/main/resources/pics.csv rename {subset => docker/include}/pentests/brute_server.py (100%) rename {subset => docker/include}/security/nginx-site/html/index.html (100%) rename {subset => docker/include}/security/nginxfail.conf (100%) rename {subset => docker/include}/security/nginxpass.conf (100%) rename {subset => docker/include}/security/sshfaux/ssh_build.sh (100%) rename {subset => docker/include}/security/sshfaux/ssh_privsep.sh (100%) rename {subset => docker/include}/security/tlsfaux/absolute_filepath.py (100%) rename {subset => docker/include}/security/tlsfaux/certs/server.crt (100%) rename {subset => docker/include}/security/tlsfaux/certs/server.csr (100%) rename {subset => docker/include}/security/tlsfaux/certs/server.key (100%) rename {subset => docker/include}/security/tlsfaux/expcerts/server.crt (100%) rename {subset => docker/include}/security/tlsfaux/expcerts/server.csr (100%) rename {subset => docker/include}/security/tlsfaux/expcerts/server.key (100%) rename {subset => docker/include}/security/tlsfaux/generate_certs.py (100%) rename {subset => docker/include}/security/tlsfaux/server.py (100%) diff --git a/docker/include/bacnet/bacnetFaux/.idea/google-java-format.xml b/docker/include/bacnet/bacnetFaux/.idea/google-java-format.xml new file mode 100644 index 0000000000..8b57f4527a --- /dev/null +++ b/docker/include/bacnet/bacnetFaux/.idea/google-java-format.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/docker/include/bacnet/bacnetFaux/.idea/gradle.xml b/docker/include/bacnet/bacnetFaux/.idea/gradle.xml new file mode 100644 index 0000000000..d50e06cdb1 --- /dev/null +++ b/docker/include/bacnet/bacnetFaux/.idea/gradle.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/docker/include/bacnet/bacnetFaux/.idea/libraries/bacnet4j.xml b/docker/include/bacnet/bacnetFaux/.idea/libraries/bacnet4j.xml new file mode 100644 index 0000000000..fc50401e9e --- /dev/null +++ b/docker/include/bacnet/bacnetFaux/.idea/libraries/bacnet4j.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/docker/include/bacnet/bacnetFaux/.idea/misc.xml b/docker/include/bacnet/bacnetFaux/.idea/misc.xml new file mode 100644 index 0000000000..bc8d0a3a63 --- /dev/null +++ b/docker/include/bacnet/bacnetFaux/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/docker/include/bacnet/bacnetFaux/build.gradle b/docker/include/bacnet/bacnetFaux/build.gradle new file mode 100644 index 0000000000..85657774fd --- /dev/null +++ b/docker/include/bacnet/bacnetFaux/build.gradle @@ -0,0 +1,41 @@ +plugins { + id 'java' +} + +group 'bacnetFaux' +version '1.0-SNAPSHOT' + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + +dependencies { + testCompile group: 'junit', name: 'junit', version: '4.13' + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'com.googlecode.json-simple:json-simple:1.1.1' +} + +jar { + manifest { + attributes 'Main-Class': 'Main' + } +} + +task fatJar(type: Jar) { + manifest.from jar.manifest + classifier = 'all' + from { + configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } + } { + exclude "META-INF/*.SF" + exclude "META-INF/*.DSA" + exclude "META-INF/*.RSA" + } + with jar +} + +artifacts { + archives fatJar +} diff --git a/docker/include/bacnet/bacnetFaux/gradle/wrapper/gradle-wrapper.jar b/docker/include/bacnet/bacnetFaux/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..94336fcae912db8a11d55634156fa011f4686124 GIT binary patch literal 56177 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 i;x|p)^~-yfPOPa3(|vBayXKz \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/docker/include/bacnet/bacnetFaux/gradlew.bat b/docker/include/bacnet/bacnetFaux/gradlew.bat new file mode 100644 index 0000000000..e95643d6a2 --- /dev/null +++ b/docker/include/bacnet/bacnetFaux/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/docker/include/bacnet/bacnetFaux/settings.gradle b/docker/include/bacnet/bacnetFaux/settings.gradle new file mode 100644 index 0000000000..600831e41d --- /dev/null +++ b/docker/include/bacnet/bacnetFaux/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'bacnet' + diff --git a/subset/bacnet/bacnetTests/src/main/java/FauxDeviceEngine/Analog.java b/docker/include/bacnet/bacnetFaux/src/main/java/FauxDeviceEngine/Analog.java similarity index 100% rename from subset/bacnet/bacnetTests/src/main/java/FauxDeviceEngine/Analog.java rename to docker/include/bacnet/bacnetFaux/src/main/java/FauxDeviceEngine/Analog.java diff --git a/subset/bacnet/bacnetTests/src/main/java/FauxDeviceEngine/Binary.java b/docker/include/bacnet/bacnetFaux/src/main/java/FauxDeviceEngine/Binary.java similarity index 100% rename from subset/bacnet/bacnetTests/src/main/java/FauxDeviceEngine/Binary.java rename to docker/include/bacnet/bacnetFaux/src/main/java/FauxDeviceEngine/Binary.java diff --git a/subset/bacnet/bacnetTests/src/main/java/FauxDeviceEngine/EntryPoint.java b/docker/include/bacnet/bacnetFaux/src/main/java/FauxDeviceEngine/EntryPoint.java similarity index 100% rename from subset/bacnet/bacnetTests/src/main/java/FauxDeviceEngine/EntryPoint.java rename to docker/include/bacnet/bacnetFaux/src/main/java/FauxDeviceEngine/EntryPoint.java diff --git a/subset/bacnet/bacnetTests/src/main/java/FauxDeviceEngine/JSON.java b/docker/include/bacnet/bacnetFaux/src/main/java/FauxDeviceEngine/JSON.java similarity index 100% rename from subset/bacnet/bacnetTests/src/main/java/FauxDeviceEngine/JSON.java rename to docker/include/bacnet/bacnetFaux/src/main/java/FauxDeviceEngine/JSON.java diff --git a/subset/bacnet/bacnetTests/src/main/java/FauxDeviceEngine/helper/Device.java b/docker/include/bacnet/bacnetFaux/src/main/java/FauxDeviceEngine/helper/Device.java similarity index 100% rename from subset/bacnet/bacnetTests/src/main/java/FauxDeviceEngine/helper/Device.java rename to docker/include/bacnet/bacnetFaux/src/main/java/FauxDeviceEngine/helper/Device.java diff --git a/docker/include/bacnet/bacnetFaux/src/main/java/FauxDeviceEngine/helper/FileManager.java b/docker/include/bacnet/bacnetFaux/src/main/java/FauxDeviceEngine/helper/FileManager.java new file mode 100644 index 0000000000..35ef1bc27c --- /dev/null +++ b/docker/include/bacnet/bacnetFaux/src/main/java/FauxDeviceEngine/helper/FileManager.java @@ -0,0 +1,74 @@ +package helper; + +import java.io.File; + +public class FileManager { + + private String filePath = ""; + private String csvName = "pics"; + private String csvExtension = ".csv"; + private boolean debug = false; + + /** + * Checks if pics.csv exists. + * @return if pics.csv exists + */ + public boolean checkDevicePicCSV() { + String csvFolder = getCSVPath(); + try { + File[] listFiles = new File(csvFolder).listFiles(); + for (int i = 0; i < listFiles.length; i++) { + if (listFiles[i].isFile()) { + String fileName = listFiles[i].getName(); + if (fileName.contains(csvName) + && fileName.endsWith(csvExtension)) { + System.out.println("pics.csv file found in " + csvFolder); + setFilePath(fileName); + return true; + } + } + } + String errorMessage = "pics.csv not found.\n"; + System.err.println(errorMessage); + } catch (Exception e) { + System.out.println("Error in reading " + csvName + csvExtension + " in " + csvFolder); + } + return false; + } + + private void setFilePath(String fileName) { + String absolutePath = getCSVPath(); + this.filePath = absolutePath + "/" + fileName; + } + + public String getFilePath() { + return this.filePath; + } + + /** + * Returns absolute path to the working directory. + */ + public String getAbsolutePath() { + String absolutePath = ""; + String systemPath = System.getProperty("user.dir"); + System.out.println("system_path: " + systemPath); + String[] pathArr = systemPath.split("/"); + for (int count = 0; count < pathArr.length; count++) { + if (pathArr[count].equals("bacnetTests")) { + break; + } + absolutePath += pathArr[count] + "/"; + } + return absolutePath; + } + + /** + * Returns directory pics.csv is located within test container + */ + public String getCSVPath() { + if (debug) { + return "src/main/resources"; + } + return "/config/type"; + } +} diff --git a/docker/include/bacnet/bacnetFaux/src/main/resources/Faux-Device-Fail.json b/docker/include/bacnet/bacnetFaux/src/main/resources/Faux-Device-Fail.json new file mode 100644 index 0000000000..29324d53d3 --- /dev/null +++ b/docker/include/bacnet/bacnetFaux/src/main/resources/Faux-Device-Fail.json @@ -0,0 +1,184 @@ +[ + { + "DeviceID": "1234", + "AnalogInput01": { + "Object_Name": "device_run_command", + "Device_Type": "0to1Volts", + "Deadband": "21f", + "Resolution": "0.3f", + "Event_Enable": "true true false", + "Event_State": "0", + "Object_Type": "0", + "Time_Delay_Normal": "0", + "Low_Limit": "0", + "Limit_Enable": "false false", + "Cov_Increment": "1.0f", + "Status_Flags": "false false false false", + "Update_Interval": "1001", + "Acked_Transitions": "true true true", + "High_Limit": "0", + "Notify_Type": "0", + "Event_Detection_Enable": "false", + "Min_Pres_Value": "103.78f", + "Max_Pres_Value": "145.89f", + "Reliability": "4", + "Event_Message_Texts": "true", + "Notification_Class": "3", + "Description": "Faux-Device created to run inside DAQ", + "Event_Algorithm_Inhibit": "false", + "Units": "64", + "Profile_Name": "FD-01", + "Out_Of_Service": "false" + } + }, + { + "AnalogOutput01": { + "Event_State": "0", + "Time_Delay_Normal": "0", + "Reliability": "4", + "Resolution": "0.3f", + "Event_Algorithm_Inhibit": "false", + "Out_Of_Service": "false", + "Status_Flags": "false false false false", + "Object_Type": "1", + "Description": "Faux-Device created to run inside DAQ", + "Low_Limit": "0", + "Deadband": "22f", + "Cov_Increment": "1.0f", + "Limit_Enable": "false false", + "Object_Name": "fan_run_speed_percentage_command", + "Notification_Class": "3", + "Units": "62", + "Notify_Type": "0", + "Device_Type": "0to1Volts", + "Event_Enable": "true true false", + "Event_Detection_Enable": "false", + "Event_Message_Texts": "true", + "High_Limit": "0", + "Acked_Transitions": "true true true", + "Priority_Array": "true", + "Relinquish_Default": "0.1" + } + }, + { + "AnalogValue01": { + "Object_Name":"chilled_water_valve_percentage_setpoint", + "Present_Value":"5.1f", + "Deadband": "21.0f", + "Out_Of_Service": "false", + "Event_Message_Texts": "true", + "Event_State": "1", + "Time_Delay_Normal": "1", + "Low_Limit": "0", + "Object_Type": "2", + "Cov_Increment": "1.2f", + "Limit_Enable": "false false", + "Status_Flags": "false true false true", + "Acked_Transitions": "true false true", + "High_Limit": "0", + "Notify_Type": "0", + "Event_Detection_Enable": "false", + "Reliability": "4", + "Notification_Class": "2", + "Description": "Faux-Device created to run inside DAQ", + "Units": "62", + "Event_Algorithm_Inhibit": "false" + } + }, + { + "BinaryInput01": { + "Object_Name":"chiller_water_valve_percentage_command", + "Present_Value":"5", + "Out_Of_Service": "false", + "Active_Text": "TRUE", + "Time_Of_State_Count_Reset": "13/05/2019", + "Event_Enable": "true true false", + "Change_Of_State_Count": "0", + "Event_State": "0", + "Object_Type": "3", + "Time_Delay_Normal": "0", + "Inactive_Text": "FALSE", + "Alarm_Value": "0", + "Acked_Transitions": "true false true", + "Status_Flags": "false false false false", + "Change_Of_State_Time": "13/05/2019", + "Notify_Type": "0", + "Time_Of_Active_Time_Reset": "13/05/2019", + "Event_Detection_Enable": "false", + "Reliability": "4", + "Event_Message_Texts": "true", + "Elapsed_Active_Time": "0", + "Notification_Class": "3", + "Description": "Faux-Device created to run inside DAQ", + "Event_Algorithm_Inhibit": "false", + "Polarity": "0", + "Device_Type": "0to1Volts" + } + }, + { + "BinaryOutput01": { + "Object_Name":"fun_run_command", + "Present_Value":"5", + "Out_Of_Service": "false", + "Active_Text": "TRUE", + "Time_Of_State_Count_Reset": "13/05/2019", + "Event_Enable": "true true false", + "Change_Of_State_Count": "0", + "Event_State": "0", + "Object_Type": "4", + "Time_Delay_Normal": "0", + "Inactive_Text": "FALSE", + "Alarm_Value": "0", + "Acked_Transitions": "true false true", + "Status_Flags": "false false false false", + "Change_Of_State_Time": "13/05/2019", + "Notify_Type": "0", + "Time_Of_Active_Time_Reset": "13/05/2019", + "Event_Detection_Enable": "false", + "Reliability": "4", + "Event_Message_Texts": "true", + "Elapsed_Active_Time": "0", + "Notification_Class": "3", + "Description": "Faux-Device created to run inside DAQ", + "Event_Algorithm_Inhibit": "false", + "Minimum_On_Time": "0", + "Minimum_Off_Time": "0", + "Relinquish_Default": "0.0", + "Feedback_Value": "0", + "Polarity": "0", + "Device_Type": "0to1Volts" + } + }, + { + "BinaryValue01": { + "Object_Name":"device1_run_command", + "Present_Value":"5", + "Out_Of_Service": "false", + "Active_Text": "TRUE", + "Time_Of_State_Count_Reset": "13/05/2019", + "Event_Enable": "true true false", + "Change_Of_State_Count": "0", + "Event_State": "0", + "Object_Type": "4", + "Time_Delay_Normal": "0", + "Inactive_Text": "FALSE", + "Alarm_Value": "0", + "Acked_Transitions": "true false true", + "Status_Flags": "false false false false", + "Change_Of_State_Time": "13/05/2019", + "Notify_Type": "0", + "Time_Of_Active_Time_Reset": "13/05/2019", + "Event_Detection_Enable": "false", + "Reliability": "4", + "Event_Message_Texts": "true", + "Elapsed_Active_Time": "0", + "Notification_Class": "3", + "Description": "Faux-Device created to run inside DAQ", + "Event_Algorithm_Inhibit": "false", + "Minimum_On_Time": "0", + "Minimum_Off_Time": "0", + "Relinquish_Default": "0.0", + "Feedback_Value": "0" + } + } +] diff --git a/docker/include/bacnet/bacnetFaux/src/main/resources/Faux-Device-Pass.json b/docker/include/bacnet/bacnetFaux/src/main/resources/Faux-Device-Pass.json new file mode 100644 index 0000000000..678817d3ff --- /dev/null +++ b/docker/include/bacnet/bacnetFaux/src/main/resources/Faux-Device-Pass.json @@ -0,0 +1,185 @@ +[ + { + "DeviceID": "1234", + "AnalogInput01": { + "Present_Value": "5.1", + "Object_Name": "device_run_command", + "Device_Type": "0to1Volts", + "Deadband": "21f", + "Resolution": "0.3f", + "Event_Enable": "true true false", + "Event_State": "0", + "Object_Type": "0", + "Time_Delay_Normal": "0", + "Low_Limit": "0", + "Limit_Enable": "false false", + "Cov_Increment": "1.0f", + "Status_Flags": "false false false false", + "Update_Interval": "1001", + "Acked_Transitions": "true true true", + "High_Limit": "0", + "Notify_Type": "0", + "Event_Detection_Enable": "false", + "Min_Pres_Value": "103.78f", + "Max_Pres_Value": "145.89f", + "Reliability": "4", + "Event_Message_Texts": "true", + "Notification_Class": "3", + "Description": "Faux-Device created to run inside DAQ", + "Event_Algorithm_Inhibit": "false", + "Units": "64", + "Profile_Name": "FD-01", + "Out_Of_Service": "false" + } + }, + { + "AnalogOutput01": { + "Event_State": "0", + "Time_Delay_Normal": "0", + "Reliability": "4", + "Resolution": "0.3f", + "Event_Algorithm_Inhibit": "false", + "Out_Of_Service": "false", + "Status_Flags": "false false false false", + "Object_Type": "1", + "Description": "Faux-Device created to run inside DAQ", + "Low_Limit": "0", + "Deadband": "22f", + "Cov_Increment": "1.0f", + "Limit_Enable": "false false", + "Object_Name": "fan_run_speed_percentage_command", + "Notification_Class": "3", + "Units": "62", + "Notify_Type": "0", + "Device_Type": "0to1Volts", + "Event_Enable": "true true false", + "Event_Detection_Enable": "false", + "Event_Message_Texts": "true", + "High_Limit": "0", + "Acked_Transitions": "true true true", + "Priority_Array": "true", + "Relinquish_Default": "0.1" + } + }, + { + "AnalogValue01": { + "Object_Name":"chilled_water_valve_percentage_setpoint", + "Present_Value":"5.1f", + "Deadband": "21.0f", + "Out_Of_Service": "false", + "Event_Message_Texts": "true", + "Event_State": "1", + "Time_Delay_Normal": "1", + "Low_Limit": "0", + "Object_Type": "2", + "Cov_Increment": "1.2f", + "Limit_Enable": "false false", + "Status_Flags": "false true false true", + "Acked_Transitions": "true false true", + "High_Limit": "0", + "Notify_Type": "0", + "Event_Detection_Enable": "false", + "Reliability": "4", + "Notification_Class": "2", + "Description": "Faux-Device created to run inside DAQ", + "Units": "62", + "Event_Algorithm_Inhibit": "false" + } + }, + { + "BinaryInput01": { + "Object_Name":"chiller_water_valve_percentage_command", + "Present_Value":"5", + "Out_Of_Service": "false", + "Active_Text": "TRUE", + "Time_Of_State_Count_Reset": "13/05/2019", + "Event_Enable": "true true false", + "Change_Of_State_Count": "0", + "Event_State": "0", + "Object_Type": "3", + "Time_Delay_Normal": "0", + "Inactive_Text": "FALSE", + "Alarm_Value": "0", + "Acked_Transitions": "true false true", + "Status_Flags": "false false false false", + "Change_Of_State_Time": "13/05/2019", + "Notify_Type": "0", + "Time_Of_Active_Time_Reset": "13/05/2019", + "Event_Detection_Enable": "false", + "Reliability": "4", + "Event_Message_Texts": "true", + "Elapsed_Active_Time": "0", + "Notification_Class": "3", + "Description": "Faux-Device created to run inside DAQ", + "Event_Algorithm_Inhibit": "false", + "Polarity": "0", + "Device_Type": "0to1Volts" + } + }, + { + "BinaryOutput01": { + "Object_Name":"fun_run_command", + "Present_Value":"5", + "Out_Of_Service": "false", + "Active_Text": "TRUE", + "Time_Of_State_Count_Reset": "13/05/2019", + "Event_Enable": "true true false", + "Change_Of_State_Count": "0", + "Event_State": "0", + "Object_Type": "4", + "Time_Delay_Normal": "0", + "Inactive_Text": "FALSE", + "Alarm_Value": "0", + "Acked_Transitions": "true false true", + "Status_Flags": "false false false false", + "Change_Of_State_Time": "13/05/2019", + "Notify_Type": "0", + "Time_Of_Active_Time_Reset": "13/05/2019", + "Event_Detection_Enable": "false", + "Reliability": "4", + "Event_Message_Texts": "true", + "Elapsed_Active_Time": "0", + "Notification_Class": "3", + "Description": "Faux-Device created to run inside DAQ", + "Event_Algorithm_Inhibit": "false", + "Minimum_On_Time": "0", + "Minimum_Off_Time": "0", + "Relinquish_Default": "0.0", + "Feedback_Value": "0", + "Polarity": "0", + "Device_Type": "0to1Volts" + } + }, + { + "BinaryValue01": { + "Object_Name":"device1_run_command", + "Present_Value":"5", + "Out_Of_Service": "false", + "Active_Text": "TRUE", + "Time_Of_State_Count_Reset": "13/05/2019", + "Event_Enable": "true true false", + "Change_Of_State_Count": "0", + "Event_State": "0", + "Object_Type": "4", + "Time_Delay_Normal": "0", + "Inactive_Text": "FALSE", + "Alarm_Value": "0", + "Acked_Transitions": "true false true", + "Status_Flags": "false false false false", + "Change_Of_State_Time": "13/05/2019", + "Notify_Type": "0", + "Time_Of_Active_Time_Reset": "13/05/2019", + "Event_Detection_Enable": "false", + "Reliability": "4", + "Event_Message_Texts": "true", + "Elapsed_Active_Time": "0", + "Notification_Class": "3", + "Description": "Faux-Device created to run inside DAQ", + "Event_Algorithm_Inhibit": "false", + "Minimum_On_Time": "0", + "Minimum_Off_Time": "0", + "Relinquish_Default": "0.0", + "Feedback_Value": "0" + } + } +] diff --git a/docker/include/bacnet/bacnetFaux/src/main/resources/pics.csv b/docker/include/bacnet/bacnetFaux/src/main/resources/pics.csv new file mode 100644 index 0000000000..aab3985dec --- /dev/null +++ b/docker/include/bacnet/bacnetFaux/src/main/resources/pics.csv @@ -0,0 +1,486 @@ +Bacnet_Object_Type,Bacnet_Object_Property,Property_Datatype,Conformance_Code,Supported, +Bacnet_Analogue_Input,Object_Identifier,BACnetObjectIdentifier,R,TRUE, +Bacnet_Analogue_Input,Object_Name,CharacterString,W,TRUE, +Bacnet_Analogue_Input,Object_Type,BACnetObjectType,R,TRUE, +Bacnet_Analogue_Input,Present_Value,REAL,R,TRUE, + ,Description,CharacterString,O,TRUE, +Bacnet_Analogue_Input,Device_Type,,O,TRUE, +Bacnet_Analogue_Input,Status_Flags,BACnetStatusFlags,R,TRUE, +Bacnet_Analogue_Input,Event_State,BACnetEventState,R,TRUE, +Bacnet_Analogue_Input,Reliability,BACnetReliability,O,TRUE, +Bacnet_Analogue_Input,Out_Of_Service,BOOLEAN,W,TRUE, +Bacnet_Analogue_Input,Update_Interval,,O,TRUE, +Bacnet_Analogue_Input,Units,,R,TRUE, +Bacnet_Analogue_Input,Min_Pres_Value,REAL,O,TRUE, +Bacnet_Analogue_Input,Max_Pres_Value,REAL,O,TRUE, +Bacnet_Analogue_Input,Resolution,,O,TRUE, +Bacnet_Analogue_Input,COV_Increment,REAL,O,TRUE, +Bacnet_Analogue_Input,COV_Period,,O,TRUE, +Bacnet_Analogue_Input,COV_Min_Send_Time,,O,TRUE, +Bacnet_Analogue_Input,Time_Delay,,O,TRUE, +Bacnet_Analogue_Input,Notification_Class,Unsigned,O,TRUE, +Bacnet_Analogue_Input,High_Limit,,O,TRUE, +Bacnet_Analogue_Input,Low_Limit,,O,TRUE, +Bacnet_Analogue_Input,Deadband,,O,TRUE, +Bacnet_Analogue_Input,Limit_Enable,,O,TRUE, +Bacnet_Analogue_Input,Event_Enable,BACnetEventTransitionBits,O,TRUE, +Bacnet_Analogue_Input,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, +Bacnet_Analogue_Input,Notify_Type,BACnetNotifyType,O,TRUE, +Bacnet_Analogue_Input,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, +Bacnet_Analogue_Input,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Analogue_Input,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Analogue_Input,Event_Detection_Enable,BOOLEAN,O,TRUE, +Bacnet_Analogue_Input,Time_Delay_Normal,,O,TRUE, +Bacnet_Analogue_Input,Event_Algorithm_Inhibit,,O,TRUE, +Bacnet_Analogue_Input,Event_Algorithm_Inhibit_Ref,,O,TRUE, +Bacnet_Analogue_Input,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,R,TRUE, +Bacnet_Analogue_Output,Object_Identifier,BACnetObjectIdentifier,R,TRUE, +Bacnet_Analogue_Output,Object_Name,CharacterString,W,TRUE, +Bacnet_Analogue_Output,Object_Type,BACnetObjectType,R,TRUE, +Bacnet_Analogue_Output,Present_Value,REAL,W,TRUE, +Bacnet_Analogue_Output,Description,CharacterString,O,TRUE, +Bacnet_Analogue_Output,Device_Type,,O,TRUE, +Bacnet_Analogue_Output,Status_Flags,BACnetStatusFlags,R,TRUE, +Bacnet_Analogue_Output,Event_State,BACnetEventState,R,TRUE, +Bacnet_Analogue_Output,Reliability,BACnetReliability,O,TRUE, +Bacnet_Analogue_Output,Out_Of_Service,BOOLEAN,W,TRUE, +Bacnet_Analogue_Output,Units,,R,TRUE, +Bacnet_Analogue_Output,Min_Present_Value,,O,TRUE, +Bacnet_Analogue_Output,Max_Present_Value,,O,TRUE, +Bacnet_Analogue_Output,Resolution,,O,TRUE, +Bacnet_Analogue_Output,Priority_Array,,R,TRUE, +Bacnet_Analogue_Output,Relinquish_Default,,W,TRUE, +Bacnet_Analogue_Output,COV_Increment,REAL,O,TRUE, +Bacnet_Analogue_Output,COV_Period,,O,TRUE, +Bacnet_Analogue_Output,COV_Min_Send_Time,,O,TRUE, +Bacnet_Analogue_Output,Time_Delay,,O,TRUE, +Bacnet_Analogue_Output,Notification_Class,Unsigned,O,TRUE, +Bacnet_Analogue_Output,High_Limit,,O,TRUE, +Bacnet_Analogue_Output,Low_Limit,,O,TRUE, +Bacnet_Analogue_Output,Deadband,,O,TRUE, +Bacnet_Analogue_Output,Limit_Enable,,O,TRUE, +Bacnet_Analogue_Output,Event_Enable,BACnetEventTransitionBits,O,TRUE, +Bacnet_Analogue_Output,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, +Bacnet_Analogue_Output,Notify_Type,BACnetNotifyType,O,TRUE, +Bacnet_Analogue_Output,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, +Bacnet_Analogue_Output,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Analogue_Output,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Analogue_Output,Event_Detection_Enable,BOOLEAN,O,TRUE, +Bacnet_Analogue_Output,Time_Delay_Normal,,O,TRUE, +Bacnet_Analogue_Output,Event_Algorithm_Inhibit,,O,TRUE, +Bacnet_Analogue_Output,Event_Algorithm_Inhibit_Ref,,O,TRUE, +Bacnet_Analogue_Output,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,R,TRUE, +Bacnet_Analogue_Value,Object_Identifier,BACnetObjectIdentifier,O,TRUE, +Bacnet_Analogue_Value,Object_Name,CharacterString,O,TRUE, +Bacnet_Analogue_Value,Object_Type,BACnetObjectType,O,TRUE, +Bacnet_Analogue_Value,Present_Value,REAL,O,TRUE, +Bacnet_Analogue_Value,Description,CharacterString,O,TRUE, +Bacnet_Analogue_Value,Status_Flags,BACnetStatusFlags,O,TRUE, +Bacnet_Analogue_Value,Event_State,BACnetEventState,O,TRUE, +Bacnet_Analogue_Value,Reliability,BACnetReliability,O,TRUE, +Bacnet_Analogue_Value,Out_Of_Service,BOOLEAN,O,TRUE, +Bacnet_Analogue_Value,Units,,O,TRUE, +Bacnet_Analogue_Value,Priority_Array,,O,TRUE, +Bacnet_Analogue_Value,Relinquish_Default,,O,TRUE, +Bacnet_Analogue_Value,Min_Present_Value,,O,TRUE, +Bacnet_Analogue_Value,Max_Present_Value,,O,TRUE, +Bacnet_Analogue_Value,COV_Increment,REAL,O,TRUE, +Bacnet_Analogue_Value,COV_Period,,O,TRUE, +Bacnet_Analogue_Value,COV_Min_Send_Time,,O,TRUE, +Bacnet_Analogue_Value,Time_Delay,,O,TRUE, +Bacnet_Analogue_Value,Notification_Class,Unsigned,O,TRUE, +Bacnet_Analogue_Value,High_Limit,,O,TRUE, +Bacnet_Analogue_Value,Low_Limit,,O,TRUE, +Bacnet_Analogue_Value,Deadband,,O,TRUE, +Bacnet_Analogue_Value,Limit_Enable,,O,TRUE, +Bacnet_Analogue_Value,Event_Enable,BACnetEventTransitionBits,O,TRUE, +Bacnet_Analogue_Value,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, +Bacnet_Analogue_Value,Notify_Type,BACnetNotifyType,O,TRUE, +Bacnet_Analogue_Value,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, +Bacnet_Analogue_Value,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Analogue_Value,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Analogue_Value,Event_Detection_Enable,BOOLEAN,O,TRUE, +Bacnet_Analogue_Value,Time_Delay_Normal,,O,TRUE, +Bacnet_Analogue_Value,Event_Algorithm_Inhibit,,O,TRUE, +Bacnet_Analogue_Value,Event_Algorithm_Inhibit_Ref,,O,TRUE, +Bacnet_Analogue_Value,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,R,TRUE, +Bacnet_Binary_Input,Object_Identifier,BACnetObjectIdentifier,R,TRUE, +Bacnet_Binary_Input,Object_Name,CharacterString,W,TRUE, +Bacnet_Binary_Input,Object_Type,BACnetObjectType,R,TRUE, +Bacnet_Binary_Input,Present_Value,REAL,R,TRUE, +Bacnet_Binary_Input,Description,CharacterString,O,TRUE, +Bacnet_Binary_Input,Device_Type,,O,TRUE, +Bacnet_Binary_Input,Status_Flags,BACnetStatusFlags,R,TRUE, +Bacnet_Binary_Input,Event_State,BACnetEventState,R,TRUE, +Bacnet_Binary_Input,Reliability,BACnetReliability,O,TRUE, +Bacnet_Binary_Input,Out_Of_Service,BOOLEAN,W,TRUE, +Bacnet_Binary_Input,Polarity,,R,TRUE, +Bacnet_Binary_Input,Inactive_Text,,O,TRUE, +Bacnet_Binary_Input,Active_Text,,O,TRUE, +Bacnet_Binary_Input,Change_Of_State_Time,,O,TRUE, +Bacnet_Binary_Input,Change_Of_State_Count,,O,TRUE, +Bacnet_Binary_Input,Time_Of_State_Count_Reset,,O,TRUE, +Bacnet_Binary_Input,Elapsed_Active_Time,,O,TRUE, +Bacnet_Binary_Input,Time_Of_Active_Time_Reset,,O,TRUE, +Bacnet_Binary_Input,COV_Period,,O,TRUE, +Bacnet_Binary_Input,COV_Min_Send_Time,,O,TRUE, +Bacnet_Binary_Input,Time_Delay,,O,TRUE, +Bacnet_Binary_Input,Notification_Class,Unsigned,O,TRUE, +Bacnet_Binary_Input,Alarm_Value,,O,TRUE, +Bacnet_Binary_Input,Event_Enable,BACnetEventTransitionBits,O,TRUE, +Bacnet_Binary_Input,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, +Bacnet_Binary_Input,Notify_Type,BACnetNotifyType,O,TRUE, +Bacnet_Binary_Input,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, +Bacnet_Binary_Input,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Binary_Input,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Binary_Input,Event_Detection_Enable,BOOLEAN,O,TRUE, +Bacnet_Binary_Input,Time_Delay_Normal,,O,TRUE, +Bacnet_Binary_Input,Event_Algorithm_Inhibit,,O,TRUE, +Bacnet_Binary_Input,Event_Algorithm_Inhibit_Ref,,O,TRUE, +Bacnet_Binary_Input,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,R,TRUE, +Bacnet_Binary_Output,Object_Identifier,BACnetObjectIdentifier,O,TRUE, +Bacnet_Binary_Output,Object_Name,CharacterString,O,TRUE, +Bacnet_Binary_Output,Object_Type,BACnetObjectType,O,TRUE, +Bacnet_Binary_Output,Present_Value,REAL,O,TRUE, +Bacnet_Binary_Output,Description,CharacterString,O,TRUE, +Bacnet_Binary_Output,Device_Type,,O,TRUE, +Bacnet_Binary_Output,Status_Flags,BACnetStatusFlags,O,TRUE, +Bacnet_Binary_Output,Event_State,BACnetEventState,O,TRUE, +Bacnet_Binary_Output,Reliability,BACnetReliability,O,TRUE, +Bacnet_Binary_Output,Out_Of_Service,BOOLEAN,O,TRUE, +Bacnet_Binary_Output,Polarity,,O,TRUE, +Bacnet_Binary_Output,Inactive_Text,,O,TRUE, +Bacnet_Binary_Output,Active_Text,,O,TRUE, +Bacnet_Binary_Output,Change_Of_State_Time,,O,TRUE, +Bacnet_Binary_Output,Change_Of_State_Count,,O,TRUE, +Bacnet_Binary_Output,Time_Of_State_Count_Reset,,O,TRUE, +Bacnet_Binary_Output,Elapsed_Active_Time,,O,TRUE, +Bacnet_Binary_Output,Time_Of_Active_Time_Reset,,O,TRUE, +Bacnet_Binary_Output,Minimum_Off_Time,,O,TRUE, +Bacnet_Binary_Output,Minimum_On_Time,,O,TRUE, +Bacnet_Binary_Output,Priority_Array,,O,TRUE, +Bacnet_Binary_Output,Relinquish_Default,,O,TRUE, +Bacnet_Binary_Output,COV_Period,,O,TRUE, +Bacnet_Binary_Output,COV_Min_Send_Time,,O,TRUE, +Bacnet_Binary_Output,Time_Delay,,O,TRUE, +Bacnet_Binary_Output,Notification_Class,Unsigned,O,TRUE, +Bacnet_Binary_Output,Feedback_Value,,O,TRUE, +Bacnet_Binary_Output,Event_Enable,BACnetEventTransitionBits,O,TRUE, +Bacnet_Binary_Output,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, +Bacnet_Binary_Output,Notify_Type,BACnetNotifyType,O,TRUE, +Bacnet_Binary_Output,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, +Bacnet_Binary_Output,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Binary_Output,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Binary_Output,Event_Detection_Enable,BOOLEAN,O,TRUE, +Bacnet_Binary_Output,Time_Delay_Normal,,O,TRUE, +Bacnet_Binary_Output,Event_Algorithm_Inhibit,,O,TRUE, +Bacnet_Binary_Output,Event_Algorithm_Inhibit_Ref,,O,TRUE, +Bacnet_Binary_Output,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, +Bacnet_Binary_Value,Object_Identifier,BACnetObjectIdentifier,O,TRUE, +Bacnet_Binary_Value,Object_Name,CharacterString,O,TRUE, +Bacnet_Binary_Value,Object_Type,BACnetObjectType,O,TRUE, +Bacnet_Binary_Value,Present_Value,REAL,O,TRUE, +Bacnet_Binary_Value,Description,CharacterString,O,TRUE, +Bacnet_Binary_Value,Status_Flags,BACnetStatusFlags,O,TRUE, +Bacnet_Binary_Value,Event_State,BACnetEventState,O,TRUE, +Bacnet_Binary_Value,Reliability,BACnetReliability,O,TRUE, +Bacnet_Binary_Value,Out_Of_Service,BOOLEAN,O,TRUE, +Bacnet_Binary_Value,Inactive_Text,,O,TRUE, +Bacnet_Binary_Value,Active_Text,,O,TRUE, +Bacnet_Binary_Value,Change_Of_State_Time,,O,TRUE, +Bacnet_Binary_Value,Change_Of_State_Count,,O,TRUE, +Bacnet_Binary_Value,Time_Of_State_Count_Reset,,O,TRUE, +Bacnet_Binary_Value,Elapsed_Active_Time,,O,TRUE, +Bacnet_Binary_Value,Time_Of_Active_Time_Reset,,O,TRUE, +Bacnet_Binary_Value,Minimum_Off_Time,,O,TRUE, +Bacnet_Binary_Value,Minimum_On_Time,,O,TRUE, +Bacnet_Binary_Value,Priority_Array,,O,TRUE, +Bacnet_Binary_Value,Relinquish_Default,,O,TRUE, +Bacnet_Binary_Value,COV_Period,,O,TRUE, +Bacnet_Binary_Value,COV_Min_Send_Time,,O,TRUE, +Bacnet_Binary_Value,Time_Delay,,O,TRUE, +Bacnet_Binary_Value,Notification_Class,Unsigned,O,TRUE, +Bacnet_Binary_Value,Alarm_Value,,O,TRUE, +Bacnet_Binary_Value,Event_Enable,BACnetEventTransitionBits,O,TRUE, +Bacnet_Binary_Value,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, +Bacnet_Binary_Value,Notify_Type,BACnetNotifyType,O,TRUE, +Bacnet_Binary_Value,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, +Bacnet_Binary_Value,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Binary_Value,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Binary_Value,Event_Detection_Enable,BOOLEAN,O,TRUE, +Bacnet_Binary_Value,Time_Delay_Normal,,O,TRUE, +Bacnet_Binary_Value,Event_Algorithm_Inhibit,,O,TRUE, +Bacnet_Binary_Value,Event_Algorithm_Inhibit_Ref,,O,TRUE, +Bacnet_Binary_Value,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, +Bacnet_Calendar,Object_Identifier,BACnetObjectIdentifier,O,TRUE, +Bacnet_Calendar,Object_Name,CharacterString,O,TRUE, +Bacnet_Calendar,Object_Type,BACnetObjectType,O,TRUE, +Bacnet_Calendar,Present_Value,REAL,O,TRUE, +Bacnet_Calendar,Description,CharacterString,O,TRUE, +Bacnet_Calendar,Date_List,,O,TRUE, +Bacnet_Calendar,Time_To_Next_State,,O,TRUE, +Bacnet_Calendar,Next_State,,O,TRUE, +Bacnet_Calendar,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, +Device,Object_Identifier,BACnetObjectIdentifier,W,TRUE, +Device,Object_Name,CharacterString,W,TRUE, +Device,Object_Type,BACnetObjectType,R,TRUE, +Device,System_Status,,R,TRUE, +Device,Vendor_Name,,R,TRUE, +Device,Vendor_Identifier,,R,TRUE, +Device,Model_Name,,R,TRUE, +Device,Firmware_Revision,,R,TRUE, +Device,Application_Software_Version,,R,TRUE, +Device,Location,,O,TRUE, +Device,Description,CharacterString,O,TRUE, +Device,Protocol_Version,,R,TRUE, +Device,Protocol_Revision,,R,TRUE, +Device,Protocol_Services_Supported,,R,TRUE, +Device,Protocol_Object_Types_Supported,,R,TRUE, +Device,Object_List,,R,TRUE, +Device,Max_APDU_Length_Accepted,,R,TRUE, +Device,Segmentation_Supported,,R,TRUE, +Device,Max_Segments_Accepted,,O,TRUE, +Device,Local_Date,,O,TRUE, +Device,Local_Time,,O,TRUE, +Device,UTC_Offset,,O,TRUE, +Device,Daylight_Savings_Status,,O,TRUE, +Device,Apdu_Segment_Timeout,,O,TRUE, +Device,APDU_Timeout,,W,TRUE, +Device,Number_Of_APDU_Retries,,W,TRUE, +Device,Time_Synchronization_Recipients,,O,TRUE, +Device,Device_Address_Binding,,R,TRUE, +Device,Database_Revision,,R,TRUE, +Device,Configuration_Files,,O,TRUE, +Device,Last_Restore_Time,,O,TRUE, +Device,Backup_Failure_Timeout,,O,TRUE, +Device,Backup_Preparation_Time,,O,TRUE, +Device,Restore_Preparation_Time,,O,TRUE, +Device,Restore_Completion_Time,,O,TRUE, +Device,Backup_And_Restore_State,,O,TRUE, +Device,Active_COV_Subscriptions,,O,TRUE, +Device,Last_Restart_Reason,,O,TRUE, +Device,Time_Of_Device_Restart,,O,TRUE, +Device,Restart_Notification_Recipients,,O,TRUE, +Device,Utc_Time_Synchronization_Recipients,,O,TRUE, +Device,Max_Master,,O,TRUE, +Device,Max_Info_Frames,,O,TRUE, +Device,Time_Synchronization_Interval,,O,TRUE, +Device,Align_Intervals,,O,TRUE, +Device,Interval_Offset,,O,TRUE, +Device,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,R,TRUE, +Event_Enrollment,Object_Identifier,BACnetObjectIdentifier,O,TRUE, +Event_Enrollment,Object_Name,CharacterString,O,TRUE, +Event_Enrollment,Object_Type,BACnetObjectType,O,TRUE, +Event_Enrollment,Description,CharacterString,O,TRUE, +Event_Enrollment,Event_Type,,O,TRUE, +Event_Enrollment,Notify_Type,BACnetNotifyType,O,TRUE, +Event_Enrollment,Event_Parameters,,O,TRUE, +Event_Enrollment,Object_Property_Reference,,O,TRUE, +Event_Enrollment,Event_State,BACnetEventState,O,TRUE, +Event_Enrollment,Event_Enable,BACnetEventTransitionBits,O,TRUE, +Event_Enrollment,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, +Event_Enrollment,Notification_Class,Unsigned,O,TRUE, +Event_Enrollment,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, +Event_Enrollment,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, +Event_Enrollment,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, +Event_Enrollment,Event_Detection_Enable,BOOLEAN,O,TRUE, +Event_Enrollment,Time_Delay_Normal,,O,TRUE, +Event_Enrollment,Status_Flags,BACnetStatusFlags,O,TRUE, +Event_Enrollment,Reliability,BACnetReliability,O,TRUE, +Event_Enrollment,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, +Bacnet_File,Object_Identifier,BACnetObjectIdentifier,O,TRUE, +Bacnet_File,Object_Name,CharacterString,O,TRUE, +Bacnet_File,Object_Type,BACnetObjectType,O,TRUE, +Bacnet_File,Description,CharacterString,O,TRUE, +Bacnet_File,File_Type,,O,TRUE, +Bacnet_File,File_Size,,O,TRUE, +Bacnet_File,Modification_Date,,O,TRUE, +Bacnet_File,Archive,,O,TRUE, +Bacnet_File,Read_Only,,O,TRUE, +Bacnet_File,File_Access_Method,,O,TRUE, +Bacnet_File,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, +Bacnet_Loop,Object_Identifier,BACnetObjectIdentifier,O,TRUE, +Bacnet_Loop,Object_Name,CharacterString,O,TRUE, +Bacnet_Loop,Object_Type,BACnetObjectType,O,TRUE, +Bacnet_Loop,Present_Value,REAL,O,TRUE, +Bacnet_Loop,Description,CharacterString,O,TRUE, +Bacnet_Loop,Status_Flags,BACnetStatusFlags,O,TRUE, +Bacnet_Loop,Event_State,BACnetEventState,O,TRUE, +Bacnet_Loop,Reliability,BACnetReliability,O,TRUE, +Bacnet_Loop,Out_Of_Service,BOOLEAN,O,TRUE, +Bacnet_Loop,Update_Interval,,O,TRUE, +Bacnet_Loop,Output_Units,,O,TRUE, +Bacnet_Loop,Manipulated_Variable_Reference,,O,TRUE, +Bacnet_Loop,Controlled_Variable_Reference,,O,TRUE, +Bacnet_Loop,Controlled_Variable_Value,,O,TRUE, +Bacnet_Loop,Controlled_Variable_Units,,O,TRUE, +Bacnet_Loop,Setpoint_Reference,,O,TRUE, +Bacnet_Loop,Setpoint,,O,TRUE, +Bacnet_Loop,Action,,O,TRUE, +Bacnet_Loop,Proportional_Constant,,O,TRUE, +Bacnet_Loop,Proportional_Constant_Units,,O,TRUE, +Bacnet_Loop,Integral_Constant,,O,TRUE, +Bacnet_Loop,Integral_Constant_Units,,O,TRUE, +Bacnet_Loop,Derivative_Constant,,O,TRUE, +Bacnet_Loop,Derivative_Constant_Units,,O,TRUE, +Bacnet_Loop,Bias,,O,TRUE, +Bacnet_Loop,Maximum_Output,,O,TRUE, +Bacnet_Loop,Minimum_Output,,O,TRUE, +Bacnet_Loop,Priority_For_Writing,Unsigned(1..16),O,TRUE, +Bacnet_Loop,LoopDeadband,,O,TRUE, +Bacnet_Loop,Saturation_Time,,O,TRUE, +Bacnet_Loop,COV_Increment,REAL,O,TRUE, +Bacnet_Loop,COV_Period,,O,TRUE, +Bacnet_Loop,COV_Min_Send_Time,,O,TRUE, +Bacnet_Loop,Ramp_Time,,O,TRUE, +Bacnet_Loop,Saturation_Time_Low_Limit_Enable,,O,TRUE, +Bacnet_Loop,Saturation_Time_High_Limit_Enable,,O,TRUE, +Bacnet_Loop,Time_Delay,,O,TRUE, +Bacnet_Loop,Notification_Class,Unsigned,O,TRUE, +Bacnet_Loop,Error_Limit,,O,TRUE, +Bacnet_Loop,Deadband,,O,TRUE, +Bacnet_Loop,Event_Enable,BACnetEventTransitionBits,O,TRUE, +Bacnet_Loop,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, +Bacnet_Loop,Notify_Type,BACnetNotifyType,O,TRUE, +Bacnet_Loop,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, +Bacnet_Loop,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Loop,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Loop,Event_Detection_Enable,BOOLEAN,O,TRUE, +Bacnet_Loop,Time_Delay_Normal,,O,TRUE, +Bacnet_Loop,Event_Algorithm_Inhibit,,O,TRUE, +Bacnet_Loop,Event_Algorithm_Inhibit_Ref,,O,TRUE, +Bacnet_Loop,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, +Bacnet_Multi-state_Input,Object_Identifier,BACnetObjectIdentifier,O,TRUE, +Bacnet_Multi-state_Input,Object_Name,CharacterString,O,TRUE, +Bacnet_Multi-state_Input,Object_Type,BACnetObjectType,O,TRUE, +Bacnet_Multi-state_Input,Present_Value,REAL,O,TRUE, +Bacnet_Multi-state_Input,Description,CharacterString,O,TRUE, +Bacnet_Multi-state_Input,Device_Type,,O,TRUE, +Bacnet_Multi-state_Input,Status_Flags,BACnetStatusFlags,O,TRUE, +Bacnet_Multi-state_Input,Event_State,BACnetEventState,O,TRUE, +Bacnet_Multi-state_Input,Reliability,BACnetReliability,O,TRUE, +Bacnet_Multi-state_Input,Out_Of_Service,BOOLEAN,O,TRUE, +Bacnet_Multi-state_Input,Number_of_States,,O,TRUE, +Bacnet_Multi-state_Input,State_Text,,O,TRUE, +Bacnet_Multi-state_Input,COV_Period,,O,TRUE, +Bacnet_Multi-state_Input,COV_Min_Send_Time,,O,TRUE, +Bacnet_Multi-state_Input,Time_Delay,,O,TRUE, +Bacnet_Multi-state_Input,Notification_Class,Unsigned,O,TRUE, +Bacnet_Multi-state_Input,Alarm_Values,,O,TRUE, +Bacnet_Multi-state_Input,Fault_Values,,O,TRUE, +Bacnet_Multi-state_Input,Event_Enable,BACnetEventTransitionBits,O,TRUE, +Bacnet_Multi-state_Input,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, +Bacnet_Multi-state_Input,Notify_Type,BACnetNotifyType,O,TRUE, +Bacnet_Multi-state_Input,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, +Bacnet_Multi-state_Input,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Multi-state_Input,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Multi-state_Input,Event_Detection_Enable,BOOLEAN,O,TRUE, +Bacnet_Multi-state_Input,Time_Delay_Normal,,O,TRUE, +Bacnet_Multi-state_Input,Event_Algorithm_Inhibit,,O,TRUE, +Bacnet_Multi-state_Input,Event_Algorithm_Inhibit_Ref,,O,TRUE, +Bacnet_Multi-state_Input,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, +Bacnet_Multi-state_Value,Object_Identifier,BACnetObjectIdentifier,O,TRUE, +Bacnet_Multi-state_Value,Object_Name,CharacterString,O,TRUE, +Bacnet_Multi-state_Value,Object_Type,BACnetObjectType,O,TRUE, +Bacnet_Multi-state_Value,Present_Value,REAL,O,TRUE, +Bacnet_Multi-state_Value,Description,CharacterString,O,TRUE, +Bacnet_Multi-state_Value,Status_Flags,BACnetStatusFlags,O,TRUE, +Bacnet_Multi-state_Value,Event_State,BACnetEventState,O,TRUE, +Bacnet_Multi-state_Value,Reliability,BACnetReliability,O,TRUE, +Bacnet_Multi-state_Value,Out_Of_Service,BOOLEAN,O,TRUE, +Bacnet_Multi-state_Value,Number_of_States,,O,TRUE, +Bacnet_Multi-state_Value,State_Text,,O,TRUE, +Bacnet_Multi-state_Value,Priority_Array,,O,TRUE, +Bacnet_Multi-state_Value,Relinquish_Default,,O,TRUE, +Bacnet_Multi-state_Value,COV_Period,,O,TRUE, +Bacnet_Multi-state_Value,COV_Min_Send_Time,,O,TRUE, +Bacnet_Multi-state_Value,Time_Delay,,O,TRUE, +Bacnet_Multi-state_Value,Notification_Class,Unsigned,O,TRUE, +Bacnet_Multi-state_Value,Alarm_Values,,O,TRUE, +Bacnet_Multi-state_Value,Fault_Values,,O,TRUE, +Bacnet_Multi-state_Value,Event_Enable,BACnetEventTransitionBits,O,TRUE, +Bacnet_Multi-state_Value,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, +Bacnet_Multi-state_Value,Notify_Type,BACnetNotifyType,O,TRUE, +Bacnet_Multi-state_Value,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, +Bacnet_Multi-state_Value,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Multi-state_Value,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Multi-state_Value,Event_Detection_Enable,BOOLEAN,O,TRUE, +Bacnet_Multi-state_Value,Time_Delay_Normal,,O,TRUE, +Bacnet_Multi-state_Value,Event_Algorithm_Inhibit,,O,TRUE, +Bacnet_Multi-state_Value,Event_Algorithm_Inhibit_Ref,,O,TRUE, +Bacnet_Multi-state_Value,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, +Bacnet_Program,Object_Identifier,BACnetObjectIdentifier,O,TRUE, +Bacnet_Program,Object_Name,CharacterString,O,TRUE, +Bacnet_Program,Object_Type,BACnetObjectType,O,TRUE, +Bacnet_Program,Description,CharacterString,O,TRUE, +Bacnet_Program,Program_State,,O,TRUE, +Bacnet_Program,Program_Change,,O,TRUE, +Bacnet_Program,Description_Of_Halt,,O,TRUE, +Bacnet_Program,Reason_For_Halt,,O,TRUE, +Bacnet_Program,Status_Flags,BACnetStatusFlags,O,TRUE, +Bacnet_Program,Reliability,BACnetReliability,O,TRUE, +Bacnet_Program,Out_Of_Service,BOOLEAN,O,TRUE, +Bacnet_Program,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, +Bacnet_Notification,Object_Identifier,BACnetObjectIdentifier,O,TRUE, +Bacnet_Notification,Object_Name,CharacterString,O,TRUE, +Bacnet_Notification,Object_Type,BACnetObjectType,O,TRUE, +Bacnet_Notification,Description,CharacterString,O,TRUE, +Bacnet_Notification,Notification_Class,Unsigned,O,TRUE, +Bacnet_Notification,Priority,,O,TRUE, +Bacnet_Notification,Ack_Required,,O,TRUE, +Bacnet_Notification,Recipient_List,,O,TRUE, +Bacnet_Notification,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, +Bacnet_Schedule,Object_Identifier,BACnetObjectIdentifier,O,TRUE, +Bacnet_Schedule,Object_Name,CharacterString,O,TRUE, +Bacnet_Schedule,Object_Type,BACnetObjectType,O,TRUE, +Bacnet_Schedule,Description,CharacterString,O,TRUE, +Bacnet_Schedule,Present_Value,REAL,O,TRUE, +Bacnet_Schedule,Effective_Period,,O,TRUE, +Bacnet_Schedule,Weekly_Schedule,,O,TRUE, +Bacnet_Schedule,Exception_Schedule,,O,TRUE, +Bacnet_Schedule,Schedule_Default,,O,TRUE, +Bacnet_Schedule,List_Of_Object_Property_References,,O,TRUE, +Bacnet_Schedule,Priority_For_Writing,Unsigned(1..16),O,TRUE, +Bacnet_Schedule,Status_Flags,BACnetStatusFlags,O,TRUE, +Bacnet_Schedule,Reliability,BACnetReliability,O,TRUE, +Bacnet_Schedule,Out_Of_Service,BOOLEAN,O,TRUE, +Bacnet_Schedule,Time_To_Next_State,,O,TRUE, +Bacnet_Schedule,Next_State,,O,TRUE, +Bacnet_Schedule,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, +Bacnet_Trend_Log,Object_Identifier,BACnetObjectIdentifier,O,TRUE, +Bacnet_Trend_Log,Object_Name,CharacterString,O,TRUE, +Bacnet_Trend_Log,Object_Type,BACnetObjectType,O,TRUE, +Bacnet_Trend_Log,Description,CharacterString,O,TRUE, +Bacnet_Trend_Log,Enable,,O,TRUE, +Bacnet_Trend_Log,Start_Time,,O,TRUE, +Bacnet_Trend_Log,Stop_Time,,O,TRUE, +Bacnet_Trend_Log,Log_Device_Object_Property,,O,TRUE, +Bacnet_Trend_Log,Log_Interval,,O,TRUE, +Bacnet_Trend_Log,Cov_Resubscription_Interval,,O,TRUE, +Bacnet_Trend_Log,Client_Cov_Increment,,O,TRUE, +Bacnet_Trend_Log,Stop_When_Full,,O,TRUE, +Bacnet_Trend_Log,Buffer_Size,,O,TRUE, +Bacnet_Trend_Log,Log_Buffer,,O,TRUE, +Bacnet_Trend_Log,Record_Count,,O,TRUE, +Bacnet_Trend_Log,Total_Record_Count,,O,TRUE, +Bacnet_Trend_Log,Logging_Type,,O,TRUE, +Bacnet_Trend_Log,Align_Intervals,,O,TRUE, +Bacnet_Trend_Log,Interval_Offset,,O,TRUE, +Bacnet_Trend_Log,Trigger,,O,TRUE, +Bacnet_Trend_Log,Status_Flags,BACnetStatusFlags,O,TRUE, +Bacnet_Trend_Log,Reliability,BACnetReliability,O,TRUE, +Bacnet_Trend_Log,Notification_Threshold,,O,TRUE, +Bacnet_Trend_Log,Records_Since_Notification,,O,TRUE, +Bacnet_Trend_Log,Last_Notify_Record,,O,TRUE, +Bacnet_Trend_Log,Event_State,BACnetEventState,O,TRUE, +Bacnet_Trend_Log,Notification_Class,Unsigned,O,TRUE, +Bacnet_Trend_Log,Event_Enable,BACnetEventTransitionBits,O,TRUE, +Bacnet_Trend_Log,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, +Bacnet_Trend_Log,Notify_Type,BACnetNotifyType,O,TRUE, +Bacnet_Trend_Log,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, +Bacnet_Trend_Log,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Trend_Log,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Trend_Log,Event_Detection_Enable,BOOLEAN,O,TRUE, +Bacnet_Trend_Log,Event_Algorithm_Inhibit,,O,TRUE, +Bacnet_Trend_Log,Event_Algorithm_Inhibit_Ref,,O,TRUE, +Bacnet_Trend_Log,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,R,TRUE, \ No newline at end of file diff --git a/docker/include/bin/start_faux b/docker/include/bin/start_faux index bd1cb160a1..25b13a5f1d 100755 --- a/docker/include/bin/start_faux +++ b/docker/include/bin/start_faux @@ -137,11 +137,11 @@ fi if [ -n "${options[bacnet]}" ]; then echo Starting bacnet loop device. - java -cp bacnetTests/build/libs/bacnet-1.0-SNAPSHOT-all.jar \ + java -cp bacnetFaux/build/libs/bacnet-1.0-SNAPSHOT-all.jar \ FauxDeviceEngine.EntryPoint $local_ip $broadcast_ip "Faux-Device-Pass.json" & elif [ -n "${options[bacnetfail]}" ]; then echo Starting bacnet loop device. - java -cp bacnetTests/build/libs/bacnet-1.0-SNAPSHOT-all.jar \ + java -cp bacnetFaux/build/libs/bacnet-1.0-SNAPSHOT-all.jar \ FauxDeviceEngine.EntryPoint $local_ip $broadcast_ip "Faux-Device-Fail.json" & fi diff --git a/subset/pentests/brute_server.py b/docker/include/pentests/brute_server.py similarity index 100% rename from subset/pentests/brute_server.py rename to docker/include/pentests/brute_server.py diff --git a/subset/security/nginx-site/html/index.html b/docker/include/security/nginx-site/html/index.html similarity index 100% rename from subset/security/nginx-site/html/index.html rename to docker/include/security/nginx-site/html/index.html diff --git a/subset/security/nginxfail.conf b/docker/include/security/nginxfail.conf similarity index 100% rename from subset/security/nginxfail.conf rename to docker/include/security/nginxfail.conf diff --git a/subset/security/nginxpass.conf b/docker/include/security/nginxpass.conf similarity index 100% rename from subset/security/nginxpass.conf rename to docker/include/security/nginxpass.conf diff --git a/subset/security/sshfaux/ssh_build.sh b/docker/include/security/sshfaux/ssh_build.sh similarity index 100% rename from subset/security/sshfaux/ssh_build.sh rename to docker/include/security/sshfaux/ssh_build.sh diff --git a/subset/security/sshfaux/ssh_privsep.sh b/docker/include/security/sshfaux/ssh_privsep.sh similarity index 100% rename from subset/security/sshfaux/ssh_privsep.sh rename to docker/include/security/sshfaux/ssh_privsep.sh diff --git a/subset/security/tlsfaux/absolute_filepath.py b/docker/include/security/tlsfaux/absolute_filepath.py similarity index 100% rename from subset/security/tlsfaux/absolute_filepath.py rename to docker/include/security/tlsfaux/absolute_filepath.py diff --git a/subset/security/tlsfaux/certs/server.crt b/docker/include/security/tlsfaux/certs/server.crt similarity index 100% rename from subset/security/tlsfaux/certs/server.crt rename to docker/include/security/tlsfaux/certs/server.crt diff --git a/subset/security/tlsfaux/certs/server.csr b/docker/include/security/tlsfaux/certs/server.csr similarity index 100% rename from subset/security/tlsfaux/certs/server.csr rename to docker/include/security/tlsfaux/certs/server.csr diff --git a/subset/security/tlsfaux/certs/server.key b/docker/include/security/tlsfaux/certs/server.key similarity index 100% rename from subset/security/tlsfaux/certs/server.key rename to docker/include/security/tlsfaux/certs/server.key diff --git a/subset/security/tlsfaux/expcerts/server.crt b/docker/include/security/tlsfaux/expcerts/server.crt similarity index 100% rename from subset/security/tlsfaux/expcerts/server.crt rename to docker/include/security/tlsfaux/expcerts/server.crt diff --git a/subset/security/tlsfaux/expcerts/server.csr b/docker/include/security/tlsfaux/expcerts/server.csr similarity index 100% rename from subset/security/tlsfaux/expcerts/server.csr rename to docker/include/security/tlsfaux/expcerts/server.csr diff --git a/subset/security/tlsfaux/expcerts/server.key b/docker/include/security/tlsfaux/expcerts/server.key similarity index 100% rename from subset/security/tlsfaux/expcerts/server.key rename to docker/include/security/tlsfaux/expcerts/server.key diff --git a/subset/security/tlsfaux/generate_certs.py b/docker/include/security/tlsfaux/generate_certs.py similarity index 100% rename from subset/security/tlsfaux/generate_certs.py rename to docker/include/security/tlsfaux/generate_certs.py diff --git a/subset/security/tlsfaux/server.py b/docker/include/security/tlsfaux/server.py similarity index 100% rename from subset/security/tlsfaux/server.py rename to docker/include/security/tlsfaux/server.py diff --git a/docker/modules/Dockerfile.faux1 b/docker/modules/Dockerfile.faux1 index c6e76a865b..4dbb7e16a8 100644 --- a/docker/modules/Dockerfile.faux1 +++ b/docker/modules/Dockerfile.faux1 @@ -25,7 +25,7 @@ RUN $AG update && $AG install wget make build-essential gcc libz-dev ca-certific # Build SSH, OpenSSL from source and configure -COPY subset/security/sshfaux/*.sh ./ +COPY docker/include/security/sshfaux/*.sh ./ RUN sh ssh_build.sh FROM daqf/aardvark:latest @@ -54,25 +54,25 @@ COPY docker/include/bin/bacnet_discover bin/ COPY --from=java_build /root/pubber/build/libs/*.jar pubber/build/libs/ COPY udmi/pubber/bin/run pubber/bin/ -COPY subset/pentests/brute_server.py pentests/ -COPY subset/security/tlsfaux tlsfaux/ +COPY docker/include/pentests/brute_server.py pentests/ +COPY docker/include/security/tlsfaux tlsfaux/ -COPY subset/bacnet/bacnetTests/ bacnetTests -COPY subset/bacnet/bacnetTests/src/main/resources/Faux*.json tmp/ -COPY --from=java_build /root/bacnet4j/bacnet4j-1.0-SNAPSHOT-all.jar bacnetTests/libs/ -RUN cd bacnetTests && ./gradlew build +COPY docker/include/bacnet/bacnetFaux/ bacnetFaux +COPY docker/include/bacnet/bacnetFaux/src/main/resources/Faux*.json tmp/ +COPY --from=java_build /root/bacnet4j/bacnet4j-1.0-SNAPSHOT-all.jar bacnetFaux/libs/ +RUN cd bacnetFaux && ./gradlew build # HTTP/HTTPS dependency -COPY subset/security/nginxpass.conf /root/nginx/ -COPY subset/security/nginxfail.conf /root/nginx/ -COPY subset/security/nginx-site /var/www/nginx-site +COPY docker/include/security/nginxpass.conf /root/nginx/ +COPY docker/include/security/nginxfail.conf /root/nginx/ +COPY docker/include/security/nginx-site /var/www/nginx-site COPY --from=ssh_build /usr/local/openssl/* /usr/local/openssl/ COPY --from=ssh_build /usr/local/sbin/* /usr/local/sbin/ COPY --from=ssh_build /usr/local/bin/* /usr/local/bin/ COPY --from=ssh_build /usr/local/etc/* /usr/local/etc/ -COPY subset/security/sshfaux/ssh_privsep.sh ssh_privsep.sh +COPY docker/include/security/sshfaux/ssh_privsep.sh ssh_privsep.sh RUN sh ssh_privsep.sh RUN /usr/local/bin/ssh-keygen -A diff --git a/docker/modules/Dockerfile.faux2 b/docker/modules/Dockerfile.faux2 index 11ea5020bf..e179f0b9a7 100644 --- a/docker/modules/Dockerfile.faux2 +++ b/docker/modules/Dockerfile.faux2 @@ -26,9 +26,9 @@ COPY docker/include/bin/start_faux docker/include/bin/failing bin/ # Weird workaround for problem running tcdump in a privlidged container. RUN mv /usr/sbin/tcpdump /usr/bin/tcpdump -COPY subset/security/tlsfaux tlsfaux/ -COPY subset/security/nginxpass.conf /root/nginx/ -COPY subset/security/nginxfail.conf /root/nginx/ -COPY subset/security/nginx-site /var/www/nginx-site +COPY docker/include/security/tlsfaux tlsfaux/ +COPY docker/include/security/nginxpass.conf /root/nginx/ +COPY docker/include/security/nginxfail.conf /root/nginx/ +COPY docker/include/security/nginx-site /var/www/nginx-site ENTRYPOINT ["bin/start_faux"] diff --git a/subset/bacnet/bacnetTests/src/main/java/helper/FileManager.java b/subset/bacnet/bacnetTests/src/main/java/helper/FileManager.java index 20ac76297b..35ef1bc27c 100644 --- a/subset/bacnet/bacnetTests/src/main/java/helper/FileManager.java +++ b/subset/bacnet/bacnetTests/src/main/java/helper/FileManager.java @@ -4,61 +4,71 @@ public class FileManager { - private String filePath = ""; - private String csvName = "pics"; - private String csvExtension = ".csv"; - private boolean debug = false; + private String filePath = ""; + private String csvName = "pics"; + private String csvExtension = ".csv"; + private boolean debug = false; - public boolean checkDevicePicCSV() { - String csvFolder = getCSVPath(); - try{ - File[] listFiles = new File(csvFolder).listFiles(); - for (int i = 0; i < listFiles.length; i++) { - if (listFiles[i].isFile()) { - String fileName = listFiles[i].getName(); - if (fileName.contains(csvName) - && fileName.endsWith(csvExtension)) { - System.out.println("pics.csv file found in " + csvFolder); - setFilePath(fileName); - return true; - } - } - } - String errorMessage = "pics.csv not found.\n"; - System.err.println(errorMessage); - } catch(Exception e) { - System.out.println("Error in reading " + csvName + csvExtension + " in " + csvFolder); + /** + * Checks if pics.csv exists. + * @return if pics.csv exists + */ + public boolean checkDevicePicCSV() { + String csvFolder = getCSVPath(); + try { + File[] listFiles = new File(csvFolder).listFiles(); + for (int i = 0; i < listFiles.length; i++) { + if (listFiles[i].isFile()) { + String fileName = listFiles[i].getName(); + if (fileName.contains(csvName) + && fileName.endsWith(csvExtension)) { + System.out.println("pics.csv file found in " + csvFolder); + setFilePath(fileName); + return true; + } } - return false; + } + String errorMessage = "pics.csv not found.\n"; + System.err.println(errorMessage); + } catch (Exception e) { + System.out.println("Error in reading " + csvName + csvExtension + " in " + csvFolder); } + return false; + } - private void setFilePath(String fileName) { - String absolute_path = getCSVPath(); - this.filePath = absolute_path + "/" + fileName; - } + private void setFilePath(String fileName) { + String absolutePath = getCSVPath(); + this.filePath = absolutePath + "/" + fileName; + } - public String getFilePath() { - return this.filePath; - } + public String getFilePath() { + return this.filePath; + } - public String getAbsolutePath() { - String absolute_path = ""; - String system_path = System.getProperty("user.dir"); - System.out.println("system_path: " + system_path); - String[] path_arr = system_path.split("/"); - for (int count = 0; count < path_arr.length; count++) { - if (path_arr[count].equals("bacnetTests")) { - break; - } - absolute_path += path_arr[count] + "/"; - } - return absolute_path; + /** + * Returns absolute path to the working directory. + */ + public String getAbsolutePath() { + String absolutePath = ""; + String systemPath = System.getProperty("user.dir"); + System.out.println("system_path: " + systemPath); + String[] pathArr = systemPath.split("/"); + for (int count = 0; count < pathArr.length; count++) { + if (pathArr[count].equals("bacnetTests")) { + break; + } + absolutePath += pathArr[count] + "/"; } + return absolutePath; + } - public String getCSVPath() { - if (debug) { - return "src/main/resources"; - } - return "/config/type"; + /** + * Returns directory pics.csv is located within test container + */ + public String getCSVPath() { + if (debug) { + return "src/main/resources"; } + return "/config/type"; + } } diff --git a/subset/bacnet/bacnetTests/src/main/resources/pics.csv b/subset/bacnet/bacnetTests/src/main/resources/pics.csv index bedf7117dd..aab3985dec 100644 --- a/subset/bacnet/bacnetTests/src/main/resources/pics.csv +++ b/subset/bacnet/bacnetTests/src/main/resources/pics.csv @@ -1,486 +1,486 @@ -Bacnet_Object_Type,Bacnet_Object_Property,Property_Datatype,Conformance_Code,Supported, -Bacnet_Analogue_Input,Object_Identifier,BACnetObjectIdentifier,R,TRUE, -Bacnet_Analogue_Input,Object_Name,CharacterString,W,TRUE, -Bacnet_Analogue_Input,Object_Type,BACnetObjectType,R,TRUE, -Bacnet_Analogue_Input,Present_Value,REAL,R,TRUE, - ,Description,CharacterString,O,TRUE, -Bacnet_Analogue_Input,Device_Type,,O,TRUE, -Bacnet_Analogue_Input,Status_Flags,BACnetStatusFlags,R,TRUE, -Bacnet_Analogue_Input,Event_State,BACnetEventState,R,TRUE, -Bacnet_Analogue_Input,Reliability,BACnetReliability,O,TRUE, -Bacnet_Analogue_Input,Out_Of_Service,BOOLEAN,W,TRUE, -Bacnet_Analogue_Input,Update_Interval,,O,TRUE, -Bacnet_Analogue_Input,Units,,R,TRUE, -Bacnet_Analogue_Input,Min_Pres_Value,REAL,O,TRUE, -Bacnet_Analogue_Input,Max_Pres_Value,REAL,O,TRUE, -Bacnet_Analogue_Input,Resolution,,O,TRUE, -Bacnet_Analogue_Input,COV_Increment,REAL,O,TRUE, -Bacnet_Analogue_Input,COV_Period,,O,TRUE, -Bacnet_Analogue_Input,COV_Min_Send_Time,,O,TRUE, -Bacnet_Analogue_Input,Time_Delay,,O,TRUE, -Bacnet_Analogue_Input,Notification_Class,Unsigned,O,TRUE, -Bacnet_Analogue_Input,High_Limit,,O,TRUE, -Bacnet_Analogue_Input,Low_Limit,,O,TRUE, -Bacnet_Analogue_Input,Deadband,,O,TRUE, -Bacnet_Analogue_Input,Limit_Enable,,O,TRUE, -Bacnet_Analogue_Input,Event_Enable,BACnetEventTransitionBits,O,TRUE, -Bacnet_Analogue_Input,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, -Bacnet_Analogue_Input,Notify_Type,BACnetNotifyType,O,TRUE, -Bacnet_Analogue_Input,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, -Bacnet_Analogue_Input,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, -Bacnet_Analogue_Input,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, -Bacnet_Analogue_Input,Event_Detection_Enable,BOOLEAN,O,TRUE, -Bacnet_Analogue_Input,Time_Delay_Normal,,O,TRUE, -Bacnet_Analogue_Input,Event_Algorithm_Inhibit,,O,TRUE, -Bacnet_Analogue_Input,Event_Algorithm_Inhibit_Ref,,O,TRUE, -Bacnet_Analogue_Input,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,R,TRUE, -Bacnet_Analogue_Output,Object_Identifier,BACnetObjectIdentifier,R,TRUE, -Bacnet_Analogue_Output,Object_Name,CharacterString,W,TRUE, -Bacnet_Analogue_Output,Object_Type,BACnetObjectType,R,TRUE, -Bacnet_Analogue_Output,Present_Value,REAL,W,TRUE, -Bacnet_Analogue_Output,Description,CharacterString,O,TRUE, -Bacnet_Analogue_Output,Device_Type,,O,TRUE, -Bacnet_Analogue_Output,Status_Flags,BACnetStatusFlags,R,TRUE, -Bacnet_Analogue_Output,Event_State,BACnetEventState,R,TRUE, -Bacnet_Analogue_Output,Reliability,BACnetReliability,O,TRUE, -Bacnet_Analogue_Output,Out_Of_Service,BOOLEAN,W,TRUE, -Bacnet_Analogue_Output,Units,,R,TRUE, -Bacnet_Analogue_Output,Min_Present_Value,,O,TRUE, -Bacnet_Analogue_Output,Max_Present_Value,,O,TRUE, -Bacnet_Analogue_Output,Resolution,,O,TRUE, -Bacnet_Analogue_Output,Priority_Array,,R,TRUE, -Bacnet_Analogue_Output,Relinquish_Default,,W,TRUE, -Bacnet_Analogue_Output,COV_Increment,REAL,O,TRUE, -Bacnet_Analogue_Output,COV_Period,,O,TRUE, -Bacnet_Analogue_Output,COV_Min_Send_Time,,O,TRUE, -Bacnet_Analogue_Output,Time_Delay,,O,TRUE, -Bacnet_Analogue_Output,Notification_Class,Unsigned,O,TRUE, -Bacnet_Analogue_Output,High_Limit,,O,TRUE, -Bacnet_Analogue_Output,Low_Limit,,O,TRUE, -Bacnet_Analogue_Output,Deadband,,O,TRUE, -Bacnet_Analogue_Output,Limit_Enable,,O,TRUE, -Bacnet_Analogue_Output,Event_Enable,BACnetEventTransitionBits,O,TRUE, -Bacnet_Analogue_Output,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, -Bacnet_Analogue_Output,Notify_Type,BACnetNotifyType,O,TRUE, -Bacnet_Analogue_Output,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, -Bacnet_Analogue_Output,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, -Bacnet_Analogue_Output,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, -Bacnet_Analogue_Output,Event_Detection_Enable,BOOLEAN,O,TRUE, -Bacnet_Analogue_Output,Time_Delay_Normal,,O,TRUE, -Bacnet_Analogue_Output,Event_Algorithm_Inhibit,,O,TRUE, -Bacnet_Analogue_Output,Event_Algorithm_Inhibit_Ref,,O,TRUE, -Bacnet_Analogue_Output,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,R,TRUE, -Bacnet_Analogue_Value,Object_Identifier,BACnetObjectIdentifier,O,TRUE, -Bacnet_Analogue_Value,Object_Name,CharacterString,O,TRUE, -Bacnet_Analogue_Value,Object_Type,BACnetObjectType,O,TRUE, -Bacnet_Analogue_Value,Present_Value,REAL,O,TRUE, -Bacnet_Analogue_Value,Description,CharacterString,O,TRUE, -Bacnet_Analogue_Value,Status_Flags,BACnetStatusFlags,O,TRUE, -Bacnet_Analogue_Value,Event_State,BACnetEventState,O,TRUE, -Bacnet_Analogue_Value,Reliability,BACnetReliability,O,TRUE, -Bacnet_Analogue_Value,Out_Of_Service,BOOLEAN,O,TRUE, -Bacnet_Analogue_Value,Units,,O,TRUE, -Bacnet_Analogue_Value,Priority_Array,,O,TRUE, -Bacnet_Analogue_Value,Relinquish_Default,,O,TRUE, -Bacnet_Analogue_Value,Min_Present_Value,,O,TRUE, -Bacnet_Analogue_Value,Max_Present_Value,,O,TRUE, -Bacnet_Analogue_Value,COV_Increment,REAL,O,TRUE, -Bacnet_Analogue_Value,COV_Period,,O,TRUE, -Bacnet_Analogue_Value,COV_Min_Send_Time,,O,TRUE, -Bacnet_Analogue_Value,Time_Delay,,O,TRUE, -Bacnet_Analogue_Value,Notification_Class,Unsigned,O,TRUE, -Bacnet_Analogue_Value,High_Limit,,O,TRUE, -Bacnet_Analogue_Value,Low_Limit,,O,TRUE, -Bacnet_Analogue_Value,Deadband,,O,TRUE, -Bacnet_Analogue_Value,Limit_Enable,,O,TRUE, -Bacnet_Analogue_Value,Event_Enable,BACnetEventTransitionBits,O,TRUE, -Bacnet_Analogue_Value,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, -Bacnet_Analogue_Value,Notify_Type,BACnetNotifyType,O,TRUE, -Bacnet_Analogue_Value,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, -Bacnet_Analogue_Value,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, -Bacnet_Analogue_Value,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, -Bacnet_Analogue_Value,Event_Detection_Enable,BOOLEAN,O,TRUE, -Bacnet_Analogue_Value,Time_Delay_Normal,,O,TRUE, -Bacnet_Analogue_Value,Event_Algorithm_Inhibit,,O,TRUE, -Bacnet_Analogue_Value,Event_Algorithm_Inhibit_Ref,,O,TRUE, -Bacnet_Analogue_Value,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,R,TRUE, -Bacnet_Binary_Input,Object_Identifier,BACnetObjectIdentifier,R,TRUE, -Bacnet_Binary_Input,Object_Name,CharacterString,W,TRUE, -Bacnet_Binary_Input,Object_Type,BACnetObjectType,R,TRUE, -Bacnet_Binary_Input,Present_Value,REAL,R,TRUE, -Bacnet_Binary_Input,Description,CharacterString,O,TRUE, -Bacnet_Binary_Input,Device_Type,,O,TRUE, -Bacnet_Binary_Input,Status_Flags,BACnetStatusFlags,R,TRUE, -Bacnet_Binary_Input,Event_State,BACnetEventState,R,TRUE, -Bacnet_Binary_Input,Reliability,BACnetReliability,O,TRUE, -Bacnet_Binary_Input,Out_Of_Service,BOOLEAN,W,TRUE, -Bacnet_Binary_Input,Polarity,,R,TRUE, -Bacnet_Binary_Input,Inactive_Text,,O,TRUE, -Bacnet_Binary_Input,Active_Text,,O,TRUE, -Bacnet_Binary_Input,Change_Of_State_Time,,O,TRUE, -Bacnet_Binary_Input,Change_Of_State_Count,,O,TRUE, -Bacnet_Binary_Input,Time_Of_State_Count_Reset,,O,TRUE, -Bacnet_Binary_Input,Elapsed_Active_Time,,O,TRUE, -Bacnet_Binary_Input,Time_Of_Active_Time_Reset,,O,TRUE, -Bacnet_Binary_Input,COV_Period,,O,TRUE, -Bacnet_Binary_Input,COV_Min_Send_Time,,O,TRUE, -Bacnet_Binary_Input,Time_Delay,,O,TRUE, -Bacnet_Binary_Input,Notification_Class,Unsigned,O,TRUE, -Bacnet_Binary_Input,Alarm_Value,,O,TRUE, -Bacnet_Binary_Input,Event_Enable,BACnetEventTransitionBits,O,TRUE, -Bacnet_Binary_Input,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, -Bacnet_Binary_Input,Notify_Type,BACnetNotifyType,O,TRUE, -Bacnet_Binary_Input,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, -Bacnet_Binary_Input,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, -Bacnet_Binary_Input,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, -Bacnet_Binary_Input,Event_Detection_Enable,BOOLEAN,O,TRUE, -Bacnet_Binary_Input,Time_Delay_Normal,,O,TRUE, -Bacnet_Binary_Input,Event_Algorithm_Inhibit,,O,TRUE, -Bacnet_Binary_Input,Event_Algorithm_Inhibit_Ref,,O,TRUE, -Bacnet_Binary_Input,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,R,TRUE, -Bacnet_Binary_Output,Object_Identifier,BACnetObjectIdentifier,O,TRUE, -Bacnet_Binary_Output,Object_Name,CharacterString,O,TRUE, -Bacnet_Binary_Output,Object_Type,BACnetObjectType,O,TRUE, -Bacnet_Binary_Output,Present_Value,REAL,O,TRUE, -Bacnet_Binary_Output,Description,CharacterString,O,TRUE, -Bacnet_Binary_Output,Device_Type,,O,TRUE, -Bacnet_Binary_Output,Status_Flags,BACnetStatusFlags,O,TRUE, -Bacnet_Binary_Output,Event_State,BACnetEventState,O,TRUE, -Bacnet_Binary_Output,Reliability,BACnetReliability,O,TRUE, -Bacnet_Binary_Output,Out_Of_Service,BOOLEAN,O,TRUE, -Bacnet_Binary_Output,Polarity,,O,TRUE, -Bacnet_Binary_Output,Inactive_Text,,O,TRUE, -Bacnet_Binary_Output,Active_Text,,O,TRUE, -Bacnet_Binary_Output,Change_Of_State_Time,,O,TRUE, -Bacnet_Binary_Output,Change_Of_State_Count,,O,TRUE, -Bacnet_Binary_Output,Time_Of_State_Count_Reset,,O,TRUE, -Bacnet_Binary_Output,Elapsed_Active_Time,,O,TRUE, -Bacnet_Binary_Output,Time_Of_Active_Time_Reset,,O,TRUE, -Bacnet_Binary_Output,Minimum_Off_Time,,O,TRUE, -Bacnet_Binary_Output,Minimum_On_Time,,O,TRUE, -Bacnet_Binary_Output,Priority_Array,,O,TRUE, -Bacnet_Binary_Output,Relinquish_Default,,O,TRUE, -Bacnet_Binary_Output,COV_Period,,O,TRUE, -Bacnet_Binary_Output,COV_Min_Send_Time,,O,TRUE, -Bacnet_Binary_Output,Time_Delay,,O,TRUE, -Bacnet_Binary_Output,Notification_Class,Unsigned,O,TRUE, -Bacnet_Binary_Output,Feedback_Value,,O,TRUE, -Bacnet_Binary_Output,Event_Enable,BACnetEventTransitionBits,O,TRUE, -Bacnet_Binary_Output,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, -Bacnet_Binary_Output,Notify_Type,BACnetNotifyType,O,TRUE, -Bacnet_Binary_Output,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, -Bacnet_Binary_Output,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, -Bacnet_Binary_Output,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, -Bacnet_Binary_Output,Event_Detection_Enable,BOOLEAN,O,TRUE, -Bacnet_Binary_Output,Time_Delay_Normal,,O,TRUE, -Bacnet_Binary_Output,Event_Algorithm_Inhibit,,O,TRUE, -Bacnet_Binary_Output,Event_Algorithm_Inhibit_Ref,,O,TRUE, -Bacnet_Binary_Output,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, -Bacnet_Binary_Value,Object_Identifier,BACnetObjectIdentifier,O,TRUE, -Bacnet_Binary_Value,Object_Name,CharacterString,O,TRUE, -Bacnet_Binary_Value,Object_Type,BACnetObjectType,O,TRUE, -Bacnet_Binary_Value,Present_Value,REAL,O,TRUE, -Bacnet_Binary_Value,Description,CharacterString,O,TRUE, -Bacnet_Binary_Value,Status_Flags,BACnetStatusFlags,O,TRUE, -Bacnet_Binary_Value,Event_State,BACnetEventState,O,TRUE, -Bacnet_Binary_Value,Reliability,BACnetReliability,O,TRUE, -Bacnet_Binary_Value,Out_Of_Service,BOOLEAN,O,TRUE, -Bacnet_Binary_Value,Inactive_Text,,O,TRUE, -Bacnet_Binary_Value,Active_Text,,O,TRUE, -Bacnet_Binary_Value,Change_Of_State_Time,,O,TRUE, -Bacnet_Binary_Value,Change_Of_State_Count,,O,TRUE, -Bacnet_Binary_Value,Time_Of_State_Count_Reset,,O,TRUE, -Bacnet_Binary_Value,Elapsed_Active_Time,,O,TRUE, -Bacnet_Binary_Value,Time_Of_Active_Time_Reset,,O,TRUE, -Bacnet_Binary_Value,Minimum_Off_Time,,O,TRUE, -Bacnet_Binary_Value,Minimum_On_Time,,O,TRUE, -Bacnet_Binary_Value,Priority_Array,,O,TRUE, -Bacnet_Binary_Value,Relinquish_Default,,O,TRUE, -Bacnet_Binary_Value,COV_Period,,O,TRUE, -Bacnet_Binary_Value,COV_Min_Send_Time,,O,TRUE, -Bacnet_Binary_Value,Time_Delay,,O,TRUE, -Bacnet_Binary_Value,Notification_Class,Unsigned,O,TRUE, -Bacnet_Binary_Value,Alarm_Value,,O,TRUE, -Bacnet_Binary_Value,Event_Enable,BACnetEventTransitionBits,O,TRUE, -Bacnet_Binary_Value,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, -Bacnet_Binary_Value,Notify_Type,BACnetNotifyType,O,TRUE, -Bacnet_Binary_Value,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, -Bacnet_Binary_Value,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, -Bacnet_Binary_Value,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, -Bacnet_Binary_Value,Event_Detection_Enable,BOOLEAN,O,TRUE, -Bacnet_Binary_Value,Time_Delay_Normal,,O,TRUE, -Bacnet_Binary_Value,Event_Algorithm_Inhibit,,O,TRUE, -Bacnet_Binary_Value,Event_Algorithm_Inhibit_Ref,,O,TRUE, -Bacnet_Binary_Value,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, -Bacnet_Calendar,Object_Identifier,BACnetObjectIdentifier,O,TRUE, -Bacnet_Calendar,Object_Name,CharacterString,O,TRUE, -Bacnet_Calendar,Object_Type,BACnetObjectType,O,TRUE, -Bacnet_Calendar,Present_Value,REAL,O,TRUE, -Bacnet_Calendar,Description,CharacterString,O,TRUE, -Bacnet_Calendar,Date_List,,O,TRUE, -Bacnet_Calendar,Time_To_Next_State,,O,TRUE, -Bacnet_Calendar,Next_State,,O,TRUE, -Bacnet_Calendar,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, -Device,Object_Identifier,BACnetObjectIdentifier,W,TRUE, -Device,Object_Name,CharacterString,W,TRUE, -Device,Object_Type,BACnetObjectType,R,TRUE, -Device,System_Status,,R,TRUE, -Device,Vendor_Name,,R,TRUE, -Device,Vendor_Identifier,,R,TRUE, -Device,Model_Name,,R,TRUE, -Device,Firmware_Revision,,R,TRUE, -Device,Application_Software_Version,,R,TRUE, -Device,Location,,O,TRUE, -Device,Description,CharacterString,O,TRUE, -Device,Protocol_Version,,R,TRUE, -Device,Protocol_Revision,,R,TRUE, -Device,Protocol_Services_Supported,,R,TRUE, -Device,Protocol_Object_Types_Supported,,R,TRUE, -Device,Object_List,,R,TRUE, -Device,Max_APDU_Length_Accepted,,R,TRUE, -Device,Segmentation_Supported,,R,TRUE, -Device,Max_Segments_Accepted,,O,TRUE, -Device,Local_Date,,O,TRUE, -Device,Local_Time,,O,TRUE, -Device,UTC_Offset,,O,TRUE, -Device,Daylight_Savings_Status,,O,TRUE, -Device,Apdu_Segment_Timeout,,O,TRUE, -Device,APDU_Timeout,,W,TRUE, -Device,Number_Of_APDU_Retries,,W,TRUE, -Device,Time_Synchronization_Recipients,,O,TRUE, -Device,Device_Address_Binding,,R,TRUE, -Device,Database_Revision,,R,TRUE, -Device,Configuration_Files,,O,TRUE, -Device,Last_Restore_Time,,O,TRUE, -Device,Backup_Failure_Timeout,,O,TRUE, -Device,Backup_Preparation_Time,,O,TRUE, -Device,Restore_Preparation_Time,,O,TRUE, -Device,Restore_Completion_Time,,O,TRUE, -Device,Backup_And_Restore_State,,O,TRUE, -Device,Active_COV_Subscriptions,,O,TRUE, -Device,Last_Restart_Reason,,O,TRUE, -Device,Time_Of_Device_Restart,,O,TRUE, -Device,Restart_Notification_Recipients,,O,TRUE, -Device,Utc_Time_Synchronization_Recipients,,O,TRUE, -Device,Max_Master,,O,TRUE, -Device,Max_Info_Frames,,O,TRUE, -Device,Time_Synchronization_Interval,,O,TRUE, -Device,Align_Intervals,,O,TRUE, -Device,Interval_Offset,,O,TRUE, -Device,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,R,TRUE, -Event_Enrollment,Object_Identifier,BACnetObjectIdentifier,O,TRUE, -Event_Enrollment,Object_Name,CharacterString,O,TRUE, -Event_Enrollment,Object_Type,BACnetObjectType,O,TRUE, -Event_Enrollment,Description,CharacterString,O,TRUE, -Event_Enrollment,Event_Type,,O,TRUE, -Event_Enrollment,Notify_Type,BACnetNotifyType,O,TRUE, -Event_Enrollment,Event_Parameters,,O,TRUE, -Event_Enrollment,Object_Property_Reference,,O,TRUE, -Event_Enrollment,Event_State,BACnetEventState,O,TRUE, -Event_Enrollment,Event_Enable,BACnetEventTransitionBits,O,TRUE, -Event_Enrollment,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, -Event_Enrollment,Notification_Class,Unsigned,O,TRUE, -Event_Enrollment,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, -Event_Enrollment,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, -Event_Enrollment,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, -Event_Enrollment,Event_Detection_Enable,BOOLEAN,O,TRUE, -Event_Enrollment,Time_Delay_Normal,,O,TRUE, -Event_Enrollment,Status_Flags,BACnetStatusFlags,O,TRUE, -Event_Enrollment,Reliability,BACnetReliability,O,TRUE, -Event_Enrollment,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, -Bacnet_File,Object_Identifier,BACnetObjectIdentifier,O,TRUE, -Bacnet_File,Object_Name,CharacterString,O,TRUE, -Bacnet_File,Object_Type,BACnetObjectType,O,TRUE, -Bacnet_File,Description,CharacterString,O,TRUE, -Bacnet_File,File_Type,,O,TRUE, -Bacnet_File,File_Size,,O,TRUE, -Bacnet_File,Modification_Date,,O,TRUE, -Bacnet_File,Archive,,O,TRUE, -Bacnet_File,Read_Only,,O,TRUE, -Bacnet_File,File_Access_Method,,O,TRUE, -Bacnet_File,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, -Bacnet_Loop,Object_Identifier,BACnetObjectIdentifier,O,TRUE, -Bacnet_Loop,Object_Name,CharacterString,O,TRUE, -Bacnet_Loop,Object_Type,BACnetObjectType,O,TRUE, -Bacnet_Loop,Present_Value,REAL,O,TRUE, -Bacnet_Loop,Description,CharacterString,O,TRUE, -Bacnet_Loop,Status_Flags,BACnetStatusFlags,O,TRUE, -Bacnet_Loop,Event_State,BACnetEventState,O,TRUE, -Bacnet_Loop,Reliability,BACnetReliability,O,TRUE, -Bacnet_Loop,Out_Of_Service,BOOLEAN,O,TRUE, -Bacnet_Loop,Update_Interval,,O,TRUE, -Bacnet_Loop,Output_Units,,O,TRUE, -Bacnet_Loop,Manipulated_Variable_Reference,,O,TRUE, -Bacnet_Loop,Controlled_Variable_Reference,,O,TRUE, -Bacnet_Loop,Controlled_Variable_Value,,O,TRUE, -Bacnet_Loop,Controlled_Variable_Units,,O,TRUE, -Bacnet_Loop,Setpoint_Reference,,O,TRUE, -Bacnet_Loop,Setpoint,,O,TRUE, -Bacnet_Loop,Action,,O,TRUE, -Bacnet_Loop,Proportional_Constant,,O,TRUE, -Bacnet_Loop,Proportional_Constant_Units,,O,TRUE, -Bacnet_Loop,Integral_Constant,,O,TRUE, -Bacnet_Loop,Integral_Constant_Units,,O,TRUE, -Bacnet_Loop,Derivative_Constant,,O,TRUE, -Bacnet_Loop,Derivative_Constant_Units,,O,TRUE, -Bacnet_Loop,Bias,,O,TRUE, -Bacnet_Loop,Maximum_Output,,O,TRUE, -Bacnet_Loop,Minimum_Output,,O,TRUE, -Bacnet_Loop,Priority_For_Writing,Unsigned(1..16),O,TRUE, -Bacnet_Loop,LoopDeadband,,O,TRUE, -Bacnet_Loop,Saturation_Time,,O,TRUE, -Bacnet_Loop,COV_Increment,REAL,O,TRUE, -Bacnet_Loop,COV_Period,,O,TRUE, -Bacnet_Loop,COV_Min_Send_Time,,O,TRUE, -Bacnet_Loop,Ramp_Time,,O,TRUE, -Bacnet_Loop,Saturation_Time_Low_Limit_Enable,,O,TRUE, -Bacnet_Loop,Saturation_Time_High_Limit_Enable,,O,TRUE, -Bacnet_Loop,Time_Delay,,O,TRUE, -Bacnet_Loop,Notification_Class,Unsigned,O,TRUE, -Bacnet_Loop,Error_Limit,,O,TRUE, -Bacnet_Loop,Deadband,,O,TRUE, -Bacnet_Loop,Event_Enable,BACnetEventTransitionBits,O,TRUE, -Bacnet_Loop,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, -Bacnet_Loop,Notify_Type,BACnetNotifyType,O,TRUE, -Bacnet_Loop,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, -Bacnet_Loop,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, -Bacnet_Loop,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, -Bacnet_Loop,Event_Detection_Enable,BOOLEAN,O,TRUE, -Bacnet_Loop,Time_Delay_Normal,,O,TRUE, -Bacnet_Loop,Event_Algorithm_Inhibit,,O,TRUE, -Bacnet_Loop,Event_Algorithm_Inhibit_Ref,,O,TRUE, -Bacnet_Loop,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, -Bacnet_Multi-state_Input,Object_Identifier,BACnetObjectIdentifier,O,TRUE, -Bacnet_Multi-state_Input,Object_Name,CharacterString,O,TRUE, -Bacnet_Multi-state_Input,Object_Type,BACnetObjectType,O,TRUE, -Bacnet_Multi-state_Input,Present_Value,REAL,O,TRUE, -Bacnet_Multi-state_Input,Description,CharacterString,O,TRUE, -Bacnet_Multi-state_Input,Device_Type,,O,TRUE, -Bacnet_Multi-state_Input,Status_Flags,BACnetStatusFlags,O,TRUE, -Bacnet_Multi-state_Input,Event_State,BACnetEventState,O,TRUE, -Bacnet_Multi-state_Input,Reliability,BACnetReliability,O,TRUE, -Bacnet_Multi-state_Input,Out_Of_Service,BOOLEAN,O,TRUE, -Bacnet_Multi-state_Input,Number_of_States,,O,TRUE, -Bacnet_Multi-state_Input,State_Text,,O,TRUE, -Bacnet_Multi-state_Input,COV_Period,,O,TRUE, -Bacnet_Multi-state_Input,COV_Min_Send_Time,,O,TRUE, -Bacnet_Multi-state_Input,Time_Delay,,O,TRUE, -Bacnet_Multi-state_Input,Notification_Class,Unsigned,O,TRUE, -Bacnet_Multi-state_Input,Alarm_Values,,O,TRUE, -Bacnet_Multi-state_Input,Fault_Values,,O,TRUE, -Bacnet_Multi-state_Input,Event_Enable,BACnetEventTransitionBits,O,TRUE, -Bacnet_Multi-state_Input,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, -Bacnet_Multi-state_Input,Notify_Type,BACnetNotifyType,O,TRUE, -Bacnet_Multi-state_Input,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, -Bacnet_Multi-state_Input,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, -Bacnet_Multi-state_Input,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, -Bacnet_Multi-state_Input,Event_Detection_Enable,BOOLEAN,O,TRUE, -Bacnet_Multi-state_Input,Time_Delay_Normal,,O,TRUE, -Bacnet_Multi-state_Input,Event_Algorithm_Inhibit,,O,TRUE, -Bacnet_Multi-state_Input,Event_Algorithm_Inhibit_Ref,,O,TRUE, -Bacnet_Multi-state_Input,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, -Bacnet_Multi-state_Value,Object_Identifier,BACnetObjectIdentifier,O,TRUE, -Bacnet_Multi-state_Value,Object_Name,CharacterString,O,TRUE, -Bacnet_Multi-state_Value,Object_Type,BACnetObjectType,O,TRUE, -Bacnet_Multi-state_Value,Present_Value,REAL,O,TRUE, -Bacnet_Multi-state_Value,Description,CharacterString,O,TRUE, -Bacnet_Multi-state_Value,Status_Flags,BACnetStatusFlags,O,TRUE, -Bacnet_Multi-state_Value,Event_State,BACnetEventState,O,TRUE, -Bacnet_Multi-state_Value,Reliability,BACnetReliability,O,TRUE, -Bacnet_Multi-state_Value,Out_Of_Service,BOOLEAN,O,TRUE, -Bacnet_Multi-state_Value,Number_of_States,,O,TRUE, -Bacnet_Multi-state_Value,State_Text,,O,TRUE, -Bacnet_Multi-state_Value,Priority_Array,,O,TRUE, -Bacnet_Multi-state_Value,Relinquish_Default,,O,TRUE, -Bacnet_Multi-state_Value,COV_Period,,O,TRUE, -Bacnet_Multi-state_Value,COV_Min_Send_Time,,O,TRUE, -Bacnet_Multi-state_Value,Time_Delay,,O,TRUE, -Bacnet_Multi-state_Value,Notification_Class,Unsigned,O,TRUE, -Bacnet_Multi-state_Value,Alarm_Values,,O,TRUE, -Bacnet_Multi-state_Value,Fault_Values,,O,TRUE, -Bacnet_Multi-state_Value,Event_Enable,BACnetEventTransitionBits,O,TRUE, -Bacnet_Multi-state_Value,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, -Bacnet_Multi-state_Value,Notify_Type,BACnetNotifyType,O,TRUE, -Bacnet_Multi-state_Value,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, -Bacnet_Multi-state_Value,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, -Bacnet_Multi-state_Value,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, -Bacnet_Multi-state_Value,Event_Detection_Enable,BOOLEAN,O,TRUE, -Bacnet_Multi-state_Value,Time_Delay_Normal,,O,TRUE, -Bacnet_Multi-state_Value,Event_Algorithm_Inhibit,,O,TRUE, -Bacnet_Multi-state_Value,Event_Algorithm_Inhibit_Ref,,O,TRUE, -Bacnet_Multi-state_Value,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, -Bacnet_Program,Object_Identifier,BACnetObjectIdentifier,O,TRUE, -Bacnet_Program,Object_Name,CharacterString,O,TRUE, -Bacnet_Program,Object_Type,BACnetObjectType,O,TRUE, -Bacnet_Program,Description,CharacterString,O,TRUE, -Bacnet_Program,Program_State,,O,TRUE, -Bacnet_Program,Program_Change,,O,TRUE, -Bacnet_Program,Description_Of_Halt,,O,TRUE, -Bacnet_Program,Reason_For_Halt,,O,TRUE, -Bacnet_Program,Status_Flags,BACnetStatusFlags,O,TRUE, -Bacnet_Program,Reliability,BACnetReliability,O,TRUE, -Bacnet_Program,Out_Of_Service,BOOLEAN,O,TRUE, -Bacnet_Program,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, -Bacnet_Notification,Object_Identifier,BACnetObjectIdentifier,O,TRUE, -Bacnet_Notification,Object_Name,CharacterString,O,TRUE, -Bacnet_Notification,Object_Type,BACnetObjectType,O,TRUE, -Bacnet_Notification,Description,CharacterString,O,TRUE, -Bacnet_Notification,Notification_Class,Unsigned,O,TRUE, -Bacnet_Notification,Priority,,O,TRUE, -Bacnet_Notification,Ack_Required,,O,TRUE, -Bacnet_Notification,Recipient_List,,O,TRUE, -Bacnet_Notification,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, -Bacnet_Schedule,Object_Identifier,BACnetObjectIdentifier,O,TRUE, -Bacnet_Schedule,Object_Name,CharacterString,O,TRUE, -Bacnet_Schedule,Object_Type,BACnetObjectType,O,TRUE, -Bacnet_Schedule,Description,CharacterString,O,TRUE, -Bacnet_Schedule,Present_Value,REAL,O,TRUE, -Bacnet_Schedule,Effective_Period,,O,TRUE, -Bacnet_Schedule,Weekly_Schedule,,O,TRUE, -Bacnet_Schedule,Exception_Schedule,,O,TRUE, -Bacnet_Schedule,Schedule_Default,,O,TRUE, -Bacnet_Schedule,List_Of_Object_Property_References,,O,TRUE, -Bacnet_Schedule,Priority_For_Writing,Unsigned(1..16),O,TRUE, -Bacnet_Schedule,Status_Flags,BACnetStatusFlags,O,TRUE, -Bacnet_Schedule,Reliability,BACnetReliability,O,TRUE, -Bacnet_Schedule,Out_Of_Service,BOOLEAN,O,TRUE, -Bacnet_Schedule,Time_To_Next_State,,O,TRUE, -Bacnet_Schedule,Next_State,,O,TRUE, -Bacnet_Schedule,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, -Bacnet_Trend_Log,Object_Identifier,BACnetObjectIdentifier,O,TRUE, -Bacnet_Trend_Log,Object_Name,CharacterString,O,TRUE, -Bacnet_Trend_Log,Object_Type,BACnetObjectType,O,TRUE, -Bacnet_Trend_Log,Description,CharacterString,O,TRUE, -Bacnet_Trend_Log,Enable,,O,TRUE, -Bacnet_Trend_Log,Start_Time,,O,TRUE, -Bacnet_Trend_Log,Stop_Time,,O,TRUE, -Bacnet_Trend_Log,Log_Device_Object_Property,,O,TRUE, -Bacnet_Trend_Log,Log_Interval,,O,TRUE, -Bacnet_Trend_Log,Cov_Resubscription_Interval,,O,TRUE, -Bacnet_Trend_Log,Client_Cov_Increment,,O,TRUE, -Bacnet_Trend_Log,Stop_When_Full,,O,TRUE, -Bacnet_Trend_Log,Buffer_Size,,O,TRUE, -Bacnet_Trend_Log,Log_Buffer,,O,TRUE, -Bacnet_Trend_Log,Record_Count,,O,TRUE, -Bacnet_Trend_Log,Total_Record_Count,,O,TRUE, -Bacnet_Trend_Log,Logging_Type,,O,TRUE, -Bacnet_Trend_Log,Align_Intervals,,O,TRUE, -Bacnet_Trend_Log,Interval_Offset,,O,TRUE, -Bacnet_Trend_Log,Trigger,,O,TRUE, -Bacnet_Trend_Log,Status_Flags,BACnetStatusFlags,O,TRUE, -Bacnet_Trend_Log,Reliability,BACnetReliability,O,TRUE, -Bacnet_Trend_Log,Notification_Threshold,,O,TRUE, -Bacnet_Trend_Log,Records_Since_Notification,,O,TRUE, -Bacnet_Trend_Log,Last_Notify_Record,,O,TRUE, -Bacnet_Trend_Log,Event_State,BACnetEventState,O,TRUE, -Bacnet_Trend_Log,Notification_Class,Unsigned,O,TRUE, -Bacnet_Trend_Log,Event_Enable,BACnetEventTransitionBits,O,TRUE, -Bacnet_Trend_Log,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, -Bacnet_Trend_Log,Notify_Type,BACnetNotifyType,O,TRUE, -Bacnet_Trend_Log,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, -Bacnet_Trend_Log,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, -Bacnet_Trend_Log,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, -Bacnet_Trend_Log,Event_Detection_Enable,BOOLEAN,O,TRUE, -Bacnet_Trend_Log,Event_Algorithm_Inhibit,,O,TRUE, -Bacnet_Trend_Log,Event_Algorithm_Inhibit_Ref,,O,TRUE, +Bacnet_Object_Type,Bacnet_Object_Property,Property_Datatype,Conformance_Code,Supported, +Bacnet_Analogue_Input,Object_Identifier,BACnetObjectIdentifier,R,TRUE, +Bacnet_Analogue_Input,Object_Name,CharacterString,W,TRUE, +Bacnet_Analogue_Input,Object_Type,BACnetObjectType,R,TRUE, +Bacnet_Analogue_Input,Present_Value,REAL,R,TRUE, + ,Description,CharacterString,O,TRUE, +Bacnet_Analogue_Input,Device_Type,,O,TRUE, +Bacnet_Analogue_Input,Status_Flags,BACnetStatusFlags,R,TRUE, +Bacnet_Analogue_Input,Event_State,BACnetEventState,R,TRUE, +Bacnet_Analogue_Input,Reliability,BACnetReliability,O,TRUE, +Bacnet_Analogue_Input,Out_Of_Service,BOOLEAN,W,TRUE, +Bacnet_Analogue_Input,Update_Interval,,O,TRUE, +Bacnet_Analogue_Input,Units,,R,TRUE, +Bacnet_Analogue_Input,Min_Pres_Value,REAL,O,TRUE, +Bacnet_Analogue_Input,Max_Pres_Value,REAL,O,TRUE, +Bacnet_Analogue_Input,Resolution,,O,TRUE, +Bacnet_Analogue_Input,COV_Increment,REAL,O,TRUE, +Bacnet_Analogue_Input,COV_Period,,O,TRUE, +Bacnet_Analogue_Input,COV_Min_Send_Time,,O,TRUE, +Bacnet_Analogue_Input,Time_Delay,,O,TRUE, +Bacnet_Analogue_Input,Notification_Class,Unsigned,O,TRUE, +Bacnet_Analogue_Input,High_Limit,,O,TRUE, +Bacnet_Analogue_Input,Low_Limit,,O,TRUE, +Bacnet_Analogue_Input,Deadband,,O,TRUE, +Bacnet_Analogue_Input,Limit_Enable,,O,TRUE, +Bacnet_Analogue_Input,Event_Enable,BACnetEventTransitionBits,O,TRUE, +Bacnet_Analogue_Input,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, +Bacnet_Analogue_Input,Notify_Type,BACnetNotifyType,O,TRUE, +Bacnet_Analogue_Input,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, +Bacnet_Analogue_Input,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Analogue_Input,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Analogue_Input,Event_Detection_Enable,BOOLEAN,O,TRUE, +Bacnet_Analogue_Input,Time_Delay_Normal,,O,TRUE, +Bacnet_Analogue_Input,Event_Algorithm_Inhibit,,O,TRUE, +Bacnet_Analogue_Input,Event_Algorithm_Inhibit_Ref,,O,TRUE, +Bacnet_Analogue_Input,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,R,TRUE, +Bacnet_Analogue_Output,Object_Identifier,BACnetObjectIdentifier,R,TRUE, +Bacnet_Analogue_Output,Object_Name,CharacterString,W,TRUE, +Bacnet_Analogue_Output,Object_Type,BACnetObjectType,R,TRUE, +Bacnet_Analogue_Output,Present_Value,REAL,W,TRUE, +Bacnet_Analogue_Output,Description,CharacterString,O,TRUE, +Bacnet_Analogue_Output,Device_Type,,O,TRUE, +Bacnet_Analogue_Output,Status_Flags,BACnetStatusFlags,R,TRUE, +Bacnet_Analogue_Output,Event_State,BACnetEventState,R,TRUE, +Bacnet_Analogue_Output,Reliability,BACnetReliability,O,TRUE, +Bacnet_Analogue_Output,Out_Of_Service,BOOLEAN,W,TRUE, +Bacnet_Analogue_Output,Units,,R,TRUE, +Bacnet_Analogue_Output,Min_Present_Value,,O,TRUE, +Bacnet_Analogue_Output,Max_Present_Value,,O,TRUE, +Bacnet_Analogue_Output,Resolution,,O,TRUE, +Bacnet_Analogue_Output,Priority_Array,,R,TRUE, +Bacnet_Analogue_Output,Relinquish_Default,,W,TRUE, +Bacnet_Analogue_Output,COV_Increment,REAL,O,TRUE, +Bacnet_Analogue_Output,COV_Period,,O,TRUE, +Bacnet_Analogue_Output,COV_Min_Send_Time,,O,TRUE, +Bacnet_Analogue_Output,Time_Delay,,O,TRUE, +Bacnet_Analogue_Output,Notification_Class,Unsigned,O,TRUE, +Bacnet_Analogue_Output,High_Limit,,O,TRUE, +Bacnet_Analogue_Output,Low_Limit,,O,TRUE, +Bacnet_Analogue_Output,Deadband,,O,TRUE, +Bacnet_Analogue_Output,Limit_Enable,,O,TRUE, +Bacnet_Analogue_Output,Event_Enable,BACnetEventTransitionBits,O,TRUE, +Bacnet_Analogue_Output,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, +Bacnet_Analogue_Output,Notify_Type,BACnetNotifyType,O,TRUE, +Bacnet_Analogue_Output,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, +Bacnet_Analogue_Output,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Analogue_Output,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Analogue_Output,Event_Detection_Enable,BOOLEAN,O,TRUE, +Bacnet_Analogue_Output,Time_Delay_Normal,,O,TRUE, +Bacnet_Analogue_Output,Event_Algorithm_Inhibit,,O,TRUE, +Bacnet_Analogue_Output,Event_Algorithm_Inhibit_Ref,,O,TRUE, +Bacnet_Analogue_Output,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,R,TRUE, +Bacnet_Analogue_Value,Object_Identifier,BACnetObjectIdentifier,O,TRUE, +Bacnet_Analogue_Value,Object_Name,CharacterString,O,TRUE, +Bacnet_Analogue_Value,Object_Type,BACnetObjectType,O,TRUE, +Bacnet_Analogue_Value,Present_Value,REAL,O,TRUE, +Bacnet_Analogue_Value,Description,CharacterString,O,TRUE, +Bacnet_Analogue_Value,Status_Flags,BACnetStatusFlags,O,TRUE, +Bacnet_Analogue_Value,Event_State,BACnetEventState,O,TRUE, +Bacnet_Analogue_Value,Reliability,BACnetReliability,O,TRUE, +Bacnet_Analogue_Value,Out_Of_Service,BOOLEAN,O,TRUE, +Bacnet_Analogue_Value,Units,,O,TRUE, +Bacnet_Analogue_Value,Priority_Array,,O,TRUE, +Bacnet_Analogue_Value,Relinquish_Default,,O,TRUE, +Bacnet_Analogue_Value,Min_Present_Value,,O,TRUE, +Bacnet_Analogue_Value,Max_Present_Value,,O,TRUE, +Bacnet_Analogue_Value,COV_Increment,REAL,O,TRUE, +Bacnet_Analogue_Value,COV_Period,,O,TRUE, +Bacnet_Analogue_Value,COV_Min_Send_Time,,O,TRUE, +Bacnet_Analogue_Value,Time_Delay,,O,TRUE, +Bacnet_Analogue_Value,Notification_Class,Unsigned,O,TRUE, +Bacnet_Analogue_Value,High_Limit,,O,TRUE, +Bacnet_Analogue_Value,Low_Limit,,O,TRUE, +Bacnet_Analogue_Value,Deadband,,O,TRUE, +Bacnet_Analogue_Value,Limit_Enable,,O,TRUE, +Bacnet_Analogue_Value,Event_Enable,BACnetEventTransitionBits,O,TRUE, +Bacnet_Analogue_Value,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, +Bacnet_Analogue_Value,Notify_Type,BACnetNotifyType,O,TRUE, +Bacnet_Analogue_Value,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, +Bacnet_Analogue_Value,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Analogue_Value,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Analogue_Value,Event_Detection_Enable,BOOLEAN,O,TRUE, +Bacnet_Analogue_Value,Time_Delay_Normal,,O,TRUE, +Bacnet_Analogue_Value,Event_Algorithm_Inhibit,,O,TRUE, +Bacnet_Analogue_Value,Event_Algorithm_Inhibit_Ref,,O,TRUE, +Bacnet_Analogue_Value,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,R,TRUE, +Bacnet_Binary_Input,Object_Identifier,BACnetObjectIdentifier,R,TRUE, +Bacnet_Binary_Input,Object_Name,CharacterString,W,TRUE, +Bacnet_Binary_Input,Object_Type,BACnetObjectType,R,TRUE, +Bacnet_Binary_Input,Present_Value,REAL,R,TRUE, +Bacnet_Binary_Input,Description,CharacterString,O,TRUE, +Bacnet_Binary_Input,Device_Type,,O,TRUE, +Bacnet_Binary_Input,Status_Flags,BACnetStatusFlags,R,TRUE, +Bacnet_Binary_Input,Event_State,BACnetEventState,R,TRUE, +Bacnet_Binary_Input,Reliability,BACnetReliability,O,TRUE, +Bacnet_Binary_Input,Out_Of_Service,BOOLEAN,W,TRUE, +Bacnet_Binary_Input,Polarity,,R,TRUE, +Bacnet_Binary_Input,Inactive_Text,,O,TRUE, +Bacnet_Binary_Input,Active_Text,,O,TRUE, +Bacnet_Binary_Input,Change_Of_State_Time,,O,TRUE, +Bacnet_Binary_Input,Change_Of_State_Count,,O,TRUE, +Bacnet_Binary_Input,Time_Of_State_Count_Reset,,O,TRUE, +Bacnet_Binary_Input,Elapsed_Active_Time,,O,TRUE, +Bacnet_Binary_Input,Time_Of_Active_Time_Reset,,O,TRUE, +Bacnet_Binary_Input,COV_Period,,O,TRUE, +Bacnet_Binary_Input,COV_Min_Send_Time,,O,TRUE, +Bacnet_Binary_Input,Time_Delay,,O,TRUE, +Bacnet_Binary_Input,Notification_Class,Unsigned,O,TRUE, +Bacnet_Binary_Input,Alarm_Value,,O,TRUE, +Bacnet_Binary_Input,Event_Enable,BACnetEventTransitionBits,O,TRUE, +Bacnet_Binary_Input,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, +Bacnet_Binary_Input,Notify_Type,BACnetNotifyType,O,TRUE, +Bacnet_Binary_Input,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, +Bacnet_Binary_Input,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Binary_Input,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Binary_Input,Event_Detection_Enable,BOOLEAN,O,TRUE, +Bacnet_Binary_Input,Time_Delay_Normal,,O,TRUE, +Bacnet_Binary_Input,Event_Algorithm_Inhibit,,O,TRUE, +Bacnet_Binary_Input,Event_Algorithm_Inhibit_Ref,,O,TRUE, +Bacnet_Binary_Input,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,R,TRUE, +Bacnet_Binary_Output,Object_Identifier,BACnetObjectIdentifier,O,TRUE, +Bacnet_Binary_Output,Object_Name,CharacterString,O,TRUE, +Bacnet_Binary_Output,Object_Type,BACnetObjectType,O,TRUE, +Bacnet_Binary_Output,Present_Value,REAL,O,TRUE, +Bacnet_Binary_Output,Description,CharacterString,O,TRUE, +Bacnet_Binary_Output,Device_Type,,O,TRUE, +Bacnet_Binary_Output,Status_Flags,BACnetStatusFlags,O,TRUE, +Bacnet_Binary_Output,Event_State,BACnetEventState,O,TRUE, +Bacnet_Binary_Output,Reliability,BACnetReliability,O,TRUE, +Bacnet_Binary_Output,Out_Of_Service,BOOLEAN,O,TRUE, +Bacnet_Binary_Output,Polarity,,O,TRUE, +Bacnet_Binary_Output,Inactive_Text,,O,TRUE, +Bacnet_Binary_Output,Active_Text,,O,TRUE, +Bacnet_Binary_Output,Change_Of_State_Time,,O,TRUE, +Bacnet_Binary_Output,Change_Of_State_Count,,O,TRUE, +Bacnet_Binary_Output,Time_Of_State_Count_Reset,,O,TRUE, +Bacnet_Binary_Output,Elapsed_Active_Time,,O,TRUE, +Bacnet_Binary_Output,Time_Of_Active_Time_Reset,,O,TRUE, +Bacnet_Binary_Output,Minimum_Off_Time,,O,TRUE, +Bacnet_Binary_Output,Minimum_On_Time,,O,TRUE, +Bacnet_Binary_Output,Priority_Array,,O,TRUE, +Bacnet_Binary_Output,Relinquish_Default,,O,TRUE, +Bacnet_Binary_Output,COV_Period,,O,TRUE, +Bacnet_Binary_Output,COV_Min_Send_Time,,O,TRUE, +Bacnet_Binary_Output,Time_Delay,,O,TRUE, +Bacnet_Binary_Output,Notification_Class,Unsigned,O,TRUE, +Bacnet_Binary_Output,Feedback_Value,,O,TRUE, +Bacnet_Binary_Output,Event_Enable,BACnetEventTransitionBits,O,TRUE, +Bacnet_Binary_Output,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, +Bacnet_Binary_Output,Notify_Type,BACnetNotifyType,O,TRUE, +Bacnet_Binary_Output,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, +Bacnet_Binary_Output,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Binary_Output,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Binary_Output,Event_Detection_Enable,BOOLEAN,O,TRUE, +Bacnet_Binary_Output,Time_Delay_Normal,,O,TRUE, +Bacnet_Binary_Output,Event_Algorithm_Inhibit,,O,TRUE, +Bacnet_Binary_Output,Event_Algorithm_Inhibit_Ref,,O,TRUE, +Bacnet_Binary_Output,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, +Bacnet_Binary_Value,Object_Identifier,BACnetObjectIdentifier,O,TRUE, +Bacnet_Binary_Value,Object_Name,CharacterString,O,TRUE, +Bacnet_Binary_Value,Object_Type,BACnetObjectType,O,TRUE, +Bacnet_Binary_Value,Present_Value,REAL,O,TRUE, +Bacnet_Binary_Value,Description,CharacterString,O,TRUE, +Bacnet_Binary_Value,Status_Flags,BACnetStatusFlags,O,TRUE, +Bacnet_Binary_Value,Event_State,BACnetEventState,O,TRUE, +Bacnet_Binary_Value,Reliability,BACnetReliability,O,TRUE, +Bacnet_Binary_Value,Out_Of_Service,BOOLEAN,O,TRUE, +Bacnet_Binary_Value,Inactive_Text,,O,TRUE, +Bacnet_Binary_Value,Active_Text,,O,TRUE, +Bacnet_Binary_Value,Change_Of_State_Time,,O,TRUE, +Bacnet_Binary_Value,Change_Of_State_Count,,O,TRUE, +Bacnet_Binary_Value,Time_Of_State_Count_Reset,,O,TRUE, +Bacnet_Binary_Value,Elapsed_Active_Time,,O,TRUE, +Bacnet_Binary_Value,Time_Of_Active_Time_Reset,,O,TRUE, +Bacnet_Binary_Value,Minimum_Off_Time,,O,TRUE, +Bacnet_Binary_Value,Minimum_On_Time,,O,TRUE, +Bacnet_Binary_Value,Priority_Array,,O,TRUE, +Bacnet_Binary_Value,Relinquish_Default,,O,TRUE, +Bacnet_Binary_Value,COV_Period,,O,TRUE, +Bacnet_Binary_Value,COV_Min_Send_Time,,O,TRUE, +Bacnet_Binary_Value,Time_Delay,,O,TRUE, +Bacnet_Binary_Value,Notification_Class,Unsigned,O,TRUE, +Bacnet_Binary_Value,Alarm_Value,,O,TRUE, +Bacnet_Binary_Value,Event_Enable,BACnetEventTransitionBits,O,TRUE, +Bacnet_Binary_Value,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, +Bacnet_Binary_Value,Notify_Type,BACnetNotifyType,O,TRUE, +Bacnet_Binary_Value,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, +Bacnet_Binary_Value,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Binary_Value,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Binary_Value,Event_Detection_Enable,BOOLEAN,O,TRUE, +Bacnet_Binary_Value,Time_Delay_Normal,,O,TRUE, +Bacnet_Binary_Value,Event_Algorithm_Inhibit,,O,TRUE, +Bacnet_Binary_Value,Event_Algorithm_Inhibit_Ref,,O,TRUE, +Bacnet_Binary_Value,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, +Bacnet_Calendar,Object_Identifier,BACnetObjectIdentifier,O,TRUE, +Bacnet_Calendar,Object_Name,CharacterString,O,TRUE, +Bacnet_Calendar,Object_Type,BACnetObjectType,O,TRUE, +Bacnet_Calendar,Present_Value,REAL,O,TRUE, +Bacnet_Calendar,Description,CharacterString,O,TRUE, +Bacnet_Calendar,Date_List,,O,TRUE, +Bacnet_Calendar,Time_To_Next_State,,O,TRUE, +Bacnet_Calendar,Next_State,,O,TRUE, +Bacnet_Calendar,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, +Device,Object_Identifier,BACnetObjectIdentifier,W,TRUE, +Device,Object_Name,CharacterString,W,TRUE, +Device,Object_Type,BACnetObjectType,R,TRUE, +Device,System_Status,,R,TRUE, +Device,Vendor_Name,,R,TRUE, +Device,Vendor_Identifier,,R,TRUE, +Device,Model_Name,,R,TRUE, +Device,Firmware_Revision,,R,TRUE, +Device,Application_Software_Version,,R,TRUE, +Device,Location,,O,TRUE, +Device,Description,CharacterString,O,TRUE, +Device,Protocol_Version,,R,TRUE, +Device,Protocol_Revision,,R,TRUE, +Device,Protocol_Services_Supported,,R,TRUE, +Device,Protocol_Object_Types_Supported,,R,TRUE, +Device,Object_List,,R,TRUE, +Device,Max_APDU_Length_Accepted,,R,TRUE, +Device,Segmentation_Supported,,R,TRUE, +Device,Max_Segments_Accepted,,O,TRUE, +Device,Local_Date,,O,TRUE, +Device,Local_Time,,O,TRUE, +Device,UTC_Offset,,O,TRUE, +Device,Daylight_Savings_Status,,O,TRUE, +Device,Apdu_Segment_Timeout,,O,TRUE, +Device,APDU_Timeout,,W,TRUE, +Device,Number_Of_APDU_Retries,,W,TRUE, +Device,Time_Synchronization_Recipients,,O,TRUE, +Device,Device_Address_Binding,,R,TRUE, +Device,Database_Revision,,R,TRUE, +Device,Configuration_Files,,O,TRUE, +Device,Last_Restore_Time,,O,TRUE, +Device,Backup_Failure_Timeout,,O,TRUE, +Device,Backup_Preparation_Time,,O,TRUE, +Device,Restore_Preparation_Time,,O,TRUE, +Device,Restore_Completion_Time,,O,TRUE, +Device,Backup_And_Restore_State,,O,TRUE, +Device,Active_COV_Subscriptions,,O,TRUE, +Device,Last_Restart_Reason,,O,TRUE, +Device,Time_Of_Device_Restart,,O,TRUE, +Device,Restart_Notification_Recipients,,O,TRUE, +Device,Utc_Time_Synchronization_Recipients,,O,TRUE, +Device,Max_Master,,O,TRUE, +Device,Max_Info_Frames,,O,TRUE, +Device,Time_Synchronization_Interval,,O,TRUE, +Device,Align_Intervals,,O,TRUE, +Device,Interval_Offset,,O,TRUE, +Device,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,R,TRUE, +Event_Enrollment,Object_Identifier,BACnetObjectIdentifier,O,TRUE, +Event_Enrollment,Object_Name,CharacterString,O,TRUE, +Event_Enrollment,Object_Type,BACnetObjectType,O,TRUE, +Event_Enrollment,Description,CharacterString,O,TRUE, +Event_Enrollment,Event_Type,,O,TRUE, +Event_Enrollment,Notify_Type,BACnetNotifyType,O,TRUE, +Event_Enrollment,Event_Parameters,,O,TRUE, +Event_Enrollment,Object_Property_Reference,,O,TRUE, +Event_Enrollment,Event_State,BACnetEventState,O,TRUE, +Event_Enrollment,Event_Enable,BACnetEventTransitionBits,O,TRUE, +Event_Enrollment,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, +Event_Enrollment,Notification_Class,Unsigned,O,TRUE, +Event_Enrollment,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, +Event_Enrollment,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, +Event_Enrollment,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, +Event_Enrollment,Event_Detection_Enable,BOOLEAN,O,TRUE, +Event_Enrollment,Time_Delay_Normal,,O,TRUE, +Event_Enrollment,Status_Flags,BACnetStatusFlags,O,TRUE, +Event_Enrollment,Reliability,BACnetReliability,O,TRUE, +Event_Enrollment,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, +Bacnet_File,Object_Identifier,BACnetObjectIdentifier,O,TRUE, +Bacnet_File,Object_Name,CharacterString,O,TRUE, +Bacnet_File,Object_Type,BACnetObjectType,O,TRUE, +Bacnet_File,Description,CharacterString,O,TRUE, +Bacnet_File,File_Type,,O,TRUE, +Bacnet_File,File_Size,,O,TRUE, +Bacnet_File,Modification_Date,,O,TRUE, +Bacnet_File,Archive,,O,TRUE, +Bacnet_File,Read_Only,,O,TRUE, +Bacnet_File,File_Access_Method,,O,TRUE, +Bacnet_File,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, +Bacnet_Loop,Object_Identifier,BACnetObjectIdentifier,O,TRUE, +Bacnet_Loop,Object_Name,CharacterString,O,TRUE, +Bacnet_Loop,Object_Type,BACnetObjectType,O,TRUE, +Bacnet_Loop,Present_Value,REAL,O,TRUE, +Bacnet_Loop,Description,CharacterString,O,TRUE, +Bacnet_Loop,Status_Flags,BACnetStatusFlags,O,TRUE, +Bacnet_Loop,Event_State,BACnetEventState,O,TRUE, +Bacnet_Loop,Reliability,BACnetReliability,O,TRUE, +Bacnet_Loop,Out_Of_Service,BOOLEAN,O,TRUE, +Bacnet_Loop,Update_Interval,,O,TRUE, +Bacnet_Loop,Output_Units,,O,TRUE, +Bacnet_Loop,Manipulated_Variable_Reference,,O,TRUE, +Bacnet_Loop,Controlled_Variable_Reference,,O,TRUE, +Bacnet_Loop,Controlled_Variable_Value,,O,TRUE, +Bacnet_Loop,Controlled_Variable_Units,,O,TRUE, +Bacnet_Loop,Setpoint_Reference,,O,TRUE, +Bacnet_Loop,Setpoint,,O,TRUE, +Bacnet_Loop,Action,,O,TRUE, +Bacnet_Loop,Proportional_Constant,,O,TRUE, +Bacnet_Loop,Proportional_Constant_Units,,O,TRUE, +Bacnet_Loop,Integral_Constant,,O,TRUE, +Bacnet_Loop,Integral_Constant_Units,,O,TRUE, +Bacnet_Loop,Derivative_Constant,,O,TRUE, +Bacnet_Loop,Derivative_Constant_Units,,O,TRUE, +Bacnet_Loop,Bias,,O,TRUE, +Bacnet_Loop,Maximum_Output,,O,TRUE, +Bacnet_Loop,Minimum_Output,,O,TRUE, +Bacnet_Loop,Priority_For_Writing,Unsigned(1..16),O,TRUE, +Bacnet_Loop,LoopDeadband,,O,TRUE, +Bacnet_Loop,Saturation_Time,,O,TRUE, +Bacnet_Loop,COV_Increment,REAL,O,TRUE, +Bacnet_Loop,COV_Period,,O,TRUE, +Bacnet_Loop,COV_Min_Send_Time,,O,TRUE, +Bacnet_Loop,Ramp_Time,,O,TRUE, +Bacnet_Loop,Saturation_Time_Low_Limit_Enable,,O,TRUE, +Bacnet_Loop,Saturation_Time_High_Limit_Enable,,O,TRUE, +Bacnet_Loop,Time_Delay,,O,TRUE, +Bacnet_Loop,Notification_Class,Unsigned,O,TRUE, +Bacnet_Loop,Error_Limit,,O,TRUE, +Bacnet_Loop,Deadband,,O,TRUE, +Bacnet_Loop,Event_Enable,BACnetEventTransitionBits,O,TRUE, +Bacnet_Loop,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, +Bacnet_Loop,Notify_Type,BACnetNotifyType,O,TRUE, +Bacnet_Loop,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, +Bacnet_Loop,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Loop,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Loop,Event_Detection_Enable,BOOLEAN,O,TRUE, +Bacnet_Loop,Time_Delay_Normal,,O,TRUE, +Bacnet_Loop,Event_Algorithm_Inhibit,,O,TRUE, +Bacnet_Loop,Event_Algorithm_Inhibit_Ref,,O,TRUE, +Bacnet_Loop,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, +Bacnet_Multi-state_Input,Object_Identifier,BACnetObjectIdentifier,O,TRUE, +Bacnet_Multi-state_Input,Object_Name,CharacterString,O,TRUE, +Bacnet_Multi-state_Input,Object_Type,BACnetObjectType,O,TRUE, +Bacnet_Multi-state_Input,Present_Value,REAL,O,TRUE, +Bacnet_Multi-state_Input,Description,CharacterString,O,TRUE, +Bacnet_Multi-state_Input,Device_Type,,O,TRUE, +Bacnet_Multi-state_Input,Status_Flags,BACnetStatusFlags,O,TRUE, +Bacnet_Multi-state_Input,Event_State,BACnetEventState,O,TRUE, +Bacnet_Multi-state_Input,Reliability,BACnetReliability,O,TRUE, +Bacnet_Multi-state_Input,Out_Of_Service,BOOLEAN,O,TRUE, +Bacnet_Multi-state_Input,Number_of_States,,O,TRUE, +Bacnet_Multi-state_Input,State_Text,,O,TRUE, +Bacnet_Multi-state_Input,COV_Period,,O,TRUE, +Bacnet_Multi-state_Input,COV_Min_Send_Time,,O,TRUE, +Bacnet_Multi-state_Input,Time_Delay,,O,TRUE, +Bacnet_Multi-state_Input,Notification_Class,Unsigned,O,TRUE, +Bacnet_Multi-state_Input,Alarm_Values,,O,TRUE, +Bacnet_Multi-state_Input,Fault_Values,,O,TRUE, +Bacnet_Multi-state_Input,Event_Enable,BACnetEventTransitionBits,O,TRUE, +Bacnet_Multi-state_Input,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, +Bacnet_Multi-state_Input,Notify_Type,BACnetNotifyType,O,TRUE, +Bacnet_Multi-state_Input,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, +Bacnet_Multi-state_Input,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Multi-state_Input,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Multi-state_Input,Event_Detection_Enable,BOOLEAN,O,TRUE, +Bacnet_Multi-state_Input,Time_Delay_Normal,,O,TRUE, +Bacnet_Multi-state_Input,Event_Algorithm_Inhibit,,O,TRUE, +Bacnet_Multi-state_Input,Event_Algorithm_Inhibit_Ref,,O,TRUE, +Bacnet_Multi-state_Input,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, +Bacnet_Multi-state_Value,Object_Identifier,BACnetObjectIdentifier,O,TRUE, +Bacnet_Multi-state_Value,Object_Name,CharacterString,O,TRUE, +Bacnet_Multi-state_Value,Object_Type,BACnetObjectType,O,TRUE, +Bacnet_Multi-state_Value,Present_Value,REAL,O,TRUE, +Bacnet_Multi-state_Value,Description,CharacterString,O,TRUE, +Bacnet_Multi-state_Value,Status_Flags,BACnetStatusFlags,O,TRUE, +Bacnet_Multi-state_Value,Event_State,BACnetEventState,O,TRUE, +Bacnet_Multi-state_Value,Reliability,BACnetReliability,O,TRUE, +Bacnet_Multi-state_Value,Out_Of_Service,BOOLEAN,O,TRUE, +Bacnet_Multi-state_Value,Number_of_States,,O,TRUE, +Bacnet_Multi-state_Value,State_Text,,O,TRUE, +Bacnet_Multi-state_Value,Priority_Array,,O,TRUE, +Bacnet_Multi-state_Value,Relinquish_Default,,O,TRUE, +Bacnet_Multi-state_Value,COV_Period,,O,TRUE, +Bacnet_Multi-state_Value,COV_Min_Send_Time,,O,TRUE, +Bacnet_Multi-state_Value,Time_Delay,,O,TRUE, +Bacnet_Multi-state_Value,Notification_Class,Unsigned,O,TRUE, +Bacnet_Multi-state_Value,Alarm_Values,,O,TRUE, +Bacnet_Multi-state_Value,Fault_Values,,O,TRUE, +Bacnet_Multi-state_Value,Event_Enable,BACnetEventTransitionBits,O,TRUE, +Bacnet_Multi-state_Value,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, +Bacnet_Multi-state_Value,Notify_Type,BACnetNotifyType,O,TRUE, +Bacnet_Multi-state_Value,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, +Bacnet_Multi-state_Value,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Multi-state_Value,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Multi-state_Value,Event_Detection_Enable,BOOLEAN,O,TRUE, +Bacnet_Multi-state_Value,Time_Delay_Normal,,O,TRUE, +Bacnet_Multi-state_Value,Event_Algorithm_Inhibit,,O,TRUE, +Bacnet_Multi-state_Value,Event_Algorithm_Inhibit_Ref,,O,TRUE, +Bacnet_Multi-state_Value,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, +Bacnet_Program,Object_Identifier,BACnetObjectIdentifier,O,TRUE, +Bacnet_Program,Object_Name,CharacterString,O,TRUE, +Bacnet_Program,Object_Type,BACnetObjectType,O,TRUE, +Bacnet_Program,Description,CharacterString,O,TRUE, +Bacnet_Program,Program_State,,O,TRUE, +Bacnet_Program,Program_Change,,O,TRUE, +Bacnet_Program,Description_Of_Halt,,O,TRUE, +Bacnet_Program,Reason_For_Halt,,O,TRUE, +Bacnet_Program,Status_Flags,BACnetStatusFlags,O,TRUE, +Bacnet_Program,Reliability,BACnetReliability,O,TRUE, +Bacnet_Program,Out_Of_Service,BOOLEAN,O,TRUE, +Bacnet_Program,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, +Bacnet_Notification,Object_Identifier,BACnetObjectIdentifier,O,TRUE, +Bacnet_Notification,Object_Name,CharacterString,O,TRUE, +Bacnet_Notification,Object_Type,BACnetObjectType,O,TRUE, +Bacnet_Notification,Description,CharacterString,O,TRUE, +Bacnet_Notification,Notification_Class,Unsigned,O,TRUE, +Bacnet_Notification,Priority,,O,TRUE, +Bacnet_Notification,Ack_Required,,O,TRUE, +Bacnet_Notification,Recipient_List,,O,TRUE, +Bacnet_Notification,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, +Bacnet_Schedule,Object_Identifier,BACnetObjectIdentifier,O,TRUE, +Bacnet_Schedule,Object_Name,CharacterString,O,TRUE, +Bacnet_Schedule,Object_Type,BACnetObjectType,O,TRUE, +Bacnet_Schedule,Description,CharacterString,O,TRUE, +Bacnet_Schedule,Present_Value,REAL,O,TRUE, +Bacnet_Schedule,Effective_Period,,O,TRUE, +Bacnet_Schedule,Weekly_Schedule,,O,TRUE, +Bacnet_Schedule,Exception_Schedule,,O,TRUE, +Bacnet_Schedule,Schedule_Default,,O,TRUE, +Bacnet_Schedule,List_Of_Object_Property_References,,O,TRUE, +Bacnet_Schedule,Priority_For_Writing,Unsigned(1..16),O,TRUE, +Bacnet_Schedule,Status_Flags,BACnetStatusFlags,O,TRUE, +Bacnet_Schedule,Reliability,BACnetReliability,O,TRUE, +Bacnet_Schedule,Out_Of_Service,BOOLEAN,O,TRUE, +Bacnet_Schedule,Time_To_Next_State,,O,TRUE, +Bacnet_Schedule,Next_State,,O,TRUE, +Bacnet_Schedule,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,O,TRUE, +Bacnet_Trend_Log,Object_Identifier,BACnetObjectIdentifier,O,TRUE, +Bacnet_Trend_Log,Object_Name,CharacterString,O,TRUE, +Bacnet_Trend_Log,Object_Type,BACnetObjectType,O,TRUE, +Bacnet_Trend_Log,Description,CharacterString,O,TRUE, +Bacnet_Trend_Log,Enable,,O,TRUE, +Bacnet_Trend_Log,Start_Time,,O,TRUE, +Bacnet_Trend_Log,Stop_Time,,O,TRUE, +Bacnet_Trend_Log,Log_Device_Object_Property,,O,TRUE, +Bacnet_Trend_Log,Log_Interval,,O,TRUE, +Bacnet_Trend_Log,Cov_Resubscription_Interval,,O,TRUE, +Bacnet_Trend_Log,Client_Cov_Increment,,O,TRUE, +Bacnet_Trend_Log,Stop_When_Full,,O,TRUE, +Bacnet_Trend_Log,Buffer_Size,,O,TRUE, +Bacnet_Trend_Log,Log_Buffer,,O,TRUE, +Bacnet_Trend_Log,Record_Count,,O,TRUE, +Bacnet_Trend_Log,Total_Record_Count,,O,TRUE, +Bacnet_Trend_Log,Logging_Type,,O,TRUE, +Bacnet_Trend_Log,Align_Intervals,,O,TRUE, +Bacnet_Trend_Log,Interval_Offset,,O,TRUE, +Bacnet_Trend_Log,Trigger,,O,TRUE, +Bacnet_Trend_Log,Status_Flags,BACnetStatusFlags,O,TRUE, +Bacnet_Trend_Log,Reliability,BACnetReliability,O,TRUE, +Bacnet_Trend_Log,Notification_Threshold,,O,TRUE, +Bacnet_Trend_Log,Records_Since_Notification,,O,TRUE, +Bacnet_Trend_Log,Last_Notify_Record,,O,TRUE, +Bacnet_Trend_Log,Event_State,BACnetEventState,O,TRUE, +Bacnet_Trend_Log,Notification_Class,Unsigned,O,TRUE, +Bacnet_Trend_Log,Event_Enable,BACnetEventTransitionBits,O,TRUE, +Bacnet_Trend_Log,Acked_Transitions,BACnetEventTransitionBits,O,TRUE, +Bacnet_Trend_Log,Notify_Type,BACnetNotifyType,O,TRUE, +Bacnet_Trend_Log,Event_Time_Stamps,BACnetARRAY[3] of BACnetTimeStamp,O,TRUE, +Bacnet_Trend_Log,Event_Message_Texts,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Trend_Log,Event_Message_Texts_Config,BACnetARRAY[3] of CharacterString,O,TRUE, +Bacnet_Trend_Log,Event_Detection_Enable,BOOLEAN,O,TRUE, +Bacnet_Trend_Log,Event_Algorithm_Inhibit,,O,TRUE, +Bacnet_Trend_Log,Event_Algorithm_Inhibit_Ref,,O,TRUE, Bacnet_Trend_Log,Property_List,BACnetARRAY[N] of BACnetPropertyIdentifier,R,TRUE, \ No newline at end of file From 85b132a9ef431c5a0b048640dad9842559bc596b Mon Sep 17 00:00:00 2001 From: Trevor Date: Mon, 3 Aug 2020 10:40:23 -0700 Subject: [PATCH 068/212] Test infrastructure cleanup (#572) --- .github/workflows/tests.yml | 15 +++++++++++++-- .github/workflows/usi.yml | 21 --------------------- README.md | 3 +-- bin/setup_base | 9 ++------- bin/setup_dev | 4 +--- bin/test_daq | 10 ++++------ bin/trigger_travis | 28 ---------------------------- 7 files changed, 21 insertions(+), 69 deletions(-) delete mode 100644 .github/workflows/usi.yml delete mode 100755 bin/trigger_travis diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c65e0a6c13..457c8c6be0 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,7 +1,7 @@ # This workflow will install Python dependencies, run tests and lint with a single version of Python # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions -name: DAQ main tests +name: DAQ push/pull tests on: [push, pull_request] @@ -50,4 +50,15 @@ jobs: bin/check_style - name: Unit test run: | - testing/run_unit_tests.sh \ No newline at end of file + testing/run_unit_tests.sh + + usi_tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 1.11 + uses: actions/setup-java@v1 + with: + java-version: 1.11 + - name: Build with Maven + run: mvn -B clean compile test assembly:single --file usi/pom.xml diff --git a/.github/workflows/usi.yml b/.github/workflows/usi.yml deleted file mode 100644 index 550fc9d815..0000000000 --- a/.github/workflows/usi.yml +++ /dev/null @@ -1,21 +0,0 @@ - -# This workflow will build a Java project with Maven -# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven - -name: USI Java CI with Maven - -on: [push, pull_request] - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - name: Set up JDK 1.11 - uses: actions/setup-java@v1 - with: - java-version: 1.11 - - name: Build with Maven - run: mvn -B clean compile test assembly:single --file usi/pom.xml diff --git a/README.md b/README.md index 7fcde011ef..d680013e8e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -![Main tests](https://github.com/faucetsdn/daq/workflows/DAQ%20main%20tests/badge.svg?branch=master) -![USI Java CI with Maven](https://github.com/faucetsdn/daq/workflows/USI%20Java%20CI%20with%20Maven/badge.svg?branch=master) +![CI Tests](https://github.com/faucetsdn/daq/workflows/DAQ%20push%2Fpull%20tests/badge.svg?branch=master) # DAQ: Device Automated Qualification for IoT Devices. diff --git a/bin/setup_base b/bin/setup_base index 2df5826d96..6ccd6e8dee 100755 --- a/bin/setup_base +++ b/bin/setup_base @@ -24,10 +24,7 @@ fi echo AG is $AG -# Hacky workaround for https://travis-ci.community/t/sometimes-build-fails-when-apt-is-updating-postgresql-apt-repository/4872/17 -# Need to remove the || true at the end of the update line. Same as for instance below. Also in bin/setup_dev. -$AG update || true -$AG install realpath || true # On newer versions this is included elsewhere. +$AG update $AG install expect lsb-release git curl sudo apt-transport-https software-properties-common gnupg-agent net-tools retry=bin/retry_cmd @@ -46,9 +43,7 @@ else echo "deb http://packages.wand.net.nz $release main" | sudo tee /etc/apt/sources.list.d/wand.list $retry sudo curl http://packages.wand.net.nz/keyring.gpg -o /etc/apt/trusted.gpg.d/wand.gpg - # Hacky workaround for https://travis-ci.community/t/sometimes-build-fails-when-apt-is-updating-postgresql-apt-repository/4872/17 - #Need to remove the || true at the end of the update line. Same as for instance above. Also in bin/setup_dev. - $AG update || true + $AG update $AG install docker-ce${DOCKER_VERSION} fi diff --git a/bin/setup_dev b/bin/setup_dev index 7ae8b1aef0..f6debbae9b 100755 --- a/bin/setup_dev +++ b/bin/setup_dev @@ -62,10 +62,8 @@ if [ "$DAQ_BUILD" == "no" ]; then exit 0 fi -# Hacky workaround for https://travis-ci.community/t/sometimes-build-fails-when-apt-is-updating-postgresql-apt-repository/4872/17 -# Need to remove the || true at the end of the update line. Also in bin/setup_base. echo $AG update -$AG update || true +$AG update echo $AG install $AG install lsb-release diff --git a/bin/test_daq b/bin/test_daq index a389500482..38028a4fb0 100755 --- a/bin/test_daq +++ b/bin/test_daq @@ -8,13 +8,12 @@ if [ -z "$DAQ_TEST" ]; then false fi -function delay_finish { - # Travis doesn't always wait for buffer to flush on exit, so give some time. - sleep 10 +function test_finish { + echo Exiting test script. } if [ -n "$CI" ]; then - trap delay_finish EXIT + trap test_finish EXIT fi ROOT=$(realpath $(dirname $0)/..) @@ -36,7 +35,7 @@ if ! git show $TAGGED_VERSION > /dev/null; then echo echo Tagged version $TAGGED_VERSION not found. echo Maybe you need to fetch tags: git fetch --tags. - echo If this is on Travis, ensure tags were pushed to your repo. + echo If this happens during CI testing, ensure tags were pushed to your repo. echo false fi @@ -69,7 +68,6 @@ GCP_RESULTS=inst/test_$DAQ_TEST.gcp CRED_FILE=inst/config/gcp_service_account.json echo Running test script $TEST_SCRIPT -# Combine stderr & stdout b/c travis has problems processing both. sudo PATH=$PATH TEST_RESULTS=$TEST_RESULTS GCP_RESULTS=$GCP_RESULTS \ DAQ_CODECOV=y GCP_BASE64_CRED="$GCP_BASE64_CRED" $TEST_SCRIPT 2>&1 diff --git a/bin/trigger_travis b/bin/trigger_travis deleted file mode 100755 index e32a6fe648..0000000000 --- a/bin/trigger_travis +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -e - -OUTFILE=$HOME/.travis.out - -echo Trigger build at `date` > $OUTFILE - -echo Reading info from $HOME/.travis.env >> $OUTFILE -source $HOME/.travis.env - -if [ -z "$TRAVIS_API_TOKEN" ]; then - echo TRAVIS_API_TOKEN not defined. - false -fi - -body='{ -"request": { -"branch":"master" -}}' - -curl -s -X POST \ - -H "Content-Type: application/json" \ - -H "Accept: application/json" \ - -H "Travis-API-Version: 3" \ - -H "Authorization: token $TRAVIS_API_TOKEN" \ - -d "$body" \ - https://api.travis-ci.org/repo/grafnu%2Fdaq/requests >> $OUTFILE 2>&1 - -echo Trigger complete. >> $OUTFILE From 4886fecc015b177af7c9e9716d91ae279002476a Mon Sep 17 00:00:00 2001 From: Noureddine Date: Tue, 4 Aug 2020 23:15:43 +0100 Subject: [PATCH 069/212] Cleanup Network Tests and Network Test Module (#565) * removed depreciated code and moved ntp and macoui tests into network module --- config/modules/all.conf | 3 +- docker/include/bin/start_faux | 22 +- .../.idea/codeStyles/codeStyleConfig.xml | 0 .../network/NTPClient/.idea/gradle.xml | 0 .../NTPClient/.idea/jarRepositories.xml | 0 .../include}/network/NTPClient/.idea/misc.xml | 0 .../include}/network/NTPClient/.idea/vcs.xml | 0 .../include}/network/NTPClient/build.gradle | 0 .../gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 0 .../include}/network/NTPClient/gradlew | 0 .../include}/network/NTPClient/gradlew.bat | 0 .../network/NTPClient/settings.gradle | 0 .../src/main/java/META-INF/MANIFEST.MF | 0 .../NTPClient/src/main/java/Main.java | 0 .../NTPClient/src/main/java/NtpMessage.java | 0 .../network/TransportClient/client.py | 23 +- docker/modules/Dockerfile.faux1 | 6 +- docs/device_report.md | 73 ++++--- .../module_config.json | 6 - .../distech_ecy-s1000/module_config.json | 6 - resources/setups/baseline/module_config.json | 6 - .../qualification/device_module_config.json | 6 - .../device_type_module_config.json | 7 +- .../qualification/system_module_config.json | 7 +- .../remediation/device_module_config.json | 7 +- .../remediation/system_module_config.json | 7 +- .../mac_addrs/3c5ab41e8f0b/module_config.json | 4 - resources/test_site/module_config.json | 3 - subset/connection/Dockerfile.test_macoui | 17 -- subset/connection/build.conf | 2 - subset/connection/mac_oui/.project | 23 -- subset/connection/readme.md | 20 -- subset/network/Dockerfile.test_network | 19 +- .../gradle/wrapper/gradle-wrapper.properties | 5 - .../network/NTPClient/src/main/java/Main.java | 81 ------- .../NTPClient/src/main/java/NtpMessage.java | 206 ------------------ subset/network/README.md | 67 ++++++ subset/network/debug_generate_capture.py | 20 -- .../mac_oui/.classpath | 0 .../mac_oui/.gitignore | 0 .../org.eclipse.buildship.core.prefs | 0 .../mac_oui/build.gradle | 0 .../mac_oui/gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 0 .../{connection => network}/mac_oui/gradlew | 0 .../mac_oui/gradlew.bat | 0 .../mac_oui/mac_oui.iml | 0 .../mac_oui/settings.gradle | 0 .../mac_oui/src/main/java/MacLookup.java | 0 .../mac_oui/src/main/java/Main.java | 0 .../mac_oui/src/main/java/ReportHandler.java | 2 +- .../mac_oui/src/main/java/RetrieveList.java | 0 subset/network/network_tests.py | 151 ++++--------- subset/{ntp => network}/ntp_tests.py | 3 +- .../test_macoui => network/run_macoui_test} | 8 +- subset/network/test_network | 19 +- subset/ntp/Dockerfile.test_ntp | 10 - subset/ntp/NTPClient/.idea/gradle.xml | 19 -- .../ntp/NTPClient/.idea/jarRepositories.xml | 20 -- subset/ntp/NTPClient/.idea/misc.xml | 5 - subset/ntp/NTPClient/.idea/vcs.xml | 6 - subset/ntp/NTPClient/build.gradle | 22 -- .../gradle/wrapper/gradle-wrapper.jar | Bin 55190 -> 0 bytes subset/ntp/NTPClient/gradlew | 172 --------------- subset/ntp/NTPClient/gradlew.bat | 84 ------- subset/ntp/NTPClient/settings.gradle | 2 - .../src/main/java/META-INF/MANIFEST.MF | 3 - subset/ntp/README.md | 29 --- subset/ntp/build.conf | 2 - subset/ntp/test_ntp | 10 - testing/test_aux.out | 26 +-- testing/test_aux.sh | 6 +- 73 files changed, 249 insertions(+), 996 deletions(-) rename {subset/ntp => docker/include/network}/NTPClient/.idea/codeStyles/codeStyleConfig.xml (100%) rename {subset => docker/include}/network/NTPClient/.idea/gradle.xml (100%) rename {subset => docker/include}/network/NTPClient/.idea/jarRepositories.xml (100%) rename {subset => docker/include}/network/NTPClient/.idea/misc.xml (100%) rename {subset => docker/include}/network/NTPClient/.idea/vcs.xml (100%) rename {subset => docker/include}/network/NTPClient/build.gradle (100%) rename {subset => docker/include}/network/NTPClient/gradle/wrapper/gradle-wrapper.jar (100%) rename {subset/ntp => docker/include/network}/NTPClient/gradle/wrapper/gradle-wrapper.properties (100%) rename {subset => docker/include}/network/NTPClient/gradlew (100%) rename {subset => docker/include}/network/NTPClient/gradlew.bat (100%) rename {subset => docker/include}/network/NTPClient/settings.gradle (100%) rename {subset => docker/include}/network/NTPClient/src/main/java/META-INF/MANIFEST.MF (100%) rename {subset/ntp => docker/include/network}/NTPClient/src/main/java/Main.java (100%) rename {subset/ntp => docker/include/network}/NTPClient/src/main/java/NtpMessage.java (100%) rename {subset => docker/include}/network/TransportClient/client.py (59%) delete mode 100644 subset/connection/Dockerfile.test_macoui delete mode 100644 subset/connection/build.conf delete mode 100644 subset/connection/mac_oui/.project delete mode 100644 subset/connection/readme.md delete mode 100644 subset/network/NTPClient/gradle/wrapper/gradle-wrapper.properties delete mode 100644 subset/network/NTPClient/src/main/java/Main.java delete mode 100644 subset/network/NTPClient/src/main/java/NtpMessage.java create mode 100644 subset/network/README.md delete mode 100644 subset/network/debug_generate_capture.py rename subset/{connection => network}/mac_oui/.classpath (100%) rename subset/{connection => network}/mac_oui/.gitignore (100%) rename subset/{connection => network}/mac_oui/.settings/org.eclipse.buildship.core.prefs (100%) rename subset/{connection => network}/mac_oui/build.gradle (100%) rename subset/{connection => network}/mac_oui/gradle/wrapper/gradle-wrapper.jar (100%) rename subset/{connection => network}/mac_oui/gradle/wrapper/gradle-wrapper.properties (100%) rename subset/{connection => network}/mac_oui/gradlew (100%) rename subset/{connection => network}/mac_oui/gradlew.bat (100%) rename subset/{connection => network}/mac_oui/mac_oui.iml (100%) rename subset/{connection => network}/mac_oui/settings.gradle (100%) rename subset/{connection => network}/mac_oui/src/main/java/MacLookup.java (100%) rename subset/{connection => network}/mac_oui/src/main/java/Main.java (100%) rename subset/{connection => network}/mac_oui/src/main/java/ReportHandler.java (91%) rename subset/{connection => network}/mac_oui/src/main/java/RetrieveList.java (100%) rename subset/{ntp => network}/ntp_tests.py (99%) rename subset/{connection/test_macoui => network/run_macoui_test} (89%) delete mode 100644 subset/ntp/Dockerfile.test_ntp delete mode 100644 subset/ntp/NTPClient/.idea/gradle.xml delete mode 100644 subset/ntp/NTPClient/.idea/jarRepositories.xml delete mode 100644 subset/ntp/NTPClient/.idea/misc.xml delete mode 100644 subset/ntp/NTPClient/.idea/vcs.xml delete mode 100644 subset/ntp/NTPClient/build.gradle delete mode 100644 subset/ntp/NTPClient/gradle/wrapper/gradle-wrapper.jar delete mode 100755 subset/ntp/NTPClient/gradlew delete mode 100644 subset/ntp/NTPClient/gradlew.bat delete mode 100644 subset/ntp/NTPClient/settings.gradle delete mode 100644 subset/ntp/NTPClient/src/main/java/META-INF/MANIFEST.MF delete mode 100644 subset/ntp/README.md delete mode 100644 subset/ntp/build.conf delete mode 100755 subset/ntp/test_ntp diff --git a/config/modules/all.conf b/config/modules/all.conf index 59b4b74367..37b581b695 100644 --- a/config/modules/all.conf +++ b/config/modules/all.conf @@ -3,9 +3,8 @@ include config/modules/host.conf # All contributed modules. include subset/switches/build.conf -include subset/connection/build.conf include subset/bacnet/build.conf include subset/security/build.conf include subset/cloud/build.conf include subset/manual/build.conf -include subset/ntp/build.conf +include subset/network/build.conf diff --git a/docker/include/bin/start_faux b/docker/include/bin/start_faux index 25b13a5f1d..d6afdf8972 100755 --- a/docker/include/bin/start_faux +++ b/docker/include/bin/start_faux @@ -181,11 +181,11 @@ if [ -n "${options[ntp_pass]}" -o -n "${options[ntp_fail]}" ]; then fi if [ -n "${options[broadcast_client]}" ]; then - echo Starting broatcast client. - cip_port=41794 + echo Starting broadcast client. + port=41794 cycle_seconds=20 duration_seconds=360 - python TransportClient/client.py $broadcast_ip $cip_port broadcast $duration_seconds $cycle_seconds & + python TransportClient/client.py $broadcast_ip $port broadcast $duration_seconds $cycle_seconds & fi if [ -n "${options[discover]}" ]; then @@ -193,11 +193,6 @@ if [ -n "${options[discover]}" ]; then bin/bacnet_discover loop & fi -if [ -n "${options[curl]}" ]; then - echo Starting curl loop. - (while true; do curl -o - http://google.com; sleep 1; done) & -fi - if [ -n "${options[brute]}" ]; then echo Starting brute server. (python pentests/brute_server.py bad 10000; echo Brute done.) & @@ -229,6 +224,17 @@ if [ -n "${options[pubber]}" ]; then done) & fi +# Periodically sends ARP packets +if [ -z "${options[xarp]}" ]; then + echo Starting arp send loop. + (while true; do arpsend -D -e 10.20.254.254 $intf_name; sleep 2; done) & +fi + +if [ -n "${options[curl]}" ]; then + echo Starting curl loop. + (while true; do curl -o - http://google.com; sleep 1; done) & +fi + conf_file=/config/start/start_faux.sh if [ -f $conf_file ]; then echo Loading $conf_file... diff --git a/subset/ntp/NTPClient/.idea/codeStyles/codeStyleConfig.xml b/docker/include/network/NTPClient/.idea/codeStyles/codeStyleConfig.xml similarity index 100% rename from subset/ntp/NTPClient/.idea/codeStyles/codeStyleConfig.xml rename to docker/include/network/NTPClient/.idea/codeStyles/codeStyleConfig.xml diff --git a/subset/network/NTPClient/.idea/gradle.xml b/docker/include/network/NTPClient/.idea/gradle.xml similarity index 100% rename from subset/network/NTPClient/.idea/gradle.xml rename to docker/include/network/NTPClient/.idea/gradle.xml diff --git a/subset/network/NTPClient/.idea/jarRepositories.xml b/docker/include/network/NTPClient/.idea/jarRepositories.xml similarity index 100% rename from subset/network/NTPClient/.idea/jarRepositories.xml rename to docker/include/network/NTPClient/.idea/jarRepositories.xml diff --git a/subset/network/NTPClient/.idea/misc.xml b/docker/include/network/NTPClient/.idea/misc.xml similarity index 100% rename from subset/network/NTPClient/.idea/misc.xml rename to docker/include/network/NTPClient/.idea/misc.xml diff --git a/subset/network/NTPClient/.idea/vcs.xml b/docker/include/network/NTPClient/.idea/vcs.xml similarity index 100% rename from subset/network/NTPClient/.idea/vcs.xml rename to docker/include/network/NTPClient/.idea/vcs.xml diff --git a/subset/network/NTPClient/build.gradle b/docker/include/network/NTPClient/build.gradle similarity index 100% rename from subset/network/NTPClient/build.gradle rename to docker/include/network/NTPClient/build.gradle diff --git a/subset/network/NTPClient/gradle/wrapper/gradle-wrapper.jar b/docker/include/network/NTPClient/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from subset/network/NTPClient/gradle/wrapper/gradle-wrapper.jar rename to docker/include/network/NTPClient/gradle/wrapper/gradle-wrapper.jar diff --git a/subset/ntp/NTPClient/gradle/wrapper/gradle-wrapper.properties b/docker/include/network/NTPClient/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from subset/ntp/NTPClient/gradle/wrapper/gradle-wrapper.properties rename to docker/include/network/NTPClient/gradle/wrapper/gradle-wrapper.properties diff --git a/subset/network/NTPClient/gradlew b/docker/include/network/NTPClient/gradlew similarity index 100% rename from subset/network/NTPClient/gradlew rename to docker/include/network/NTPClient/gradlew diff --git a/subset/network/NTPClient/gradlew.bat b/docker/include/network/NTPClient/gradlew.bat similarity index 100% rename from subset/network/NTPClient/gradlew.bat rename to docker/include/network/NTPClient/gradlew.bat diff --git a/subset/network/NTPClient/settings.gradle b/docker/include/network/NTPClient/settings.gradle similarity index 100% rename from subset/network/NTPClient/settings.gradle rename to docker/include/network/NTPClient/settings.gradle diff --git a/subset/network/NTPClient/src/main/java/META-INF/MANIFEST.MF b/docker/include/network/NTPClient/src/main/java/META-INF/MANIFEST.MF similarity index 100% rename from subset/network/NTPClient/src/main/java/META-INF/MANIFEST.MF rename to docker/include/network/NTPClient/src/main/java/META-INF/MANIFEST.MF diff --git a/subset/ntp/NTPClient/src/main/java/Main.java b/docker/include/network/NTPClient/src/main/java/Main.java similarity index 100% rename from subset/ntp/NTPClient/src/main/java/Main.java rename to docker/include/network/NTPClient/src/main/java/Main.java diff --git a/subset/ntp/NTPClient/src/main/java/NtpMessage.java b/docker/include/network/NTPClient/src/main/java/NtpMessage.java similarity index 100% rename from subset/ntp/NTPClient/src/main/java/NtpMessage.java rename to docker/include/network/NTPClient/src/main/java/NtpMessage.java diff --git a/subset/network/TransportClient/client.py b/docker/include/network/TransportClient/client.py similarity index 59% rename from subset/network/TransportClient/client.py rename to docker/include/network/TransportClient/client.py index e72b83ec2f..15a01d951c 100644 --- a/subset/network/TransportClient/client.py +++ b/docker/include/network/TransportClient/client.py @@ -1,3 +1,10 @@ +""" + Used within the faux device to start a client which will send out broadcast packets. + + Usage: + python TransportClient/client.py $broadcast_ip $port broadcast $duration_seconds $cycle_seconds +""" + import socket, sys, time arguments = sys.argv @@ -7,19 +14,25 @@ transport_type = str(arguments[3]) duration_seconds = int(arguments[4]) cycle_seconds = int(arguments[5]) -message = "Fried lizards taste like chicken" +message = "Fried lizards taste like chicken!" -def broadcast_setup_socket(): + +def get_broadcast_socket(): client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) client.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) return client + def send_message(message, transport_type): + client = None + if transport_type == 'broadcast': - client = broadcast_setup_socket() - sent = client.sendto(message, (udp_ip_address, udp_port)) + client = get_broadcast_socket() + + client.sendto(message, (udp_ip_address, udp_port)) + -while(duration_seconds > 0): +while duration_seconds > 0: print('{t} to {a}'.format(t=transport_type, a=udp_ip_address)) send_message(message, transport_type) time.sleep(cycle_seconds) diff --git a/docker/modules/Dockerfile.faux1 b/docker/modules/Dockerfile.faux1 index 4dbb7e16a8..14e18e428e 100644 --- a/docker/modules/Dockerfile.faux1 +++ b/docker/modules/Dockerfile.faux1 @@ -34,14 +34,14 @@ FROM daqf/aardvark:latest RUN $AG update && $AG install openjdk-8-jre RUN $AG update && $AG install openjdk-8-jdk git RUN $AG update && $AG install isc-dhcp-client ethtool network-manager netcat curl\ - python ifupdown openssl nano apache2-utils ntpdate + python ifupdown openssl nano apache2-utils ntpdate vzctl # Additional OS dependencies RUN $AG update && $AG install -y telnetd && $AG install xinetd nginx -COPY subset/ntp/NTPClient NTPClient +COPY docker/include/network/NTPClient NTPClient RUN cd NTPClient && ./gradlew build -COPY subset/network/TransportClient TransportClient +COPY docker/include/network/TransportClient TransportClient # Prefetch resolvconf to dynamically install at runtime in start_faux. RUN $AG update && cd /tmp && ln -s ~/bin bin && $AG download resolvconf && mv resolvconf_*.deb ~ diff --git a/docs/device_report.md b/docs/device_report.md index a3e4f1736f..5e05860613 100644 --- a/docs/device_report.md +++ b/docs/device_report.md @@ -52,11 +52,11 @@ Overall device result FAIL |Other|1/2| |Connectivity|n/a| -|Expectation|pass|fail|skip|gone| -|---|---|---|---|---| -|Required|1|0|0|0| -|Recommended|2|0|0|0| -|Other|3|2|22|2| +|Expectation|pass|fail|skip|info|gone| +|---|---|---|---|---|---| +|Required|1|0|0|0|0| +|Recommended|2|0|0|0|0| +|Other|4|2|22|1|2| |Result|Test|Category|Expectation|Notes| |---|---|---|---|---| @@ -66,7 +66,9 @@ Overall device result FAIL |skip|cloud.udmi.pointset|Other|Other|No device id| |skip|cloud.udmi.state|Other|Other|No device id| |skip|cloud.udmi.system|Other|Other|No device id| +|info|communication.type.broadcast|Other|Other|Broadcast packets received. Unicast packets received.| |fail|connection.mac_oui|Other|Other|Manufacturer prefix not found!| +|pass|connection.min_send|Other|Other|ARP packets received. Data packets were sent at a frequency of less than 5 minutes| |pass|connection.network.ntp_support|Other|Other|Using NTPv4.| |pass|connection.network.ntp_update|Other|Other|Device clock synchronized.| |skip|connection.port_duplex|Other|Other|No local IP has been set, check system config| @@ -267,30 +269,6 @@ RESULT skip poe.support No local IP has been set, check system config |enabled|True| |poe|{'enabled': True}| -## Module macoui - - -#### Report - -``` --------------------- -connection.mac_oui --------------------- -Check Physical device address OUI against IEEE registration and verify it is registered with the correct manufacturer --------------------- -Using the host hardware address 9a:02:57:1e:8f:01 -Mac OUI Test --------------------- -RESULT fail connection.mac_oui Manufacturer prefix not found! - -``` - -#### Module Config - -|Attribute|Value| -|---|---| -|enabled|True| - ## Module bacext @@ -560,13 +538,38 @@ RESULT pass manual.test.name Manual test - for testing |---|---| |enabled|True| -## Module ntp +## Module network #### Report ``` -------------------- +connection.min_send +-------------------- +Device sends data at a frequency of less than 5 minutes. +-------------------- + + + + + + + + + + + +RESULT pass connection.min_send ARP packets received. Data packets were sent at a frequency of less than 5 minutes +-------------------- +communication.type.broadcast +-------------------- +Device sends unicast or broadcast packets. +-------------------- + + +RESULT info communication.type.broadcast Broadcast packets received. Unicast packets received. +-------------------- connection.network.ntp_support -------------------- Device supports NTP version 4. @@ -578,6 +581,16 @@ connection.network.ntp_update Device synchronizes its time to the NTP server. -------------------- RESULT pass connection.network.ntp_update Device clock synchronized. +-------------------- +connection.mac_oui +-------------------- +Check Physical device address OUI against IEEE registration and verify it is registered with the correct manufacturer +-------------------- +Using the host hardware address 9a:02:57:1e:8f:01 +Mac OUI Test +-------------------- +RESULT fail connection.mac_oui Manufacturer prefix not found! + ``` #### Module Config diff --git a/resources/device_types/deltacontrols_o3-din-cpu/module_config.json b/resources/device_types/deltacontrols_o3-din-cpu/module_config.json index a17a5a6997..6859207787 100644 --- a/resources/device_types/deltacontrols_o3-din-cpu/module_config.json +++ b/resources/device_types/deltacontrols_o3-din-cpu/module_config.json @@ -15,18 +15,12 @@ "bacnet": { "enabled": true }, - "macoui": { - "enabled": true - }, "mudgee": { "enabled": true }, "nmap": { "enabled": true }, - "ntp": { - "enabled": true - }, "switch": { "enabled": true, "poe": { diff --git a/resources/device_types/distech_ecy-s1000/module_config.json b/resources/device_types/distech_ecy-s1000/module_config.json index b9a1847754..09e9fd37b9 100644 --- a/resources/device_types/distech_ecy-s1000/module_config.json +++ b/resources/device_types/distech_ecy-s1000/module_config.json @@ -15,18 +15,12 @@ "bacnet": { "enabled": true }, - "macoui": { - "enabled": true - }, "mudgee": { "enabled": true }, "nmap": { "enabled": true }, - "ntp": { - "enabled": true - }, "switch": { "enabled": true, "poe": { diff --git a/resources/setups/baseline/module_config.json b/resources/setups/baseline/module_config.json index be0cb97454..a6c53b8ba0 100644 --- a/resources/setups/baseline/module_config.json +++ b/resources/setups/baseline/module_config.json @@ -12,9 +12,6 @@ "nmap": { "enabled": true }, - "macoui": { - "enabled": true - }, "switch": { "enabled": true }, @@ -35,9 +32,6 @@ }, "network": { "enabled": true - }, - "ntp": { - "enabled": true } } } diff --git a/resources/setups/qualification/device_module_config.json b/resources/setups/qualification/device_module_config.json index 9713c5723b..131348b856 100644 --- a/resources/setups/qualification/device_module_config.json +++ b/resources/setups/qualification/device_module_config.json @@ -30,18 +30,12 @@ "ipaddr": { "timeout_sec": 120 }, - "macoui": { - "enabled": true - }, "mudgee": { "enabled": true }, "nmap": { "enabled": true }, - "ntp": { - "enabled": true - }, "switch": { "enabled": true, "poe": { diff --git a/resources/setups/qualification/device_type_module_config.json b/resources/setups/qualification/device_type_module_config.json index 9d3181460b..0401a128b7 100644 --- a/resources/setups/qualification/device_type_module_config.json +++ b/resources/setups/qualification/device_type_module_config.json @@ -24,16 +24,13 @@ "ipaddr": { "timeout_sec": 120 }, - "macoui": { - "enabled": true - }, "mudgee": { "enabled": true }, - "nmap": { + "network": { "enabled": true }, - "ntp": { + "nmap": { "enabled": true }, "switch": { diff --git a/resources/setups/qualification/system_module_config.json b/resources/setups/qualification/system_module_config.json index be6d1bf2ef..1cc6fd9835 100644 --- a/resources/setups/qualification/system_module_config.json +++ b/resources/setups/qualification/system_module_config.json @@ -15,16 +15,13 @@ "ipaddr": { "timeout_sec": 120 }, - "macoui": { - "enabled": true - }, "mudgee": { "enabled": true }, - "nmap": { + "network": { "enabled": true }, - "ntp": { + "nmap": { "enabled": true }, "switch": { diff --git a/resources/setups/remediation/device_module_config.json b/resources/setups/remediation/device_module_config.json index 65223dac27..1d14c6f7aa 100644 --- a/resources/setups/remediation/device_module_config.json +++ b/resources/setups/remediation/device_module_config.json @@ -26,16 +26,13 @@ "ipaddr": { "timeout_sec": 120 }, - "macoui": { - "enabled": true - }, "mudgee": { "enabled": true }, - "nmap": { + "network": { "enabled": true }, - "ntp": { + "nmap": { "enabled": true }, "switch": { diff --git a/resources/setups/remediation/system_module_config.json b/resources/setups/remediation/system_module_config.json index 58fb3fa9f4..e7542de45d 100644 --- a/resources/setups/remediation/system_module_config.json +++ b/resources/setups/remediation/system_module_config.json @@ -15,16 +15,13 @@ "ipaddr": { "timeout_sec": 120 }, - "macoui": { - "enabled": true - }, "mudgee": { "enabled": true }, - "nmap": { + "network": { "enabled": true }, - "ntp": { + "nmap": { "enabled": true }, "switch": { diff --git a/resources/test_site/mac_addrs/3c5ab41e8f0b/module_config.json b/resources/test_site/mac_addrs/3c5ab41e8f0b/module_config.json index c999dd7e16..bb981518eb 100644 --- a/resources/test_site/mac_addrs/3c5ab41e8f0b/module_config.json +++ b/resources/test_site/mac_addrs/3c5ab41e8f0b/module_config.json @@ -3,10 +3,6 @@ "modules": { "hold": { "enabled": true - }, - "macoui": { - "enabled": true, - "timeout_sec": 1 } } } diff --git a/resources/test_site/module_config.json b/resources/test_site/module_config.json index 7971fca2a4..03f7d504d0 100644 --- a/resources/test_site/module_config.json +++ b/resources/test_site/module_config.json @@ -18,9 +18,6 @@ "manual": { "enabled": true }, - "ntp": { - "enabled": true - }, "ssh": { "enabled": false } diff --git a/subset/connection/Dockerfile.test_macoui b/subset/connection/Dockerfile.test_macoui deleted file mode 100644 index 6624495d00..0000000000 --- a/subset/connection/Dockerfile.test_macoui +++ /dev/null @@ -1,17 +0,0 @@ -FROM daqf/aardvark:latest - -RUN $AG update && $AG install openjdk-8-jre - -RUN $AG update && $AG install openjdk-8-jdk git - -RUN $AG update && $AG install curl - -COPY subset/connection/ . - -RUN mkdir -p mac_oui/src/main/resources - -RUN curl https://svn.nmap.org/nmap/nmap-mac-prefixes > mac_oui/src/main/resources/macList.txt - -RUN cd mac_oui && ./gradlew shadowJar - -CMD ["./test_macoui"] diff --git a/subset/connection/build.conf b/subset/connection/build.conf deleted file mode 100644 index 5c585856af..0000000000 --- a/subset/connection/build.conf +++ /dev/null @@ -1,2 +0,0 @@ -build subset/connection -add macoui diff --git a/subset/connection/mac_oui/.project b/subset/connection/mac_oui/.project deleted file mode 100644 index cd2d52f077..0000000000 --- a/subset/connection/mac_oui/.project +++ /dev/null @@ -1,23 +0,0 @@ - - - mac_oui - Project mac_oui created by Buildship. - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.buildship.core.gradleprojectbuilder - - - - - - org.eclipse.jdt.core.javanature - org.eclipse.buildship.core.gradleprojectnature - - diff --git a/subset/connection/readme.md b/subset/connection/readme.md deleted file mode 100644 index f1166e933c..0000000000 --- a/subset/connection/readme.md +++ /dev/null @@ -1,20 +0,0 @@ -# Connection testing - -## test_macoui -The MAC OUI test looks up the manufacturer information for the mac address of the device under test. - -### Note for test developers -The functional test code is included in the `mac_oui/src/main/java` folder. - -The `macList.txt` file containing the MAC OUI database is downloaded at build time by the container specified in -the `Dockerfile.test_macoui` file. - -If java code requires debugging in an IDE, then it will require the `macList.txt` to be placed under the -`mac_oui/src/main/resources/` folder. Use the curl command from the `Dockerfile.test_macoui` file to download and -place the file locally into your project. This `.txt` file is git ignored to avoid being included as a -static resource on the source code repo. - -### Conditions for mac_oui - - pass -> if the MAC OUI matches the mac prefix IEEE registration. - - fail -> if the MAC OUI does not match with any of the mac prefixes. - diff --git a/subset/network/Dockerfile.test_network b/subset/network/Dockerfile.test_network index fbbb2fdec7..ef4b204207 100644 --- a/subset/network/Dockerfile.test_network +++ b/subset/network/Dockerfile.test_network @@ -1,8 +1,21 @@ FROM daqf/aardvark:latest -RUN $AG update && $AG install python netcat +RUN $AG update && $AG install openjdk-8-jre -COPY subset/network/network_tests.py . -COPY subset/network/test_network . +RUN $AG update && $AG install openjdk-8-jdk git + +RUN $AG update && $AG install python python-setuptools python-pip netcat + +RUN $AG update && $AG install curl + +RUN pip install scapy + +COPY subset/network/ . + +RUN mkdir -p mac_oui/src/main/resources + +RUN curl https://svn.nmap.org/nmap/nmap-mac-prefixes > mac_oui/src/main/resources/macList.txt + +RUN cd mac_oui && ./gradlew shadowJar CMD ["./test_network"] diff --git a/subset/network/NTPClient/gradle/wrapper/gradle-wrapper.properties b/subset/network/NTPClient/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index bb8b2fc26b..0000000000 --- a/subset/network/NTPClient/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-bin.zip -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/subset/network/NTPClient/src/main/java/Main.java b/subset/network/NTPClient/src/main/java/Main.java deleted file mode 100644 index b9e53b2833..0000000000 --- a/subset/network/NTPClient/src/main/java/Main.java +++ /dev/null @@ -1,81 +0,0 @@ -import java.io.IOException; -import java.net.*; -import java.text.DecimalFormat; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - - -public class Main { - static final double SECONDS_FROM_01_01_1900_TO_01_01_1970 = 2208988800.0; - static String serverName = "time.google.com"; - static int PORT = 123; - static int timerPeriod = 10; - - public static void main(String[] args) { - if (args.length < 2) { - throw new IllegalArgumentException("Usage: server_name port timerPeriod"); - } - serverName = args[0]; - PORT = Integer.parseInt(args[1]); - timerPeriod = Integer.parseInt(args[2]); - - Runnable senderRunnable = new Runnable() { - @Override - public void run() { - try { - sendRequest(); - } catch (IOException e) { - System.out.println(e.getMessage()); - } - } - }; - ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); - executor.scheduleAtFixedRate(senderRunnable, 0, timerPeriod, TimeUnit.SECONDS); - } - - private static void sendRequest() throws IOException { - // Send request - DatagramSocket socket = new DatagramSocket(); - InetAddress address = InetAddress.getByName(serverName); - byte[] buf = new NtpMessage(SECONDS_FROM_01_01_1900_TO_01_01_1970).toByteArray(); - DatagramPacket packet = - new DatagramPacket(buf, buf.length, address, PORT); - - // Set the transmit timestamp *just* before sending the packet - NtpMessage.encodeTimestamp(packet.getData(), 40, - (System.currentTimeMillis() / 1000.0) + SECONDS_FROM_01_01_1900_TO_01_01_1970); - sendPacket(socket, packet, buf); - } - - private static void sendPacket(DatagramSocket socket, DatagramPacket packet, byte[] buf) throws IOException { - socket.send(packet); - - // Get response - System.out.println("NTP request sent, waiting for response...\n"); - packet = new DatagramPacket(buf, buf.length); - socket.receive(packet); - - // Immediately record the incoming timestamp - double destinationTimestamp = - (System.currentTimeMillis() / 1000.0) + SECONDS_FROM_01_01_1900_TO_01_01_1970; - - // Process response - NtpMessage msg = new NtpMessage(packet.getData()); - double roundTripDelay = (destinationTimestamp-msg.originateTimestamp) - - (msg.transmitTimestamp-msg.receiveTimestamp); - double localClockOffset = - ((msg.receiveTimestamp - msg.originateTimestamp) + - (msg.transmitTimestamp - destinationTimestamp)) / 2; - - // Display response - System.out.println("NTP server: " + serverName); - System.out.println(msg.toString()); - System.out.println("Dest. timestamp: " + - NtpMessage.timestampToString(destinationTimestamp)); - System.out.println("Round-trip delay: " + - new DecimalFormat("0.00").format(roundTripDelay * 1000) + " ms"); - System.out.println("Local clock offset: " + - new DecimalFormat("0.00").format(localClockOffset * 1000) + " ms"); - } -} diff --git a/subset/network/NTPClient/src/main/java/NtpMessage.java b/subset/network/NTPClient/src/main/java/NtpMessage.java deleted file mode 100644 index cfea458b1e..0000000000 --- a/subset/network/NTPClient/src/main/java/NtpMessage.java +++ /dev/null @@ -1,206 +0,0 @@ -import java.text.DecimalFormat; -import java.text.SimpleDateFormat; -import java.util.Date; - -public class NtpMessage { - public byte leapIndicator = 0; - public byte version = 3; - public byte mode = 0; - public short stratum = 0; - public byte pollInterval = 0; - public byte precision = 0; - public double rootDelay = 0; - public double rootDispersion = 0; - public byte[] referenceIdentifier = {0, 0, 0, 0}; - public double referenceTimestamp = 0; - public double originateTimestamp = 0; - public double receiveTimestamp = 0; - public double transmitTimestamp = 0; - - /** - * Constructs a new NtpMessage from an array of bytes. - */ - public NtpMessage(byte[] array) { - // See the packet format diagram in RFC 2030 for details - leapIndicator = (byte)((array[0] >> 6) & 0x3); - version = (byte)((array[0] >> 3) & 0x7); - mode = (byte)(array[0] & 0x7); - stratum = unsignedByteToShort(array[1]); - pollInterval = array[2]; - precision = array[3]; - - rootDelay = (array[4] * 256.0) + - unsignedByteToShort(array[5]) + - (unsignedByteToShort(array[6]) / 256.0) + - (unsignedByteToShort(array[7]) / 65536.0); - - rootDispersion = (unsignedByteToShort(array[8]) * 256.0) + - unsignedByteToShort(array[9]) + - (unsignedByteToShort(array[10]) / 256.0) + - (unsignedByteToShort(array[11]) / 65536.0); - - referenceIdentifier[0] = array[12]; - referenceIdentifier[1] = array[13]; - referenceIdentifier[2] = array[14]; - referenceIdentifier[3] = array[15]; - - referenceTimestamp = decodeTimestamp(array, 16); - originateTimestamp = decodeTimestamp(array, 24); - receiveTimestamp = decodeTimestamp(array, 32); - transmitTimestamp = decodeTimestamp(array, 40); - } - - /** - * Constructs a new NtpMessage in client -> server mode, and sets the - * transmit timestamp to the current time. - */ - public NtpMessage(double SECONDS_FROM_01_01_1900_TO_01_01_1970) { - this.mode = 3; - this.transmitTimestamp = (System.currentTimeMillis() / 1000.0) + SECONDS_FROM_01_01_1900_TO_01_01_1970; - } - - /** - * This method constructs the data bytes of a raw NTP packet. - */ - public byte[] toByteArray() { - // All bytes are automatically set to 0 - byte[] p = new byte[48]; - - p[0] = (byte)(leapIndicator << 6 | version << 3 | mode); - p[1] = (byte)stratum; - p[2] = (byte)pollInterval; - p[3] = (byte)precision; - - // root delay is a signed 16.16-bit FP, in Java an int is 32-bits - int l = (int)(rootDelay * 65536.0); - p[4] = (byte)((l >> 24) & 0xFF); - p[5] = (byte)((l >> 16) & 0xFF); - p[6] = (byte)((l >> 8) & 0xFF); - p[7] = (byte)(l & 0xFF); - - // root dispersion is an unsigned 16.16-bit FP, in Java there are no - // unsigned primitive types, so we use a long which is 64-bits - long ul = (long)(rootDispersion * 65536.0); - p[8] = (byte)((ul >> 24) & 0xFF); - p[9] = (byte)((ul >> 16) & 0xFF); - p[10] = (byte)((ul >> 8) & 0xFF); - p[11] = (byte)(ul & 0xFF); - - p[12] = referenceIdentifier[0]; - p[13] = referenceIdentifier[1]; - p[14] = referenceIdentifier[2]; - p[15] = referenceIdentifier[3]; - - encodeTimestamp(p, 16, referenceTimestamp); - encodeTimestamp(p, 24, originateTimestamp); - encodeTimestamp(p, 32, receiveTimestamp); - encodeTimestamp(p, 40, transmitTimestamp); - - return p; - } - - /** - * Returns a string representation of a NtpMessage - */ - public String toString() { - String precisionStr = - new DecimalFormat("0.#E0").format(Math.pow(2, precision)); - - return "Leap indicator: " + leapIndicator + "\n" + - "Version: " + version + "\n" + - "Mode: " + mode + "\n" + - "Stratum: " + stratum + "\n" + - "Poll: " + pollInterval + "\n" + - "Precision: " + precision + " (" + precisionStr + " seconds)\n" + - "Root delay: " + new DecimalFormat("0.00").format(rootDelay * 1000) + " ms\n" + - "Root dispersion: " + new DecimalFormat("0.00").format(rootDispersion * 1000) + " ms\n" + - "Reference identifier: " + referenceIdentifierToString(referenceIdentifier, stratum, version) + "\n" + - "Reference timestamp: " + timestampToString(referenceTimestamp) + "\n" + - "Originate timestamp: " + timestampToString(originateTimestamp) + "\n" + - "Receive timestamp: " + timestampToString(receiveTimestamp) + "\n" + - "Transmit timestamp: " + timestampToString(transmitTimestamp); - } - - /** - * Converts an unsigned byte to a short. By default, Java assumes that - * a byte is signed. - */ - public static short unsignedByteToShort(byte b) { - if((b & 0x80) == 0x80) return (short)(128 + (b & 0x7f)); - else return (short)b; - } - - /** - * Will read 8 bytes of a message beginning at pointer - * and return it as a double, according to the NTP 64-bit timestamp - * format. - */ - public static double decodeTimestamp(byte[] array, int pointer) { - double r = 0.0; - - for(int i = 0; i < 8; i++) - { - r += unsignedByteToShort(array[pointer + i]) * Math.pow(2, (3 - i) * 8); - } - - return r; - } - - /** - * Encodes a timestamp in the specified position in the message - */ - public static void encodeTimestamp(byte[] array, int pointer, double timestamp) { - // Converts a double into a 64-bit fixed point - for(int i = 0; i < 8; i++) { - // 2^24, 2^16, 2^8, .. 2^-32 - double base = Math.pow(2, (3 - i) * 8); - // Capture byte value - array[pointer + i] = (byte)(timestamp / base); - // Subtract captured value from remaining total - timestamp = timestamp - (double)(unsignedByteToShort(array[pointer + i]) * base); - } - array[7] = (byte)(Math.random() * 255.0); - } - - /** - * Returns a timestamp (number of seconds since 00:00 1-Jan-1900) as a - * formatted date/time string. - */ - public static String timestampToString(double timestamp) { - if(timestamp == 0) return "0"; - double utc = timestamp - (2208988800.0); - long ms = (long)(utc * 1000.0); - String date = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss").format(new Date(ms)); - double fraction = timestamp - ((long)timestamp); - String fractionSting = new DecimalFormat(".000000").format(fraction); - return date + fractionSting; - } - - /** - * Returns a string representation of a reference identifier according - * to the rules set out in RFC 2030. - */ - public static String referenceIdentifierToString(byte[] ref, short stratum, byte version) { - if(stratum == 0 || stratum == 1) - { - return new String(ref); - } - else if(version == 3) - { - return unsignedByteToShort(ref[0]) + "." + - unsignedByteToShort(ref[1]) + "." + - unsignedByteToShort(ref[2]) + "." + - unsignedByteToShort(ref[3]); - } - // In NTP Version 4 secondary servers, this is the low order 32 bits - // of the latest transmit timestamp of the reference source. - else if(version == 4) - { - return "" + ((unsignedByteToShort(ref[0]) / 256.0) + - (unsignedByteToShort(ref[1]) / 65536.0) + - (unsignedByteToShort(ref[2]) / 16777216.0) + - (unsignedByteToShort(ref[3]) / 4294967296.0)); - } - return ""; - } -} diff --git a/subset/network/README.md b/subset/network/README.md new file mode 100644 index 0000000000..d4868e113d --- /dev/null +++ b/subset/network/README.md @@ -0,0 +1,67 @@ +# Network Tests + +## General Network Tests + +### connection.min_send +- Located in network_tests.py, started up in test_network. +- Check if a device sends any data packet at a frequency of less than five minutes. + +#### Result cases: +- PASS: The time between packets is measured - pass if time between any two packets is less than five minutes (deals with case where a monitor scan is long) +- FAIL: If data packets are sent, and there are packets with time interval of less than five minutes found, then fail. +- SKIP: If no data packets are sent and the monitor scan period is short, the test will skip instead of failing. + +### communication.type.broadcast +- Located in network_tests.py, started up in test_network. +- This test counts the number of unicast, broadcast and multicast packets sent out by reading from the .pcap file that DAQ has created during runtime. + +#### Result cases: +This is an 'info' test, it does not have a pass/fail/skip case. + + +## NTP Tests +The NTP tests inspect the client NTP version and the device's ability to update its clock precisely. + +### Note for test developers +The functional test code is included in the `ntp_tests.py` file. + +The test reads packets from startup.pcap and monitor.pcap. + +If the python code needs debugging, the pip module `scapy` is required (`pip install scapy`). + +### NTP Test conditions +| Test ID | Info | Pass | Fail | Skip | +|---|---|---|---|---| +| connection.network.ntp_support | Are the received NTP packets using NTP v4? | NTP version is 4 | NTP version is not 4 | No NTP packets are received | +| connection.network.ntp_update | Does the device demonstrate updating its clock using NTP? | Device clock is synchronized | Device clock is not synchronized | Not enough NTP packets are received | + +#### NTP Support #### +The version of NTP used by the client is extracted from the fist client (outbound) NTP packets discovered in startup.pcap. + +#### NTP Update #### +The following criteria are used to determine whether a DUT has synced its clock with the NTP server provided by DAQ: + - A minimum of 2 NTP packets are present in startup.pcap and monitor.pcap (one potential poll). + - A minimum of 2 NTP packets have been exchanged between the DUT and the DAQ-provided NTP server. + - A valid NTP poll is present. Consisting of a client-server exchange. + - The calculated offset is less than 0.128 seconds and the final poll does not have a leap indicator of 3 (unsynchronized). + +When calculating the offset, the latest valid poll is inspected. A value of 0.128s is the maximum offset used to determine whether a device is considered in-sync with the NTP server because NTPv4 is capable of accuracy of tens of milliseconds. + + +## MAC OUI +The MAC OUI test looks up the manufacturer information for the mac address of the device under test. + +### Note for test developers +The functional test code is included in the `mac_oui/src/main/java` folder. + +The `macList.txt` file containing the MAC OUI database is downloaded at build time by the container specified in +the `Dockerfile.test_macoui` file. + +If java code requires debugging in an IDE, then it will require the `macList.txt` to be placed under the +`mac_oui/src/main/resources/` folder. Use the curl command from the `Dockerfile.test_macoui` file to download and +place the file locally into your project. This `.txt` file is git ignored to avoid being included as a +static resource on the source code repo. + +### Conditions for mac_oui + - pass -> if the MAC OUI matches the mac prefix IEEE registration. + - fail -> if the MAC OUI does not match with any of the mac prefixes. diff --git a/subset/network/debug_generate_capture.py b/subset/network/debug_generate_capture.py deleted file mode 100644 index 410837145f..0000000000 --- a/subset/network/debug_generate_capture.py +++ /dev/null @@ -1,20 +0,0 @@ -import subprocess -import time -import sys - -arguments = sys.argv - -capture_time = int(arguments[1]) -eth_interface = arguments[2] - -cap_pcap_file = 'capture.pcap' - -tcpdump_capture_unlimited_byte_packets = 'tcpdump -i {e} -s0 -w {c}'.format(e=eth_interface, c=cap_pcap_file) - -def shell_command_without_result(command, wait_time, terminate_flag): - process = subprocess.Popen(command, universal_newlines=True, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - time.sleep(wait_time) - if terminate_flag: - process.terminate() - -shell_command_without_result(tcpdump_capture_unlimited_byte_packets, capture_time, True) diff --git a/subset/connection/mac_oui/.classpath b/subset/network/mac_oui/.classpath similarity index 100% rename from subset/connection/mac_oui/.classpath rename to subset/network/mac_oui/.classpath diff --git a/subset/connection/mac_oui/.gitignore b/subset/network/mac_oui/.gitignore similarity index 100% rename from subset/connection/mac_oui/.gitignore rename to subset/network/mac_oui/.gitignore diff --git a/subset/connection/mac_oui/.settings/org.eclipse.buildship.core.prefs b/subset/network/mac_oui/.settings/org.eclipse.buildship.core.prefs similarity index 100% rename from subset/connection/mac_oui/.settings/org.eclipse.buildship.core.prefs rename to subset/network/mac_oui/.settings/org.eclipse.buildship.core.prefs diff --git a/subset/connection/mac_oui/build.gradle b/subset/network/mac_oui/build.gradle similarity index 100% rename from subset/connection/mac_oui/build.gradle rename to subset/network/mac_oui/build.gradle diff --git a/subset/connection/mac_oui/gradle/wrapper/gradle-wrapper.jar b/subset/network/mac_oui/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from subset/connection/mac_oui/gradle/wrapper/gradle-wrapper.jar rename to subset/network/mac_oui/gradle/wrapper/gradle-wrapper.jar diff --git a/subset/connection/mac_oui/gradle/wrapper/gradle-wrapper.properties b/subset/network/mac_oui/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from subset/connection/mac_oui/gradle/wrapper/gradle-wrapper.properties rename to subset/network/mac_oui/gradle/wrapper/gradle-wrapper.properties diff --git a/subset/connection/mac_oui/gradlew b/subset/network/mac_oui/gradlew similarity index 100% rename from subset/connection/mac_oui/gradlew rename to subset/network/mac_oui/gradlew diff --git a/subset/connection/mac_oui/gradlew.bat b/subset/network/mac_oui/gradlew.bat similarity index 100% rename from subset/connection/mac_oui/gradlew.bat rename to subset/network/mac_oui/gradlew.bat diff --git a/subset/connection/mac_oui/mac_oui.iml b/subset/network/mac_oui/mac_oui.iml similarity index 100% rename from subset/connection/mac_oui/mac_oui.iml rename to subset/network/mac_oui/mac_oui.iml diff --git a/subset/connection/mac_oui/settings.gradle b/subset/network/mac_oui/settings.gradle similarity index 100% rename from subset/connection/mac_oui/settings.gradle rename to subset/network/mac_oui/settings.gradle diff --git a/subset/connection/mac_oui/src/main/java/MacLookup.java b/subset/network/mac_oui/src/main/java/MacLookup.java similarity index 100% rename from subset/connection/mac_oui/src/main/java/MacLookup.java rename to subset/network/mac_oui/src/main/java/MacLookup.java diff --git a/subset/connection/mac_oui/src/main/java/Main.java b/subset/network/mac_oui/src/main/java/Main.java similarity index 100% rename from subset/connection/mac_oui/src/main/java/Main.java rename to subset/network/mac_oui/src/main/java/Main.java diff --git a/subset/connection/mac_oui/src/main/java/ReportHandler.java b/subset/network/mac_oui/src/main/java/ReportHandler.java similarity index 91% rename from subset/connection/mac_oui/src/main/java/ReportHandler.java rename to subset/network/mac_oui/src/main/java/ReportHandler.java index 3f85070b5c..6b691cbfd4 100644 --- a/subset/connection/mac_oui/src/main/java/ReportHandler.java +++ b/subset/network/mac_oui/src/main/java/ReportHandler.java @@ -5,7 +5,7 @@ public class ReportHandler { String report = "Mac OUI Test\n"; - File reportFile = new File("report/report.txt"); + File reportFile = new File("/report/macoui.txt"); public void addText(String text) { report += text + '\n'; diff --git a/subset/connection/mac_oui/src/main/java/RetrieveList.java b/subset/network/mac_oui/src/main/java/RetrieveList.java similarity index 100% rename from subset/connection/mac_oui/src/main/java/RetrieveList.java rename to subset/network/mac_oui/src/main/java/RetrieveList.java diff --git a/subset/network/network_tests.py b/subset/network/network_tests.py index d785debc67..8fafee8856 100644 --- a/subset/network/network_tests.py +++ b/subset/network/network_tests.py @@ -1,3 +1,14 @@ +""" + This script can be called to run a specific network module test. + Currently supports: + - connection.min_send + - connection.dhcp_long + - protocol.app_min_send + - communication.type.broadcast + - network.ntp.support + Usage: python network_tests.py + E.g. python network_tests.py connection.min_send $MONITOR $TARGET_IP +""" import subprocess, time, sys, json import re @@ -9,11 +20,7 @@ cap_pcap_file = str(arguments[2]) device_address = str(arguments[3]) -if test_request == 'protocol.app_min_send': - module_config = str(arguments[4]) - infastructure_excludes = str(arguments[5]) - -report_filename = 'report.txt' +report_filename = 'network_tests.txt' min_packet_length_bytes = 20 max_packets_in_report = 10 port_list = [] @@ -21,18 +28,16 @@ summary_text = '' result = 'fail' dash_break_line = '--------------------\n' + description_min_send = 'Device sends data at a frequency of less than 5 minutes.' -description_dhcp_long = 'Device sends ARP request on DHCP lease expiry.' -description_app_min_send = 'Device sends application packets at a frequency of less than 5 minutes.' description_communication_type = 'Device sends unicast or broadcast packets.' -description_ntp_support = 'Device sends NTP request packets.' tcpdump_display_all_packets = 'tcpdump -tttt -n src host ' + device_address + ' -r ' + cap_pcap_file tcpdump_display_udp_bacnet_packets = 'tcpdump -n udp dst portrange 47808-47809 -r ' + cap_pcap_file tcpdump_display_arp_packets = 'tcpdump arp -n src host ' + device_address + ' -r ' + cap_pcap_file -tcpdump_display_ntp_packets = 'tcpdump dst port 123 -r ' + cap_pcap_file -tcpdump_display_eapol_packets = 'tcpdump port 1812 or port 1813 or port 3799 -r ' + cap_pcap_file + tcpdump_display_broadcast_packets = 'tcpdump broadcast and src host ' + device_address + ' -r ' + cap_pcap_file +tcpdump_display_multicast_packets = 'tcpdump -n \'ip[16] & 240 = 224\' -r ' + cap_pcap_file system_conf_file = "/config/inst/system.conf" tcpdump_date_format = "%Y-%m-%d %H:%M:%S.%f" @@ -44,6 +49,7 @@ def write_report(string_to_append): with open(report_filename, 'a+') as file_open: file_open.write(string_to_append) + def shell_command_with_result(command, wait_time, terminate_flag): process = subprocess.Popen(command, universal_newlines=True, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) text = process.stdout.read() @@ -53,8 +59,10 @@ def shell_command_with_result(command, wait_time, terminate_flag): process.terminate() return str(text) + def add_packet_count_to_report(packet_type, packet_count): - write_report("{i} {t} Packets recieved={p}\n".format(i=ignore, t=packet_type, p=packet_count)) + write_report("{i} {t} packets received={p}\n".format(i=ignore, t=packet_type, p=packet_count)) + def add_packet_info_to_report(packets_received): packet_list = packets_received.strip().split("\n") @@ -63,6 +71,7 @@ def add_packet_info_to_report(packets_received): write_report("{i} {p}\n".format(i=ignore, p=packet_list[x])) write_report("{i} packets_count={p}\n".format(i=ignore, p=len(packet_list))) + def decode_shell_result(shell_result): if len(shell_result) > min_packet_length_bytes: packet_request_list = shell_result.rstrip().split("\n") @@ -70,43 +79,13 @@ def decode_shell_result(shell_result): return packets_received return 0 + def packets_received_count(shell_result): if shell_result is None: return 0 else: return decode_shell_result(shell_result) -def load_json_config(json_filename): - with open(json_filename, 'r') as json_file: - return json.load(json_file) - -def add_to_port_list(port_map): - global port_list - for port, port_info in port_map.items(): - for key, value in port_info.items(): - if key == 'allowed': - if value == True: - port_list.append(port) - -def remove_from_port_list(port_map): - global port_list - for exclude in port_map: - for port in port_list: - if port == exclude: - port_list.remove(exclude) - -def decode_json_config(config_file, map_name, action): - dictionary = load_json_config(config_file) - for key, value in dictionary.items(): - if key == map_name: - for protocol, info in value.items(): - if protocol == 'udp' or protocol == 'tcp': - for ports, port_map in info.items(): - if action == 'add': - add_to_port_list(port_map) - elif action == 'remove': - remove_from_port_list(port_map) - def get_scan_length(config_file): """ Gets length of the monitor.pcap scan @@ -137,6 +116,12 @@ def get_scan_length(config_file): write_report("Error encountered reading system.conf {}".format(e)) return False + +def add_summary(text): + global summary_text + summary_text = summary_text + " " + text if summary_text else text + + def test_connection_min_send(): """ Runs the connection.min_send test @@ -197,84 +182,40 @@ def test_connection_min_send(): min_send_duration) return 'pass' -def test_connection_dhcp_long(): - shell_result = shell_command_with_result(tcpdump_display_arp_packets, 0, False) - arp_packets_received = packets_received_count(shell_result) - if arp_packets_received > 0: - add_summary("ARP packets received.") - add_packet_info_to_report(shell_result) - return 'pass' - else: - return 'fail' -def test_protocol_app_min_send(): - """ - reads module_config json file and adds ports to port_list - read infastructure_excludes json file and removes ports from port_list (temporarily commented) +def test_communication_type_broadcast(): + """ Runs the communication.type.broadcast DAQ test. + Counts the number of unicast, broadcast and multicast packets sent. """ - decode_json_config(module_config, 'servers', 'add') - print('port_list:') - app_packets_received = 0 - for port in port_list: - try: - tcpdump_command = 'tcpdump port {p} -r {c}'.format(p=port, c=cap_pcap_file) - shell_result = shell_command_with_result(tcpdump_command, 2, False) - for_port = packets_received_count(shell_result) - app_packets_received += for_port - print('app_packets_received', port, for_port) - add_packet_info_to_report(shell_result) - except Exception as e: - print(e) - print('app_packets_received', app_packets_received) - if app_packets_received > 0: - add_summary("Application packets received.") - return 'pass' - else: - return 'fail' -def test_communication_type_broadcast(): - shell_result = shell_command_with_result(tcpdump_display_broadcast_packets, 0, False) - broadcast_packets_received = packets_received_count(shell_result) - if broadcast_packets_received > 0: + broadcast_result = shell_command_with_result(tcpdump_display_broadcast_packets, 0, False) + broadcast_packets = packets_received_count(broadcast_result) + if broadcast_packets > 0: add_summary("Broadcast packets received.") - add_packet_count_to_report("Broadcast", broadcast_packets_received) - shell_result = shell_command_with_result(tcpdump_display_all_packets, 0, False) - all_packets_received = packets_received_count(shell_result) - if (all_packets_received - broadcast_packets_received) > 0: + add_packet_count_to_report("Broadcast", broadcast_packets) + + multicast_result = shell_command_with_result(tcpdump_display_multicast_packets, 0, False) + multicast_packets = packets_received_count(multicast_result) + if multicast_packets > 0: + add_summary("Multicast packets received.") + add_packet_count_to_report("Multicast", multicast_packets) + + unicast_result = shell_command_with_result(tcpdump_display_all_packets, 0, False) + unicast_packets = packets_received_count(unicast_result) - broadcast_packets - multicast_packets + if unicast_packets > 0: add_summary("Unicast packets received.") - add_packet_count_to_report("Unicast", all_packets_received - broadcast_packets_received) - return 'info' + add_packet_count_to_report("Unicast", unicast_packets) -def test_ntp_support(): - shell_result = shell_command_with_result(tcpdump_display_ntp_packets, 0, False) - ntp_packets_received = packets_received_count(shell_result) - if ntp_packets_received > 0: - add_summary("NTP packets received.") - add_packet_info_to_report(shell_result) - return 'pass' - else: - return 'fail' + return 'info' -def add_summary(text): - global summary_text - summary_text = summary_text + " " + text if summary_text else text write_report("{b}{t}\n{b}".format(b=dash_break_line, t=test_request)) if test_request == 'connection.min_send': write_report("{d}\n{b}".format(b=dash_break_line, d=description_min_send)) result = test_connection_min_send() -elif test_request == 'connection.dhcp_long': - write_report("{d}\n{b}".format(b=dash_break_line, d=description_dhcp_long)) - result = test_connection_dhcp_long() -elif test_request == 'protocol.app_min_send': - write_report("{d}\n{b}".format(b=dash_break_line, d=description_app_min_send)) - result = test_protocol_app_min_send() elif test_request == 'communication.type.broadcast': write_report("{d}\n{b}".format(b=dash_break_line, d=description_communication_type)) result = test_communication_type_broadcast() -elif test_request == 'network.ntp.support': - write_report("{d}\n{b}".format(b=dash_break_line, d=description_ntp_support)) - result = test_ntp_support() write_report("RESULT {r} {t} {s}\n".format(r=result, t=test_request, s=summary_text.strip())) diff --git a/subset/ntp/ntp_tests.py b/subset/network/ntp_tests.py similarity index 99% rename from subset/ntp/ntp_tests.py rename to subset/network/ntp_tests.py index 37430656b6..6d0eb6b13b 100644 --- a/subset/ntp/ntp_tests.py +++ b/subset/network/ntp_tests.py @@ -9,7 +9,7 @@ startup_pcap_file = str(arguments[2]) monitor_pcap_file = str(arguments[3]) -report_filename = 'report.txt' +report_filename = 'ntp_tests.txt' ignore = '%%' summary_text = '' result = 'fail' @@ -27,6 +27,7 @@ OFFSET_ALLOWANCE = 0.128 LEAP_ALARM = 3 + def write_report(string_to_append): with open(report_filename, 'a+') as file_open: file_open.write(string_to_append) diff --git a/subset/connection/test_macoui b/subset/network/run_macoui_test similarity index 89% rename from subset/connection/test_macoui rename to subset/network/run_macoui_test index 8abab5c5ce..fba57c38c6 100755 --- a/subset/connection/test_macoui +++ b/subset/network/run_macoui_test @@ -1,8 +1,10 @@ #!/bin/bash -e source reporting.sh -REPORT=/tmp/report.txt -LOCAL_REPORT=report/report.txt +TARGET_MAC=$1 +REPORT=$2 + +LOCAL_REPORT=/report/macoui.txt CONFIG=/config/device/module_config.json LOG=/tmp/nmap.log RESULT_LINES=/tmp/result_lines.txt @@ -18,8 +20,6 @@ java -jar mac_oui/build/libs/mac_oui-all.jar $TARGET_MAC RESULT_AND_SUMMARY="$(grep "RESULT" $LOCAL_REPORT)" grep -v "RESULT" $LOCAL_REPORT >> $REDACTED_LOG -# For testing module timeout. -sleep 10 TEST_RESULT=$(cat $REDACTED_LOG) diff --git a/subset/network/test_network b/subset/network/test_network index 9e25ef0add..e3a9344ffb 100755 --- a/subset/network/test_network +++ b/subset/network/test_network @@ -2,14 +2,21 @@ REPORT=/tmp/report.txt +STARTUP=/scans/startup.pcap MONITOR=/scans/monitor.pcap -MODULE_CONFIG=/config/device/module_config.json -EXCLUDES=infastructure_excludes.json -python network_tests.py connection.dhcp_long $MONITOR $TARGET_IP +# General Network Tests python network_tests.py connection.min_send $MONITOR $TARGET_IP python network_tests.py communication.type.broadcast $MONITOR $TARGET_IP -python network_tests.py protocol.app_min_send $MONITOR $TARGET_IP $MODULE_CONFIG $EXCLUDES -python network_tests.py network.ntp.support $MONITOR $TARGET_IP -cat report.txt >> $REPORT +cat network_tests.txt >> $REPORT + +# NTP Tests +python ntp_tests.py connection.network.ntp_support $STARTUP $MONITOR +python ntp_tests.py connection.network.ntp_update $STARTUP $MONITOR + +cat ntp_tests.txt >> $REPORT + +# MACOUI Test +./run_macoui_test $TARGET_MAC $REPORT + diff --git a/subset/ntp/Dockerfile.test_ntp b/subset/ntp/Dockerfile.test_ntp deleted file mode 100644 index 017828d203..0000000000 --- a/subset/ntp/Dockerfile.test_ntp +++ /dev/null @@ -1,10 +0,0 @@ -FROM daqf/aardvark:latest - -RUN $AG update && $AG install python python-setuptools python-pip netcat - -RUN pip install scapy - -COPY subset/ntp/test_ntp . -COPY subset/ntp/ntp_tests.py . - -CMD ["./test_ntp"] diff --git a/subset/ntp/NTPClient/.idea/gradle.xml b/subset/ntp/NTPClient/.idea/gradle.xml deleted file mode 100644 index 5c0b931b2c..0000000000 --- a/subset/ntp/NTPClient/.idea/gradle.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/subset/ntp/NTPClient/.idea/jarRepositories.xml b/subset/ntp/NTPClient/.idea/jarRepositories.xml deleted file mode 100644 index fdc392fe87..0000000000 --- a/subset/ntp/NTPClient/.idea/jarRepositories.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/subset/ntp/NTPClient/.idea/misc.xml b/subset/ntp/NTPClient/.idea/misc.xml deleted file mode 100644 index aecc2806d9..0000000000 --- a/subset/ntp/NTPClient/.idea/misc.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/subset/ntp/NTPClient/.idea/vcs.xml b/subset/ntp/NTPClient/.idea/vcs.xml deleted file mode 100644 index c2365ab11f..0000000000 --- a/subset/ntp/NTPClient/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/subset/ntp/NTPClient/build.gradle b/subset/ntp/NTPClient/build.gradle deleted file mode 100644 index 8a3dd211ff..0000000000 --- a/subset/ntp/NTPClient/build.gradle +++ /dev/null @@ -1,22 +0,0 @@ -plugins { - id 'java' -} - -group 'ntp_client' -version '1.0-SNAPSHOT' - -sourceCompatibility = 1.8 - -repositories { - mavenCentral() -} - -dependencies { - testCompile group: 'junit', name: 'junit', version: '4.13' -} - -jar { - manifest { - attributes 'Main-Class': 'Main' - } -} diff --git a/subset/ntp/NTPClient/gradle/wrapper/gradle-wrapper.jar b/subset/ntp/NTPClient/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 87b738cbd051603d91cc39de6cb000dd98fe6b02..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55190 zcmafaW0WS*vSoFbZQHhO+s0S6%`V%vZQJa!ZQHKus_B{g-pt%P_q|ywBQt-*Stldc z$+IJ3?^KWm27v+sf`9-50uuadKtMnL*BJ;1^6ynvR7H?hQcjE>7)art9Bu0Pcm@7C z@c%WG|JzYkP)<@zR9S^iR_sA`azaL$mTnGKnwDyMa;8yL_0^>Ba^)phg0L5rOPTbm7g*YIRLg-2^{qe^`rb!2KqS zk~5wEJtTdD?)3+}=eby3x6%i)sb+m??NHC^u=tcG8p$TzB<;FL(WrZGV&cDQb?O0GMe6PBV=V z?tTO*5_HTW$xea!nkc~Cnx#cL_rrUGWPRa6l+A{aiMY=<0@8y5OC#UcGeE#I>nWh}`#M#kIn-$A;q@u-p71b#hcSItS!IPw?>8 zvzb|?@Ahb22L(O4#2Sre&l9H(@TGT>#Py)D&eW-LNb!=S;I`ZQ{w;MaHW z#to!~TVLgho_Pm%zq@o{K3Xq?I|MVuVSl^QHnT~sHlrVxgsqD-+YD?Nz9@HA<;x2AQjxP)r6Femg+LJ-*)k%EZ}TTRw->5xOY z9#zKJqjZgC47@AFdk1$W+KhTQJKn7e>A&?@-YOy!v_(}GyV@9G#I?bsuto4JEp;5|N{orxi_?vTI4UF0HYcA( zKyGZ4<7Fk?&LZMQb6k10N%E*$gr#T&HsY4SPQ?yerqRz5c?5P$@6dlD6UQwZJ*Je9 z7n-@7!(OVdU-mg@5$D+R%gt82Lt%&n6Yr4=|q>XT%&^z_D*f*ug8N6w$`woqeS-+#RAOfSY&Rz z?1qYa5xi(7eTCrzCFJfCxc%j{J}6#)3^*VRKF;w+`|1n;Xaojr2DI{!<3CaP`#tXs z*`pBQ5k@JLKuCmovFDqh_`Q;+^@t_;SDm29 zCNSdWXbV?9;D4VcoV`FZ9Ggrr$i<&#Dx3W=8>bSQIU_%vf)#(M2Kd3=rN@^d=QAtC zI-iQ;;GMk|&A++W5#hK28W(YqN%?!yuW8(|Cf`@FOW5QbX|`97fxmV;uXvPCqxBD zJ9iI37iV)5TW1R+fV16y;6}2tt~|0J3U4E=wQh@sx{c_eu)t=4Yoz|%Vp<#)Qlh1V z0@C2ZtlT>5gdB6W)_bhXtcZS)`9A!uIOa`K04$5>3&8An+i9BD&GvZZ=7#^r=BN=k za+=Go;qr(M)B~KYAz|<^O3LJON}$Q6Yuqn8qu~+UkUKK~&iM%pB!BO49L+?AL7N7o z(OpM(C-EY753=G=WwJHE`h*lNLMNP^c^bBk@5MyP5{v7x>GNWH>QSgTe5 z!*GPkQ(lcbEs~)4ovCu!Zt&$${9$u(<4@9%@{U<-ksAqB?6F`bQ;o-mvjr)Jn7F&j$@`il1Mf+-HdBs<-`1FahTxmPMMI)@OtI&^mtijW6zGZ67O$UOv1Jj z;a3gmw~t|LjPkW3!EZ=)lLUhFzvO;Yvj9g`8hm%6u`;cuek_b-c$wS_0M4-N<@3l|88 z@V{Sd|M;4+H6guqMm4|v=C6B7mlpP(+It%0E;W`dxMOf9!jYwWj3*MRk`KpS_jx4c z=hrKBkFK;gq@;wUV2eqE3R$M+iUc+UD0iEl#-rECK+XmH9hLKrC={j@uF=f3UiceB zU5l$FF7#RKjx+6!JHMG5-!@zI-eG=a-!Bs^AFKqN_M26%cIIcSs61R$yuq@5a3c3& z4%zLs!g}+C5%`ja?F`?5-og0lv-;(^e<`r~p$x%&*89_Aye1N)9LNVk?9BwY$Y$$F^!JQAjBJvywXAesj7lTZ)rXuxv(FFNZVknJha99lN=^h`J2> zl5=~(tKwvHHvh|9-41@OV`c;Ws--PE%{7d2sLNbDp;A6_Ka6epzOSFdqb zBa0m3j~bT*q1lslHsHqaHIP%DF&-XMpCRL(v;MV#*>mB^&)a=HfLI7efblG z(@hzN`|n+oH9;qBklb=d^S0joHCsArnR1-h{*dIUThik>ot^!6YCNjg;J_i3h6Rl0ji)* zo(tQ~>xB!rUJ(nZjCA^%X;)H{@>uhR5|xBDA=d21p@iJ!cH?+%U|VSh2S4@gv`^)^ zNKD6YlVo$%b4W^}Rw>P1YJ|fTb$_(7C;hH+ z1XAMPb6*p^h8)e5nNPKfeAO}Ik+ZN_`NrADeeJOq4Ak;sD~ zTe77no{Ztdox56Xi4UE6S7wRVxJzWxKj;B%v7|FZ3cV9MdfFp7lWCi+W{}UqekdpH zdO#eoOuB3Fu!DU`ErfeoZWJbWtRXUeBzi zBTF-AI7yMC^ntG+8%mn(I6Dw}3xK8v#Ly{3w3_E?J4(Q5JBq~I>u3!CNp~Ekk&YH` z#383VO4O42NNtcGkr*K<+wYZ>@|sP?`AQcs5oqX@-EIqgK@Pmp5~p6O6qy4ml~N{D z{=jQ7k(9!CM3N3Vt|u@%ssTw~r~Z(}QvlROAkQQ?r8OQ3F0D$aGLh zny+uGnH5muJ<67Z=8uilKvGuANrg@s3Vu_lU2ajb?rIhuOd^E@l!Kl0hYIxOP1B~Q zggUmXbh$bKL~YQ#!4fos9UUVG#}HN$lIkM<1OkU@r>$7DYYe37cXYwfK@vrHwm;pg zbh(hEU|8{*d$q7LUm+x&`S@VbW*&p-sWrplWnRM|I{P;I;%U`WmYUCeJhYc|>5?&& zj}@n}w~Oo=l}iwvi7K6)osqa;M8>fRe}>^;bLBrgA;r^ZGgY@IC^ioRmnE&H4)UV5 zO{7egQ7sBAdoqGsso5q4R(4$4Tjm&&C|7Huz&5B0wXoJzZzNc5Bt)=SOI|H}+fbit z-PiF5(NHSy>4HPMrNc@SuEMDuKYMQ--G+qeUPqO_9mOsg%1EHpqoX^yNd~~kbo`cH zlV0iAkBFTn;rVb>EK^V6?T~t~3vm;csx+lUh_%ROFPy0(omy7+_wYjN!VRDtwDu^h4n|xpAMsLepm% zggvs;v8+isCW`>BckRz1MQ=l>K6k^DdT`~sDXTWQ<~+JtY;I~I>8XsAq3yXgxe>`O zZdF*{9@Z|YtS$QrVaB!8&`&^W->_O&-JXn1n&~}o3Z7FL1QE5R*W2W@=u|w~7%EeC1aRfGtJWxImfY-D3t!!nBkWM> zafu>^Lz-ONgT6ExjV4WhN!v~u{lt2-QBN&UxwnvdH|I%LS|J-D;o>@@sA62@&yew0 z)58~JSZP!(lX;da!3`d)D1+;K9!lyNlkF|n(UduR-%g>#{`pvrD^ClddhJyfL7C-(x+J+9&7EsC~^O`&}V%)Ut8^O_7YAXPDpzv8ir4 zl`d)(;imc6r16k_d^)PJZ+QPxxVJS5e^4wX9D=V2zH&wW0-p&OJe=}rX`*->XT=;_qI&)=WHkYnZx6bLoUh_)n-A}SF_ z9z7agNTM5W6}}ui=&Qs@pO5$zHsOWIbd_&%j^Ok5PJ3yUWQw*i4*iKO)_er2CDUME ztt+{Egod~W-fn^aLe)aBz)MOc_?i-stTj}~iFk7u^-gGSbU;Iem06SDP=AEw9SzuF zeZ|hKCG3MV(z_PJg0(JbqTRf4T{NUt%kz&}4S`)0I%}ZrG!jgW2GwP=WTtkWS?DOs znI9LY!dK+1_H0h+i-_~URb^M;4&AMrEO_UlDV8o?E>^3x%ZJyh$JuDMrtYL8|G3If zPf2_Qb_W+V?$#O; zydKFv*%O;Y@o_T_UAYuaqx1isMKZ^32JtgeceA$0Z@Ck0;lHbS%N5)zzAW9iz; z8tTKeK7&qw!8XVz-+pz>z-BeIzr*#r0nB^cntjQ9@Y-N0=e&ZK72vlzX>f3RT@i7@ z=z`m7jNk!9%^xD0ug%ptZnM>F;Qu$rlwo}vRGBIymPL)L|x}nan3uFUw(&N z24gdkcb7!Q56{0<+zu zEtc5WzG2xf%1<@vo$ZsuOK{v9gx^0`gw>@h>ZMLy*h+6ueoie{D#}}` zK2@6Xxq(uZaLFC%M!2}FX}ab%GQ8A0QJ?&!vaI8Gv=vMhd);6kGguDmtuOElru()) zuRk&Z{?Vp!G~F<1#s&6io1`poBqpRHyM^p;7!+L??_DzJ8s9mYFMQ0^%_3ft7g{PD zZd}8E4EV}D!>F?bzcX=2hHR_P`Xy6?FOK)mCj)Ym4s2hh z0OlOdQa@I;^-3bhB6mpw*X5=0kJv8?#XP~9){G-+0ST@1Roz1qi8PhIXp1D$XNqVG zMl>WxwT+K`SdO1RCt4FWTNy3!i?N>*-lbnn#OxFJrswgD7HjuKpWh*o@QvgF&j+CT z{55~ZsUeR1aB}lv#s_7~+9dCix!5(KR#c?K?e2B%P$fvrsZxy@GP#R#jwL{y#Ld$} z7sF>QT6m|}?V;msb?Nlohj7a5W_D$y+4O6eI;Zt$jVGymlzLKscqer9#+p2$0It&u zWY!dCeM6^B^Z;ddEmhi?8`scl=Lhi7W%2|pT6X6^%-=q90DS(hQ-%c+E*ywPvmoF(KqDoW4!*gmQIklm zk#!GLqv|cs(JRF3G?=AYY19{w@~`G3pa z@xR9S-Hquh*&5Yas*VI};(%9%PADn`kzm zeWMJVW=>>wap*9|R7n#!&&J>gq04>DTCMtj{P^d12|2wXTEKvSf?$AvnE!peqV7i4 zE>0G%CSn%WCW1yre?yi9*aFP{GvZ|R4JT}M%x_%Hztz2qw?&28l&qW<6?c6ym{f$d z5YCF+k#yEbjCN|AGi~-NcCG8MCF1!MXBFL{#7q z)HO+WW173?kuI}^Xat;Q^gb4Hi0RGyB}%|~j8>`6X4CPo+|okMbKy9PHkr58V4bX6<&ERU)QlF8%%huUz&f+dwTN|tk+C&&o@Q1RtG`}6&6;ncQuAcfHoxd5AgD7`s zXynq41Y`zRSiOY@*;&1%1z>oNcWTV|)sjLg1X8ijg1Y zbIGL0X*Sd}EXSQ2BXCKbJmlckY(@EWn~Ut2lYeuw1wg?hhj@K?XB@V_ZP`fyL~Yd3n3SyHU-RwMBr6t-QWE5TinN9VD4XVPU; zonIIR!&pGqrLQK)=#kj40Im%V@ij0&Dh0*s!lnTw+D`Dt-xmk-jmpJv$1-E-vfYL4 zqKr#}Gm}~GPE+&$PI@4ag@=M}NYi7Y&HW82Q`@Y=W&PE31D110@yy(1vddLt`P%N^ z>Yz195A%tnt~tvsSR2{m!~7HUc@x<&`lGX1nYeQUE(%sphTi>JsVqSw8xql*Ys@9B z>RIOH*rFi*C`ohwXjyeRBDt8p)-u{O+KWP;$4gg||%*u{$~yEj+Al zE(hAQRQ1k7MkCq9s4^N3ep*$h^L%2Vq?f?{+cicpS8lo)$Cb69b98au+m2J_e7nYwID0@`M9XIo1H~|eZFc8Hl!qly612ADCVpU zY8^*RTMX(CgehD{9v|^9vZ6Rab`VeZ2m*gOR)Mw~73QEBiktViBhR!_&3l$|be|d6 zupC`{g89Y|V3uxl2!6CM(RNpdtynaiJ~*DqSTq9Mh`ohZnb%^3G{k;6%n18$4nAqR zjPOrP#-^Y9;iw{J@XH9=g5J+yEVh|e=4UeY<^65`%gWtdQ=-aqSgtywM(1nKXh`R4 zzPP&7r)kv_uC7X9n=h=!Zrf<>X=B5f<9~Q>h#jYRD#CT7D~@6@RGNyO-#0iq0uHV1 zPJr2O4d_xLmg2^TmG7|dpfJ?GGa`0|YE+`2Rata9!?$j#e9KfGYuLL(*^z z!SxFA`$qm)q-YKh)WRJZ@S+-sD_1E$V?;(?^+F3tVcK6 z2fE=8hV*2mgiAbefU^uvcM?&+Y&E}vG=Iz!%jBF7iv){lyC`)*yyS~D8k+Mx|N3bm zI~L~Z$=W9&`x)JnO;8c>3LSDw!fzN#X3qi|0`sXY4?cz{*#xz!kvZ9bO=K3XbN z5KrgN=&(JbXH{Wsu9EdmQ-W`i!JWEmfI;yVTT^a-8Ch#D8xf2dtyi?7p z%#)W3n*a#ndFpd{qN|+9Jz++AJQO#-Y7Z6%*%oyEP5zs}d&kKIr`FVEY z;S}@d?UU=tCdw~EJ{b}=9x}S2iv!!8<$?d7VKDA8h{oeD#S-$DV)-vPdGY@x08n)@ zag?yLF_E#evvRTj4^CcrLvBL=fft&@HOhZ6Ng4`8ijt&h2y}fOTC~7GfJi4vpomA5 zOcOM)o_I9BKz}I`q)fu+Qnfy*W`|mY%LO>eF^a z;$)?T4F-(X#Q-m}!-k8L_rNPf`Mr<9IWu)f&dvt=EL+ESYmCvErd@8B9hd)afc(ZL94S z?rp#h&{7Ah5IJftK4VjATklo7@hm?8BX*~oBiz)jyc9FuRw!-V;Uo>p!CWpLaIQyt zAs5WN)1CCeux-qiGdmbIk8LR`gM+Qg=&Ve}w?zA6+sTL)abU=-cvU`3E?p5$Hpkxw znu0N659qR=IKnde*AEz_7z2pdi_Bh-sb3b=PdGO1Pdf_q2;+*Cx9YN7p_>rl``knY zRn%aVkcv1(W;`Mtp_DNOIECtgq%ufk-mu_<+Fu3Q17Tq4Rr(oeq)Yqk_CHA7LR@7@ zIZIDxxhS&=F2IQfusQ+Nsr%*zFK7S4g!U0y@3H^Yln|i;0a5+?RPG;ZSp6Tul>ezM z`40+516&719qT)mW|ArDSENle5hE2e8qY+zfeZoy12u&xoMgcP)4=&P-1Ib*-bAy` zlT?>w&B|ei-rCXO;sxo7*G;!)_p#%PAM-?m$JP(R%x1Hfas@KeaG%LO?R=lmkXc_MKZW}3f%KZ*rAN?HYvbu2L$ zRt_uv7~-IejlD1x;_AhwGXjB94Q=%+PbxuYzta*jw?S&%|qb=(JfJ?&6P=R7X zV%HP_!@-zO*zS}46g=J}#AMJ}rtWBr21e6hOn&tEmaM%hALH7nlm2@LP4rZ>2 zebe5aH@k!e?ij4Zwak#30|}>;`bquDQK*xmR=zc6vj0yuyC6+U=LusGnO3ZKFRpen z#pwzh!<+WBVp-!$MAc<0i~I%fW=8IO6K}bJ<-Scq>e+)951R~HKB?Mx2H}pxPHE@} zvqpq5j81_jtb_WneAvp<5kgdPKm|u2BdQx9%EzcCN&U{l+kbkhmV<1}yCTDv%&K^> zg;KCjwh*R1f_`6`si$h6`jyIKT7rTv5#k~x$mUyIw)_>Vr)D4fwIs@}{FSX|5GB1l z4vv;@oS@>Bu7~{KgUa_8eg#Lk6IDT2IY$41$*06{>>V;Bwa(-@N;ex4;D`(QK*b}{ z{#4$Hmt)FLqERgKz=3zXiV<{YX6V)lvYBr3V>N6ajeI~~hGR5Oe>W9r@sg)Na(a4- zxm%|1OKPN6^%JaD^^O~HbLSu=f`1px>RawOxLr+1b2^28U*2#h*W^=lSpSY4(@*^l z{!@9RSLG8Me&RJYLi|?$c!B0fP=4xAM4rerxX{xy{&i6=AqXueQAIBqO+pmuxy8Ib z4X^}r!NN3-upC6B#lt7&x0J;)nb9O~xjJMemm$_fHuP{DgtlU3xiW0UesTzS30L+U zQzDI3p&3dpONhd5I8-fGk^}@unluzu%nJ$9pzoO~Kk!>dLxw@M)M9?pNH1CQhvA`z zV;uacUtnBTdvT`M$1cm9`JrT3BMW!MNVBy%?@ZX%;(%(vqQAz<7I!hlDe|J3cn9=} zF7B;V4xE{Ss76s$W~%*$JviK?w8^vqCp#_G^jN0j>~Xq#Zru26e#l3H^{GCLEXI#n z?n~F-Lv#hU(bZS`EI9(xGV*jT=8R?CaK)t8oHc9XJ;UPY0Hz$XWt#QyLBaaz5+}xM zXk(!L_*PTt7gwWH*HLWC$h3Ho!SQ-(I||nn_iEC{WT3S{3V{8IN6tZ1C+DiFM{xlI zeMMk{o5;I6UvaC)@WKp9D+o?2Vd@4)Ue-nYci()hCCsKR`VD;hr9=vA!cgGL%3k^b(jADGyPi2TKr(JNh8mzlIR>n(F_hgiV(3@Ds(tjbNM7GoZ;T|3 zWzs8S`5PrA!9){jBJuX4y`f<4;>9*&NY=2Sq2Bp`M2(fox7ZhIDe!BaQUb@P(ub9D zlP8!p(AN&CwW!V&>H?yPFMJ)d5x#HKfwx;nS{Rr@oHqpktOg)%F+%1#tsPtq7zI$r zBo-Kflhq-=7_eW9B2OQv=@?|y0CKN77)N;z@tcg;heyW{wlpJ1t`Ap!O0`Xz{YHqO zI1${8Hag^r!kA<2_~bYtM=<1YzQ#GGP+q?3T7zYbIjN6Ee^V^b&9en$8FI*NIFg9G zPG$OXjT0Ku?%L7fat8Mqbl1`azf1ltmKTa(HH$Dqlav|rU{zP;Tbnk-XkGFQ6d+gi z-PXh?_kEJl+K98&OrmzgPIijB4!Pozbxd0H1;Usy!;V>Yn6&pu*zW8aYx`SC!$*ti zSn+G9p=~w6V(fZZHc>m|PPfjK6IN4(o=IFu?pC?+`UZAUTw!e`052{P=8vqT^(VeG z=psASIhCv28Y(;7;TuYAe>}BPk5Qg=8$?wZj9lj>h2kwEfF_CpK=+O6Rq9pLn4W)# zeXCKCpi~jsfqw7Taa0;!B5_C;B}e56W1s8@p*)SPzA;Fd$Slsn^=!_&!mRHV*Lmt| zBGIDPuR>CgS4%cQ4wKdEyO&Z>2aHmja;Pz+n|7(#l%^2ZLCix%>@_mbnyPEbyrHaz z>j^4SIv;ZXF-Ftzz>*t4wyq)ng8%0d;(Z_ExZ-cxwei=8{(br-`JYO(f23Wae_MqE z3@{Mlf^%M5G1SIN&en1*| zH~ANY1h3&WNsBy$G9{T=`kcxI#-X|>zLX2r*^-FUF+m0{k)n#GTG_mhG&fJfLj~K& zU~~6othMlvMm9<*SUD2?RD+R17|Z4mgR$L*R3;nBbo&Vm@39&3xIg;^aSxHS>}gwR zmzs?h8oPnNVgET&dx5^7APYx6Vv6eou07Zveyd+^V6_LzI$>ic+pxD_8s~ zC<}ucul>UH<@$KM zT4oI=62M%7qQO{}re-jTFqo9Z;rJKD5!X5$iwUsh*+kcHVhID08MB5cQD4TBWB(rI zuWc%CA}}v|iH=9gQ?D$1#Gu!y3o~p7416n54&Hif`U-cV?VrUMJyEqo_NC4#{puzU zzXEE@UppeeRlS9W*^N$zS`SBBi<@tT+<%3l@KhOy^%MWB9(A#*J~DQ;+MK*$rxo6f zcx3$3mcx{tly!q(p2DQrxcih|)0do_ZY77pyHGE#Q(0k*t!HUmmMcYFq%l$-o6%lS zDb49W-E?rQ#Hl``C3YTEdGZjFi3R<>t)+NAda(r~f1cT5jY}s7-2^&Kvo&2DLTPYP zhVVo-HLwo*vl83mtQ9)PR#VBg)FN}+*8c-p8j`LnNUU*Olm1O1Qqe62D#$CF#?HrM zy(zkX|1oF}Z=T#3XMLWDrm(|m+{1&BMxHY7X@hM_+cV$5-t!8HT(dJi6m9{ja53Yw z3f^`yb6Q;(e|#JQIz~B*=!-GbQ4nNL-NL z@^NWF_#w-Cox@h62;r^;Y`NX8cs?l^LU;5IWE~yvU8TqIHij!X8ydbLlT0gwmzS9} z@5BccG?vO;rvCs$mse1*ANi-cYE6Iauz$Fbn3#|ToAt5v7IlYnt6RMQEYLldva{~s zvr>1L##zmeoYgvIXJ#>bbuCVuEv2ZvZ8I~PQUN3wjP0UC)!U+wn|&`V*8?)` zMSCuvnuGec>QL+i1nCPGDAm@XSMIo?A9~C?g2&G8aNKjWd2pDX{qZ?04+2 zeyLw}iEd4vkCAWwa$ zbrHlEf3hfN7^1g~aW^XwldSmx1v~1z(s=1az4-wl} z`mM+G95*N*&1EP#u3}*KwNrPIgw8Kpp((rdEOO;bT1;6ea~>>sK+?!;{hpJ3rR<6UJb`O8P4@{XGgV%63_fs%cG8L zk9Fszbdo4tS$g0IWP1>t@0)E%-&9yj%Q!fiL2vcuL;90fPm}M==<>}Q)&sp@STFCY z^p!RzmN+uXGdtPJj1Y-khNyCb6Y$Vs>eZyW zPaOV=HY_T@FwAlleZCFYl@5X<<7%5DoO(7S%Lbl55?{2vIr_;SXBCbPZ(up;pC6Wx={AZL?shYOuFxLx1*>62;2rP}g`UT5+BHg(ju z&7n5QSvSyXbioB9CJTB#x;pexicV|9oaOpiJ9VK6EvKhl4^Vsa(p6cIi$*Zr0UxQ z;$MPOZnNae2Duuce~7|2MCfhNg*hZ9{+8H3?ts9C8#xGaM&sN;2lriYkn9W>&Gry! z3b(Xx1x*FhQkD-~V+s~KBfr4M_#0{`=Yrh90yj}Ph~)Nx;1Y^8<418tu!$1<3?T*~ z7Dl0P3Uok-7w0MPFQexNG1P5;y~E8zEvE49>$(f|XWtkW2Mj`udPn)pb%} zrA%wRFp*xvDgC767w!9`0vx1=q!)w!G+9(-w&p*a@WXg{?T&%;qaVcHo>7ca%KX$B z^7|KBPo<2;kM{2mRnF8vKm`9qGV%|I{y!pKm8B(q^2V;;x2r!1VJ^Zz8bWa)!-7a8 zSRf@dqEPlsj!7}oNvFFAA)75})vTJUwQ03hD$I*j6_5xbtd_JkE2`IJD_fQ;a$EkO z{fQ{~e%PKgPJsD&PyEvDmg+Qf&p*-qu!#;1k2r_(H72{^(Z)htgh@F?VIgK#_&eS- z$~(qInec>)XIkv@+{o6^DJLpAb>!d}l1DK^(l%#OdD9tKK6#|_R?-%0V!`<9Hj z3w3chDwG*SFte@>Iqwq`J4M&{aHXzyigT620+Vf$X?3RFfeTcvx_e+(&Q*z)t>c0e zpZH$1Z3X%{^_vylHVOWT6tno=l&$3 z9^eQ@TwU#%WMQaFvaYp_we%_2-9=o{+ck zF{cKJCOjpW&qKQquyp2BXCAP920dcrZ}T1@piukx_NY;%2W>@Wca%=Ch~x5Oj58Hv z;D-_ALOZBF(Mqbcqjd}P3iDbek#Dwzu`WRs`;hRIr*n0PV7vT+%Io(t}8KZ zpp?uc2eW!v28ipep0XNDPZt7H2HJ6oey|J3z!ng#1H~x_k%35P+Cp%mqXJ~cV0xdd z^4m5^K_dQ^Sg?$P`))ccV=O>C{Ds(C2WxX$LMC5vy=*44pP&)X5DOPYfqE${)hDg< z3hcG%U%HZ39=`#Ko4Uctg&@PQLf>?0^D|4J(_1*TFMOMB!Vv1_mnOq$BzXQdOGqgy zOp#LBZ!c>bPjY1NTXksZmbAl0A^Y&(%a3W-k>bE&>K?px5Cm%AT2E<&)Y?O*?d80d zgI5l~&Mve;iXm88Q+Fw7{+`PtN4G7~mJWR^z7XmYQ>uoiV!{tL)hp|= zS(M)813PM`d<501>{NqaPo6BZ^T{KBaqEVH(2^Vjeq zgeMeMpd*1tE@@);hGjuoVzF>Cj;5dNNwh40CnU+0DSKb~GEMb_# zT8Z&gz%SkHq6!;_6dQFYE`+b`v4NT7&@P>cA1Z1xmXy<2htaDhm@XXMp!g($ zw(7iFoH2}WR`UjqjaqOQ$ecNt@c|K1H1kyBArTTjLp%-M`4nzOhkfE#}dOpcd;b#suq8cPJ&bf5`6Tq>ND(l zib{VrPZ>{KuaIg}Y$W>A+nrvMg+l4)-@2jpAQ5h(Tii%Ni^-UPVg{<1KGU2EIUNGaXcEkOedJOusFT9X3%Pz$R+-+W+LlRaY-a$5r?4V zbPzgQl22IPG+N*iBRDH%l{Zh$fv9$RN1sU@Hp3m=M}{rX%y#;4(x1KR2yCO7Pzo>rw(67E{^{yUR`91nX^&MxY@FwmJJbyPAoWZ9Z zcBS$r)&ogYBn{DOtD~tIVJUiq|1foX^*F~O4hlLp-g;Y2wKLLM=?(r3GDqsPmUo*? zwKMEi*%f)C_@?(&&hk>;m07F$X7&i?DEK|jdRK=CaaNu-)pX>n3}@%byPKVkpLzBq z{+Py&!`MZ^4@-;iY`I4#6G@aWMv{^2VTH7|WF^u?3vsB|jU3LgdX$}=v7#EHRN(im zI(3q-eU$s~r=S#EWqa_2!G?b~ z<&brq1vvUTJH380=gcNntZw%7UT8tLAr-W49;9y^=>TDaTC|cKA<(gah#2M|l~j)w zY8goo28gj$n&zcNgqX1Qn6=<8?R0`FVO)g4&QtJAbW3G#D)uNeac-7cH5W#6i!%BH z=}9}-f+FrtEkkrQ?nkoMQ1o-9_b+&=&C2^h!&mWFga#MCrm85hW;)1pDt;-uvQG^D zntSB?XA*0%TIhtWDS!KcI}kp3LT>!(Nlc(lQN?k^bS8Q^GGMfo}^|%7s;#r+pybl@?KA++|FJ zr%se9(B|g*ERQU96az%@4gYrxRRxaM2*b}jNsG|0dQi;Rw{0WM0E>rko!{QYAJJKY z)|sX0N$!8d9E|kND~v|f>3YE|uiAnqbkMn)hu$if4kUkzKqoNoh8v|S>VY1EKmgO} zR$0UU2o)4i4yc1inx3}brso+sio{)gfbLaEgLahj8(_Z#4R-v) zglqwI%`dsY+589a8$Mu7#7_%kN*ekHupQ#48DIN^uhDxblDg3R1yXMr^NmkR z7J_NWCY~fhg}h!_aXJ#?wsZF$q`JH>JWQ9`jbZzOBpS`}-A$Vgkq7+|=lPx9H7QZG z8i8guMN+yc4*H*ANr$Q-3I{FQ-^;8ezWS2b8rERp9TMOLBxiG9J*g5=?h)mIm3#CGi4JSq1ohFrcrxx@`**K5%T}qbaCGldV!t zVeM)!U3vbf5FOy;(h08JnhSGxm)8Kqxr9PsMeWi=b8b|m_&^@#A3lL;bVKTBx+0v8 zLZeWAxJ~N27lsOT2b|qyp$(CqzqgW@tyy?CgwOe~^i;ZH zlL``i4r!>i#EGBNxV_P@KpYFQLz4Bdq{#zA&sc)*@7Mxsh9u%e6Ke`?5Yz1jkTdND zR8!u_yw_$weBOU}24(&^Bm|(dSJ(v(cBct}87a^X(v>nVLIr%%D8r|&)mi+iBc;B;x;rKq zd8*X`r?SZsTNCPQqoFOrUz8nZO?225Z#z(B!4mEp#ZJBzwd7jW1!`sg*?hPMJ$o`T zR?KrN6OZA1H{9pA;p0cSSu;@6->8aJm1rrO-yDJ7)lxuk#npUk7WNER1Wwnpy%u zF=t6iHzWU(L&=vVSSc^&D_eYP3TM?HN!Tgq$SYC;pSIPWW;zeNm7Pgub#yZ@7WPw#f#Kl)W4%B>)+8%gpfoH1qZ;kZ*RqfXYeGXJ_ zk>2otbp+1By`x^1V!>6k5v8NAK@T;89$`hE0{Pc@Q$KhG0jOoKk--Qx!vS~lAiypV zCIJ&6B@24`!TxhJ4_QS*S5;;Pk#!f(qIR7*(c3dN*POKtQe)QvR{O2@QsM%ujEAWEm) z+PM=G9hSR>gQ`Bv2(k}RAv2+$7qq(mU`fQ+&}*i%-RtSUAha>70?G!>?w%F(b4k!$ zvm;E!)2`I?etmSUFW7WflJ@8Nx`m_vE2HF#)_BiD#FaNT|IY@!uUbd4v$wTglIbIX zblRy5=wp)VQzsn0_;KdM%g<8@>#;E?vypTf=F?3f@SSdZ;XpX~J@l1;p#}_veWHp>@Iq_T z@^7|h;EivPYv1&u0~l9(a~>dV9Uw10QqB6Dzu1G~-l{*7IktljpK<_L8m0|7VV_!S zRiE{u97(%R-<8oYJ{molUd>vlGaE-C|^<`hppdDz<7OS13$#J zZ+)(*rZIDSt^Q$}CRk0?pqT5PN5TT`Ya{q(BUg#&nAsg6apPMhLTno!SRq1e60fl6GvpnwDD4N> z9B=RrufY8+g3_`@PRg+(+gs2(bd;5#{uTZk96CWz#{=&h9+!{_m60xJxC%r&gd_N! z>h5UzVX%_7@CUeAA1XFg_AF%(uS&^1WD*VPS^jcC!M2v@RHZML;e(H-=(4(3O&bX- zI6>usJOS+?W&^S&DL{l|>51ZvCXUKlH2XKJPXnHjs*oMkNM#ZDLx!oaM5(%^)5XaP zk6&+P16sA>vyFe9v`Cp5qnbE#r#ltR5E+O3!WnKn`56Grs2;sqr3r# zp@Zp<^q`5iq8OqOlJ`pIuyK@3zPz&iJ0Jcc`hDQ1bqos2;}O|$i#}e@ua*x5VCSx zJAp}+?Hz++tm9dh3Fvm_bO6mQo38al#>^O0g)Lh^&l82+&x)*<n7^Sw-AJo9tEzZDwyJ7L^i7|BGqHu+ea6(&7jKpBq>~V z8CJxurD)WZ{5D0?s|KMi=e7A^JVNM6sdwg@1Eg_+Bw=9j&=+KO1PG|y(mP1@5~x>d z=@c{EWU_jTSjiJl)d(>`qEJ;@iOBm}alq8;OK;p(1AdH$)I9qHNmxxUArdzBW0t+Qeyl)m3?D09770g z)hzXEOy>2_{?o%2B%k%z4d23!pZcoxyW1Ik{|m7Q1>fm4`wsRrl)~h z_=Z*zYL+EG@DV1{6@5@(Ndu!Q$l_6Qlfoz@79q)Kmsf~J7t1)tl#`MD<;1&CAA zH8;i+oBm89dTTDl{aH`cmTPTt@^K-%*sV+t4X9q0Z{A~vEEa!&rRRr=0Rbz4NFCJr zLg2u=0QK@w9XGE=6(-JgeP}G#WG|R&tfHRA3a9*zh5wNTBAD;@YYGx%#E4{C#Wlfo z%-JuW9=FA_T6mR2-Vugk1uGZvJbFvVVWT@QOWz$;?u6+CbyQsbK$>O1APk|xgnh_8 zc)s@Mw7#0^wP6qTtyNq2G#s?5j~REyoU6^lT7dpX{T-rhZWHD%dik*=EA7bIJgOVf_Ga!yC8V^tkTOEHe+JK@Fh|$kfNxO^= z#lpV^(ZQ-3!^_BhV>aXY~GC9{8%1lOJ}6vzXDvPhC>JrtXwFBC+!3a*Z-%#9}i z#<5&0LLIa{q!rEIFSFc9)>{-_2^qbOg5;_A9 ztQ))C6#hxSA{f9R3Eh^`_f${pBJNe~pIQ`tZVR^wyp}=gLK}e5_vG@w+-mp#Fu>e| z*?qBp5CQ5zu+Fi}xAs)YY1;bKG!htqR~)DB$ILN6GaChoiy%Bq@i+1ZnANC0U&D z_4k$=YP47ng+0NhuEt}6C;9-JDd8i5S>`Ml==9wHDQFOsAlmtrVwurYDw_)Ihfk35 zJDBbe!*LUpg%4n>BExWz>KIQ9vexUu^d!7rc_kg#Bf= z7TLz|l*y*3d2vi@c|pX*@ybf!+Xk|2*z$@F4K#MT8Dt4zM_EcFmNp31#7qT6(@GG? zdd;sSY9HHuDb=w&|K%sm`bYX#%UHKY%R`3aLMO?{T#EI@FNNFNO>p@?W*i0z(g2dt z{=9Ofh80Oxv&)i35AQN>TPMjR^UID-T7H5A?GI{MD_VeXZ%;uo41dVm=uT&ne2h0i zv*xI%9vPtdEK@~1&V%p1sFc2AA`9?H)gPnRdlO~URx!fiSV)j?Tf5=5F>hnO=$d$x zzaIfr*wiIc!U1K*$JO@)gP4%xp!<*DvJSv7p}(uTLUb=MSb@7_yO+IsCj^`PsxEl& zIxsi}s3L?t+p+3FXYqujGhGwTx^WXgJ1}a@Yq5mwP0PvGEr*qu7@R$9j>@-q1rz5T zriz;B^(ex?=3Th6h;7U`8u2sDlfS{0YyydK=*>-(NOm9>S_{U|eg(J~C7O zIe{|LK=Y`hXiF_%jOM8Haw3UtaE{hWdzo3BbD6ud7br4cODBtN(~Hl+odP0SSWPw;I&^m)yLw+nd#}3#z}?UIcX3=SssI}`QwY=% zAEXTODk|MqTx}2DVG<|~(CxgLyi*A{m>M@1h^wiC)4Hy>1K7@|Z&_VPJsaQoS8=ex zDL&+AZdQa>ylxhT_Q$q=60D5&%pi6+qlY3$3c(~rsITX?>b;({FhU!7HOOhSP7>bmTkC8KM%!LRGI^~y3Ug+gh!QM=+NZXznM)?L3G=4=IMvFgX3BAlyJ z`~jjA;2z+65D$j5xbv9=IWQ^&-K3Yh`vC(1Qz2h2`o$>Cej@XRGff!it$n{@WEJ^N z41qk%Wm=}mA*iwCqU_6}Id!SQd13aFER3unXaJJXIsSnxvG2(hSCP{i&QH$tL&TPx zDYJsuk+%laN&OvKb-FHK$R4dy%M7hSB*yj#-nJy?S9tVoxAuDei{s}@+pNT!vLOIC z8g`-QQW8FKp3cPsX%{)0B+x+OhZ1=L7F-jizt|{+f1Ga7%+!BXqjCjH&x|3%?UbN# zh?$I1^YokvG$qFz5ySK+Ja5=mkR&p{F}ev**rWdKMko+Gj^?Or=UH?SCg#0F(&a_y zXOh}dPv0D9l0RVedq1~jCNV=8?vZfU-Xi|nkeE->;ohG3U7z+^0+HV17~-_Mv#mV` zzvwUJJ15v5wwKPv-)i@dsEo@#WEO9zie7mdRAbgL2kjbW4&lk$vxkbq=w5mGKZK6@ zjXWctDkCRx58NJD_Q7e}HX`SiV)TZMJ}~zY6P1(LWo`;yDynY_5_L?N-P`>ALfmyl z8C$a~FDkcwtzK9m$tof>(`Vu3#6r#+v8RGy#1D2)F;vnsiL&P-c^PO)^B-4VeJteLlT@25sPa z%W~q5>YMjj!mhN})p$47VA^v$Jo6_s{!y?}`+h+VM_SN`!11`|;C;B};B&Z<@%FOG z_YQVN+zFF|q5zKab&e4GH|B;sBbKimHt;K@tCH+S{7Ry~88`si7}S)1E{21nldiu5 z_4>;XTJa~Yd$m4A9{Qbd)KUAm7XNbZ4xHbg3a8-+1uf*$1PegabbmCzgC~1WB2F(W zYj5XhVos!X!QHuZXCatkRsdEsSCc+D2?*S7a+(v%toqyxhjz|`zdrUvsxQS{J>?c& zvx*rHw^8b|v^7wq8KWVofj&VUitbm*a&RU_ln#ZFA^3AKEf<#T%8I!Lg3XEsdH(A5 zlgh&M_XEoal)i#0tcq8c%Gs6`xu;vvP2u)D9p!&XNt z!TdF_H~;`g@fNXkO-*t<9~;iEv?)Nee%hVe!aW`N%$cFJ(Dy9+Xk*odyFj72T!(b%Vo5zvCGZ%3tkt$@Wcx8BWEkefI1-~C_3y*LjlQ5%WEz9WD8i^ z2MV$BHD$gdPJV4IaV)G9CIFwiV=ca0cfXdTdK7oRf@lgyPx;_7*RRFk=?@EOb9Gcz zg~VZrzo*Snp&EE{$CWr)JZW)Gr;{B2ka6B!&?aknM-FENcl%45#y?oq9QY z3^1Y5yn&^D67Da4lI}ljDcphaEZw2;tlYuzq?uB4b9Mt6!KTW&ptxd^vF;NbX=00T z@nE1lIBGgjqs?ES#P{ZfRb6f!At51vk%<0X%d_~NL5b8UyfQMPDtfU@>ijA0NP3UU zh{lCf`Wu7cX!go`kUG`1K=7NN@SRGjUKuo<^;@GS!%iDXbJs`o6e`v3O8-+7vRkFm z)nEa$sD#-v)*Jb>&Me+YIW3PsR1)h=-Su)))>-`aRcFJG-8icomO4J@60 zw10l}BYxi{eL+Uu0xJYk-Vc~BcR49Qyyq!7)PR27D`cqGrik=?k1Of>gY7q@&d&Ds zt7&WixP`9~jjHO`Cog~RA4Q%uMg+$z^Gt&vn+d3&>Ux{_c zm|bc;k|GKbhZLr-%p_f%dq$eiZ;n^NxoS-Nu*^Nx5vm46)*)=-Bf<;X#?`YC4tLK; z?;u?shFbXeks+dJ?^o$l#tg*1NA?(1iFff@I&j^<74S!o;SWR^Xi);DM%8XiWpLi0 zQE2dL9^a36|L5qC5+&Pf0%>l&qQ&)OU4vjd)%I6{|H+pw<0(a``9w(gKD&+o$8hOC zNAiShtc}e~ob2`gyVZx59y<6Fpl*$J41VJ-H*e-yECWaDMmPQi-N8XI3 z%iI@ljc+d}_okL1CGWffeaejlxWFVDWu%e=>H)XeZ|4{HlbgC-Uvof4ISYQzZ0Um> z#Ov{k1c*VoN^f(gfiueuag)`TbjL$XVq$)aCUBL_M`5>0>6Ska^*Knk__pw{0I>jA zzh}Kzg{@PNi)fcAk7jMAdi-_RO%x#LQszDMS@_>iFoB+zJ0Q#CQJzFGa8;pHFdi`^ zxnTC`G$7Rctm3G8t8!SY`GwFi4gF|+dAk7rh^rA{NXzc%39+xSYM~($L(pJ(8Zjs* zYdN_R^%~LiGHm9|ElV4kVZGA*T$o@YY4qpJOxGHlUi*S*A(MrgQ{&xoZQo+#PuYRs zv3a$*qoe9gBqbN|y|eaH=w^LE{>kpL!;$wRahY(hhzRY;d33W)m*dfem@)>pR54Qy z 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 \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m"' - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - -exec "$JAVACMD" "$@" diff --git a/subset/ntp/NTPClient/gradlew.bat b/subset/ntp/NTPClient/gradlew.bat deleted file mode 100644 index 0f8d5937c4..0000000000 --- a/subset/ntp/NTPClient/gradlew.bat +++ /dev/null @@ -1,84 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/subset/ntp/NTPClient/settings.gradle b/subset/ntp/NTPClient/settings.gradle deleted file mode 100644 index a6b059db39..0000000000 --- a/subset/ntp/NTPClient/settings.gradle +++ /dev/null @@ -1,2 +0,0 @@ -rootProject.name = 'NTPClient' - diff --git a/subset/ntp/NTPClient/src/main/java/META-INF/MANIFEST.MF b/subset/ntp/NTPClient/src/main/java/META-INF/MANIFEST.MF deleted file mode 100644 index 37197ef4e8..0000000000 --- a/subset/ntp/NTPClient/src/main/java/META-INF/MANIFEST.MF +++ /dev/null @@ -1,3 +0,0 @@ -Manifest-Version: 1.0 -Main-Class: Main - diff --git a/subset/ntp/README.md b/subset/ntp/README.md deleted file mode 100644 index d4a9496524..0000000000 --- a/subset/ntp/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# NTP testing - -## test_ntp -The NTP tests inspect the client NTP version and the device's ability to update its clock precisely. - -### Note for test developers -The functional test code is included in the `ntp_tests.py` file. - -The test reads packets from startup.pcap and monitor.pcap. - -If the python code needs debugging, the pip module `scapy` is required (`pip install scapy`). - -### NTP Test conditions -| Test ID | Info | Pass | Fail | Skip | -|---|---|---|---|---| -| connection.network.ntp_support | Are the received NTP packets using NTP v4? | NTP version is 4 | NTP version is not 4 | No NTP packets are received | -| connection.network.ntp_update | Does the device demonstrate updating its clock using NTP? | Device clock is synchronized | Device clock is not synchronized | Not enough NTP packets are received | - -#### NTP Support #### -The version of NTP used by the client is extracted from the fist client (outbound) NTP packets discovered in startup.pcap. - -#### NTP Update #### -The following criteria are used to determine whether a DUT has synced its clock with the NTP server provided by DAQ: - - A minimum of 2 NTP packets are present in startup.pcap and monitor.pcap (one potential poll). - - A minimum of 2 NTP packets have been exchanged between the DUT and the DAQ-provided NTP server. - - A valid NTP poll is present. Consisting of a client-server exchange. - - The calculated offset is less than 0.128 seconds and the final poll does not have a leap indicator of 3 (unsynchronized). - -When calculating the offset, the latest valid poll is inspected. A value of 0.128s is the maximum offset used to determine whether a device is considered in-sync with the NTP server because NTPv4 is capable of accuracy of tens of milliseconds. diff --git a/subset/ntp/build.conf b/subset/ntp/build.conf deleted file mode 100644 index febb370b8f..0000000000 --- a/subset/ntp/build.conf +++ /dev/null @@ -1,2 +0,0 @@ -build subset/ntp -add ntp diff --git a/subset/ntp/test_ntp b/subset/ntp/test_ntp deleted file mode 100755 index fa7d950189..0000000000 --- a/subset/ntp/test_ntp +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -e - -REPORT=/tmp/report.txt -STARTUP=/scans/startup.pcap -MONITOR=/scans/monitor.pcap - -python ntp_tests.py connection.network.ntp_support $STARTUP $MONITOR -python ntp_tests.py connection.network.ntp_update $STARTUP $MONITOR - -cat report.txt >> $REPORT diff --git a/testing/test_aux.out b/testing/test_aux.out index e5aa8a21ac..47d2650fd4 100644 --- a/testing/test_aux.out +++ b/testing/test_aux.out @@ -21,8 +21,6 @@ RESULT info protocol.bacnet.version Protocol version: 1 RESULT skip protocol.bacnet.pic BACnet device found, but pics.csv not found in device type directory. RESULT info protocol.bacnet.version Protocol version: 1 RESULT pass protocol.bacnet.pic The devices matches the PICS -RESULT fail connection.mac_oui Manufacturer prefix not found! -RESULT pass connection.mac_oui Manufacturer: Google found for address 3c:5a:b4:1e:8f:0a RESULT skip security.tls.v1 IOException unable to connect to server RESULT skip security.tls.v1.x509 IOException unable to connect to server RESULT skip security.tls.v1_2 IOException unable to connect to server @@ -55,15 +53,24 @@ RESULT pass security.passwords.telnet Default passwords have been changed. RESULT pass security.passwords.ssh Default passwords have been changed. RESULT skip security.firmware Could not retrieve a firmware version with nmap. Check bacnet port. RESULT pass security.firmware version found: ?\xFF\xFF\x19,>u\x08\x00no +RESULT pass connection.min_send ARP packets received. Data packets were sent at a frequency of less than 5 minutes +RESULT info communication.type.broadcast Broadcast packets received. Unicast packets received. RESULT pass connection.network.ntp_support Using NTPv4. RESULT pass connection.network.ntp_update Device clock synchronized. +RESULT fail connection.mac_oui Manufacturer prefix not found! +RESULT pass connection.min_send ARP packets received. Data packets were sent at a frequency of less than 5 minutes +RESULT info communication.type.broadcast Broadcast packets received. Unicast packets received. RESULT fail connection.network.ntp_support Not using NTPv4. RESULT fail connection.network.ntp_update Device clock not synchronized with local NTP server. +RESULT pass connection.mac_oui Manufacturer: Google found for address 3c:5a:b4:1e:8f:0b +RESULT pass connection.min_send ARP packets received. Data packets were sent at a frequency of less than 5 minutes +RESULT info communication.type.broadcast Broadcast packets received. Unicast packets received. RESULT skip connection.network.ntp_support No NTP packets received. RESULT skip connection.network.ntp_update Not enough NTP packets received. +RESULT pass connection.mac_oui Manufacturer: Google found for address 3c:5a:b4:1e:8f:0a dhcp requests 1 1 1 1 01: [] -02: ['02:macoui:TimeoutError', '02:ping:TimeoutError'] +02: ['02:ping:TimeoutError'] 03: [] arp.txt dp_port_acls.yaml @@ -106,9 +113,6 @@ port-01 module_config modules "port_flap_timeout_sec": 20, "timeout_sec": 900 }, - "macoui": { - "enabled": true - }, "manual": { "enabled": true }, @@ -118,9 +122,6 @@ port-01 module_config modules "nmap": { "enabled": true }, - "ntp": { - "enabled": true - }, "pass": { "enabled": true }, @@ -169,10 +170,6 @@ port-02 module_config modules "port_flap_timeout_sec": 20, "timeout_sec": 900 }, - "macoui": { - "enabled": true, - "timeout_sec": 1 - }, "manual": { "enabled": true }, @@ -182,9 +179,6 @@ port-02 module_config modules "nmap": { "enabled": true }, - "ntp": { - "enabled": true - }, "pass": { "enabled": false }, diff --git a/testing/test_aux.sh b/testing/test_aux.sh index aa7c97470f..bee1720acc 100755 --- a/testing/test_aux.sh +++ b/testing/test_aux.sh @@ -58,11 +58,11 @@ site_path: inst/test_site schema_path: schemas/udmi interfaces: faux-1: - opts: brute broadcast_client ntpv4 + opts: brute broadcast_client ntpv4 faux-2: - opts: nobrute expiredtls bacnetfail pubber passwordfail ntpv3 opendns ssh + opts: nobrute expiredtls bacnetfail pubber passwordfail ntpv3 opendns ssh faux-3: - opts: tls macoui passwordpass bacnet pubber broadcast_client ssh + opts: tls macoui passwordpass bacnet pubber broadcast_client ssh long_dhcp_response_sec: 0 monitor_scan_sec: 20 EOF From 67511b492155f08d3e9970ec50dd972fa4a0e13c Mon Sep 17 00:00:00 2001 From: Haoli Du Date: Tue, 4 Aug 2020 16:47:42 -0700 Subject: [PATCH 070/212] 1.9.0 release --- docs/changelog.md | 8 +++++++ etc/docker_images.txt | 55 ++++++++++++++++++++++--------------------- etc/docker_images.ver | 2 +- 3 files changed, 37 insertions(+), 28 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index 54c014b97a..5cdbb47729 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,4 +1,12 @@ # Changelog +* 1.9.0 + * Test infrastructure cleanup (#572) + * Remove faux dependencies from subset directory (#567) + * Github actions (#558) + * misc updates to docs (#568) + * Incorporate manual test comments (#499) + * NTP Update (#525) + * Automatic build script (#557) * 1.8.2 * GRPC timeouts + usi first command wait fix. (#555) * Numerous renovate bot updates. diff --git a/etc/docker_images.txt b/etc/docker_images.txt index a4b7dc8af8..86709318c1 100644 --- a/etc/docker_images.txt +++ b/etc/docker_images.txt @@ -1,27 +1,28 @@ -daqf/aardvark 6fb0f6c52222 -daqf/default f8652a12fdd8 -daqf/faucet 380da46f6fda -daqf/faux1 befad911308a -daqf/faux2 588b260e9316 -daqf/gauge 157decf291db -daqf/networking 1b5d992ef9a9 -daqf/switch b2113d0aa5d9 -daqf/test_bacext 67df87afaf77 -daqf/test_bacnet 53c268d102eb -daqf/test_brute aa76b01d5eed -daqf/test_discover 0ca76d766349 -daqf/test_fail 8ef4103069a5 -daqf/test_hold 5c923cd1a464 -daqf/test_macoui a605473e0f8d -daqf/test_manual 8026fdd99a5b -daqf/test_mudgee 189aa0b635fd -daqf/test_nmap 2205363f02a4 -daqf/test_ntp a5b21e0039e6 -daqf/test_pass 62dd10381336 -daqf/test_password 486b405827b2 -daqf/test_ping fe8e4dd5ddc2 -daqf/test_ssh 054efbf1b3c3 -daqf/test_switch bfca153bb3fe -daqf/test_tls 50bf58dd9a6f -daqf/test_udmi 41c2ab08ec86 -daqf/usi ab9976d57693 +daqf/aardvark 6e4060d0a709 +daqf/default aeb62fb24aec +daqf/faucet ed05522dc9a9 +daqf/faux1 8f7ea8f17cd6 +daqf/faux2 a850c4b2a543 +daqf/gauge 639232dbf1fa +daqf/networking 5751109cde18 +daqf/switch 083e95f1e99a +daqf/test_bacext 47ae2409fb29 +daqf/test_bacnet e0c2d561fed4 +daqf/test_brute bfa1aee20a20 +daqf/test_discover 82c7c43a2511 +daqf/test_fail 714d948b6704 +daqf/test_hold cb0be5cc6344 +daqf/test_macoui fd9c99e49a9e +daqf/test_manual 47cc832d53c4 +daqf/test_mudgee 239b96416b74 +daqf/test_network b55e8fdb12ed +daqf/test_nmap 16ec57a5e432 +daqf/test_ntp a62a00c53442 +daqf/test_pass 1da28b1cdfdc +daqf/test_password ac7b8f36cfd6 +daqf/test_ping 805a48f03a8d +daqf/test_ssh 836e7a6c54ad +daqf/test_switch 5f5dff0d9222 +daqf/test_tls 36f9e52f5df5 +daqf/test_udmi 1dc5b32d827a +daqf/usi f5ceac56a634 diff --git a/etc/docker_images.ver b/etc/docker_images.ver index 53adb84c82..f8e233b273 100644 --- a/etc/docker_images.ver +++ b/etc/docker_images.ver @@ -1 +1 @@ -1.8.2 +1.9.0 From 9fbd8d3eb3b2c9e13d5bcc5165c0dc782ca744cf Mon Sep 17 00:00:00 2001 From: Trevor Date: Tue, 4 Aug 2020 22:48:03 -0700 Subject: [PATCH 071/212] Fix google-cloud-core version (#574) --- bin/setup_dev | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bin/setup_dev b/bin/setup_dev index f6debbae9b..01aa1f620d 100755 --- a/bin/setup_dev +++ b/bin/setup_dev @@ -132,11 +132,12 @@ $PIP install --upgrade --index-url=https://pypi.python.org/simple Jinja2 \ pylint==2.4.2 cryptography requests netifaces codecov coverage setuptools \ pyyaml cairocffi==1.0.2 WeasyPrint==50 pypandoc==1.4 \ firebase-admin==2.16.0 \ - google-cloud-pubsub==0.40.0 \ google-api-core==1.16.0 \ - google-cloud-storage==1.16.1 \ + google-cloud-core==1.3.0 \ google-cloud-firestore==1.6.0 \ google-cloud-logging==1.14.0 \ + google-cloud-pubsub==0.40.0 \ + google-cloud-storage==1.16.1 \ grpcio-tools==1.30.0 $PIP freeze From 8372ad4cba496b27594cda1577a0040362d55dce Mon Sep 17 00:00:00 2001 From: em-redstone <60139604+em-redstone@users.noreply.github.com> Date: Wed, 5 Aug 2020 10:44:18 +0100 Subject: [PATCH 072/212] security.admin.password changes (#461) * Improvements to the password test, now using hydra under the hood --- docs/device_report.md | 69 +- subset/security/Dockerfile.test_password | 12 +- .../password/create_brute_force_dictionaries | 148 + .../password/resources/default/dictionary.txt | 1271 ++++++++ .../password/resources/default/passwords.txt | 1271 ++++++++ .../password/resources/default/usernames.txt | 1271 ++++++++ .../password/resources/faux/dictionary.txt | 4 + .../password/resources/faux/passwords.txt | 4 + .../password/resources/faux/usernames.txt | 4 + .../password/resources/raw/manufacturer.csv | 2850 +++++++++++++++++ .../security/password/resources/raw/ssh.txt | 121 + .../password/resources/raw/telnet.txt | 146 + .../password/run_password_test_for_protocol | 165 + subset/security/password/test_password | 144 + subset/security/readme.md | 51 +- subset/security/security_passwords/.classpath | 30 - subset/security/security_passwords/.gitignore | 4 - .../security/security_passwords/build.gradle | 38 - .../gradle/wrapper/gradle-wrapper.jar | Bin 56177 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 - subset/security/security_passwords/gradlew | 172 - .../security/security_passwords/gradlew.bat | 84 - .../security_passwords/settings.gradle | 2 - .../src/main/java/BruteForceTester.java | 71 - .../src/main/java/DefaultCredentials.java | 88 - .../src/main/java/PortChecker.java | 62 - .../src/main/java/ReportHandler.java | 108 - .../src/main/java/TestPassword.java | 76 - .../src/main/resources/defaultPasswords.json | 131 - subset/security/test_password | 59 - testing/test_aux.out | 26 +- testing/test_aux.sh | 5 + 32 files changed, 7499 insertions(+), 994 deletions(-) create mode 100755 subset/security/password/create_brute_force_dictionaries create mode 100644 subset/security/password/resources/default/dictionary.txt create mode 100644 subset/security/password/resources/default/passwords.txt create mode 100644 subset/security/password/resources/default/usernames.txt create mode 100644 subset/security/password/resources/faux/dictionary.txt create mode 100644 subset/security/password/resources/faux/passwords.txt create mode 100644 subset/security/password/resources/faux/usernames.txt create mode 100644 subset/security/password/resources/raw/manufacturer.csv create mode 100644 subset/security/password/resources/raw/ssh.txt create mode 100644 subset/security/password/resources/raw/telnet.txt create mode 100755 subset/security/password/run_password_test_for_protocol create mode 100755 subset/security/password/test_password delete mode 100755 subset/security/security_passwords/.classpath delete mode 100755 subset/security/security_passwords/.gitignore delete mode 100755 subset/security/security_passwords/build.gradle delete mode 100755 subset/security/security_passwords/gradle/wrapper/gradle-wrapper.jar delete mode 100755 subset/security/security_passwords/gradle/wrapper/gradle-wrapper.properties delete mode 100755 subset/security/security_passwords/gradlew delete mode 100755 subset/security/security_passwords/gradlew.bat delete mode 100755 subset/security/security_passwords/settings.gradle delete mode 100755 subset/security/security_passwords/src/main/java/BruteForceTester.java delete mode 100755 subset/security/security_passwords/src/main/java/DefaultCredentials.java delete mode 100755 subset/security/security_passwords/src/main/java/PortChecker.java delete mode 100755 subset/security/security_passwords/src/main/java/ReportHandler.java delete mode 100755 subset/security/security_passwords/src/main/java/TestPassword.java delete mode 100755 subset/security/security_passwords/src/main/resources/defaultPasswords.json delete mode 100755 subset/security/test_password diff --git a/docs/device_report.md b/docs/device_report.md index 5e05860613..b9da9c2a8a 100644 --- a/docs/device_report.md +++ b/docs/device_report.md @@ -81,10 +81,10 @@ Overall device result FAIL |fail|protocol.bacnet.pic|Other|Other|PICS file defined however a BACnet device was not found.| |skip|protocol.bacnet.version|Other|Other|Bacnet device not found.| |skip|security.firmware|Other|Other|Could not retrieve a firmware version with nmap. Check bacnet port.| -|skip|security.passwords.http|Other|Other|Port 80 is not open on target device.| -|skip|security.passwords.https|Other|Other|Port 443 is not open on target device.| -|skip|security.passwords.ssh|Other|Other|Port 22 is not open on target device.| -|skip|security.passwords.telnet|Other|Other|Port 23 is not open on target device.| +|skip|security.passwords.http|Other|Other|Port 80 not open on target device.| +|skip|security.passwords.https|Other|Other|Port 443 not open on target device.| +|skip|security.passwords.ssh|Other|Other|Port 22 not open on target device.| +|skip|security.passwords.telnet|Other|Other|Port 23 not open on target device.| |pass|security.ports.nmap|Security|Recommended|Only allowed ports found open.| |skip|security.tls.v1|Other|Other|IOException unable to connect to server| |skip|security.tls.v1.x509|Other|Other|IOException unable to connect to server| @@ -379,92 +379,80 @@ RESULT skip security.tls.v1_3.x509 IOException unable to connect to server ``` -------------------- -security.passwords.http +security.admin.password.http -------------------- -Verify all default passwords are updated and new Google provided passwords are set. +Verify all device manufacturer default passwords are changed for protocol: http, and new passwords are set. -------------------- -[STARTING WITH IP:X.X.X.X, MAC:9a:02:57:1e:8f:01, PROTOCOL: http] -Starting NMAP check... Starting Nmap 7.60 ( https://nmap.org ) at XXX Nmap scan report for daq-faux-1 (X.X.X.X) Host is up (XXX). -PORT STATE SERVICE -10000/tcp open snet-sensor-mgmt +PORT STATE SERVICE +80/tcp closed http MAC Address: 9A:02:57:1E:8F:01 (Unknown) Nmap done: 1 IP address (1 host up) scanned in XXX -nmap X.X.X.X -Done. +Could not connect to specified port on host. -------------------- -RESULT skip security.passwords.http Port 80 is not open on target device. +RESULT skip security.passwords.http Port 80 not open on target device. -------------------- -security.passwords.https +security.admin.password.https -------------------- -Verify all default passwords are updated and new Google provided passwords are set. +Verify all device manufacturer default passwords are changed for protocol: https, and new passwords are set. -------------------- -[STARTING WITH IP:X.X.X.X, MAC:9a:02:57:1e:8f:01, PROTOCOL: https] -Starting NMAP check... Starting Nmap 7.60 ( https://nmap.org ) at XXX Nmap scan report for daq-faux-1 (X.X.X.X) Host is up (XXX). -PORT STATE SERVICE -10000/tcp open snet-sensor-mgmt +PORT STATE SERVICE +443/tcp closed https MAC Address: 9A:02:57:1E:8F:01 (Unknown) Nmap done: 1 IP address (1 host up) scanned in XXX -nmap X.X.X.X -Done. +Could not connect to specified port on host. -------------------- -RESULT skip security.passwords.https Port 443 is not open on target device. +RESULT skip security.passwords.https Port 443 not open on target device. -------------------- -security.passwords.telnet +security.admin.password.ssh -------------------- -Verify all default passwords are updated and new Google provided passwords are set. +Verify all device manufacturer default passwords are changed for protocol: ssh, and new passwords are set. -------------------- -[STARTING WITH IP:X.X.X.X, MAC:9a:02:57:1e:8f:01, PROTOCOL: telnet] -Starting NMAP check... Starting Nmap 7.60 ( https://nmap.org ) at XXX Nmap scan report for daq-faux-1 (X.X.X.X) Host is up (XXX). -PORT STATE SERVICE -10000/tcp open snet-sensor-mgmt +PORT STATE SERVICE +22/tcp closed ssh MAC Address: 9A:02:57:1E:8F:01 (Unknown) Nmap done: 1 IP address (1 host up) scanned in XXX -nmap X.X.X.X -Done. +Could not connect to specified port on host. -------------------- -RESULT skip security.passwords.telnet Port 23 is not open on target device. +RESULT skip security.passwords.ssh Port 22 not open on target device. -------------------- -security.passwords.ssh +security.admin.password.telnet -------------------- -Verify all default passwords are updated and new Google provided passwords are set. +Verify all device manufacturer default passwords are changed for protocol: telnet, and new passwords are set. -------------------- -[STARTING WITH IP:X.X.X.X, MAC:9a:02:57:1e:8f:01, PROTOCOL: ssh] -Starting NMAP check... Starting Nmap 7.60 ( https://nmap.org ) at XXX Nmap scan report for daq-faux-1 (X.X.X.X) Host is up (XXX). -PORT STATE SERVICE -10000/tcp open snet-sensor-mgmt +PORT STATE SERVICE +23/tcp closed telnet MAC Address: 9A:02:57:1E:8F:01 (Unknown) Nmap done: 1 IP address (1 host up) scanned in XXX -nmap X.X.X.X -Done. +Could not connect to specified port on host. -------------------- -RESULT skip security.passwords.ssh Port 22 is not open on target device. +RESULT skip security.passwords.telnet Port 23 not open on target device. ``` @@ -473,6 +461,7 @@ RESULT skip security.passwords.ssh Port 22 is not open on target device. |Attribute|Value| |---|---| |enabled|True| +|dictionary_dir|resources/faux| ## Module udmi diff --git a/subset/security/Dockerfile.test_password b/subset/security/Dockerfile.test_password index cbe38728b0..fb4f7481f1 100644 --- a/subset/security/Dockerfile.test_password +++ b/subset/security/Dockerfile.test_password @@ -1,11 +1,9 @@ FROM daqf/aardvark:latest -RUN $AG update && $AG install openjdk-8-jre -RUN $AG update && $AG install openjdk-8-jdk git -RUN $AG update && $AG install curl -RUN $AG update && $AG install ncrack hydra nmap +# Get dependencies +RUN $AG update && $AG install curl ncrack medusa nmap git -COPY subset/security . -RUN cd security_passwords && ./gradlew shadowJar -RUN ls -l security_passwords/build/libs/security_passwords-1.0-SNAPSHOT-all.jar +COPY subset/security/password . + +# Run the test CMD ["./test_password"] diff --git a/subset/security/password/create_brute_force_dictionaries b/subset/security/password/create_brute_force_dictionaries new file mode 100755 index 0000000000..14345dc17e --- /dev/null +++ b/subset/security/password/create_brute_force_dictionaries @@ -0,0 +1,148 @@ +#!/bin/bash + +# A script to retrieve, and collate several raw brute force dictionaries into a colon separated file with format :username:password, and also to two separate username and password lists. +# +# Make sure this script is run in the password directory. +# +# Usage ./create_brute_force_dictionaries + +RAW_DICTIONARY_DIR="resources/raw" +DEFAULT_DICTIONARY_DIR="resources/default" + +MANUFACTURER_DEFAULTS_DICTIONARY="$RAW_DICTIONARY_DIR/manufacturer.csv" +SSH_DICTIONARY="$RAW_DICTIONARY_DIR/ssh.txt" +TELNET_DICTIONARY="$RAW_DICTIONARY_DIR/telnet.txt" + +OUTPUT_DICTIONARY="$DEFAULT_DICTIONARY_DIR/dictionary.txt" +TMP_DICTIONARY="$DEFAULT_DICTIONARY_DIR/tmp_dictionary.txt" +USERNAMES_LIST="$DEFAULT_DICTIONARY_DIR/usernames.txt" +PASSWORDS_LIST="$DEFAULT_DICTIONARY_DIR/passwords.txt" + +# Retrieve the raw dictionary files from the gitlab source. +# $1 Manufacturer dictionary +# $2 SSH dictionary +# $3 Telnet dictionary +# $4 Raw directory +function retrieve_raw_dictionaries() { + mkdir -p $4 + + curl "https://gitlab.com/kalilinux/packages/seclists/-/raw/094459e5d757faccfcb44375a2e4c9602d5984d4/Passwords/Default-Credentials/default-passwords.csv" \ + --create-dirs --output $1 + curl "https://gitlab.com/kalilinux/packages/seclists/-/raw/094459e5d757faccfcb44375a2e4c9602d5984d4/Passwords/Default-Credentials/ssh-betterdefaultpasslist.txt" \ + --create-dirs --output $2 + curl "https://gitlab.com/kalilinux/packages/seclists/-/raw/094459e5d757faccfcb44375a2e4c9602d5984d4/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt" \ + --create-dirs --output $3 +} + +# Create the temporary and output dictionaries, and remove existing ones. +# $1 Temporary dictionary file +# $2 Output dictionary file +# $3 Default dictionary directory +function create_dictionary() { + mkdir -p $3 + + if [ -f $1 ]; then + rm $1 + fi + + if [ -f $2 ]; then + rm $2 + fi + + touch $1 + touch $2 +} + +# Helps avoid certain special characters which cause grep to fail +# $1 Line string in file +function line_is_invalid_csv() { + echo $1 | grep -sqE "^\".*\"|\s|,," +} + +# Helps avoid certain special usernames/passwords which cause grep to fail. +# $1 Username or password string +function username_or_password_is_invalid() { + echo $1 | grep -sqE "|" +} + +# Append the username and password pair into the output dictionary with colon separation. +# $1 Username +# $2 Password +# $3 Output dictionary +function add_colon_pair_to_output_dictionary() { + if ! username_or_password_is_invalid $1; then + if ! username_or_password_is_invalid $2; then + echo "$1:$2" >> $3 + fi + fi +} + +# Convert lines in the manufacturer csv file into colon separated username:password pairs, then append them to file. +# $1 Raw dictionary +# $2 Output dictionary +function append_manufacturer_csv_to_output_dictionary() { + while read LINE + do + if ! line_is_invalid_csv "$LINE"; then + IFS=',' read -ra CREDENTIAL_ARRAY <<< "$LINE" + USERNAME="${CREDENTIAL_ARRAY[1]}" + PASSWORD="${CREDENTIAL_ARRAY[2]}" + add_colon_pair_to_output_dictionary $USERNAME $PASSWORD $2 + fi + done < $1 +} + +# Add colon separated txt file into the output dictionary. +# $1 Output dictionary file +# $2 Colon separated file +function append_colon_separated_file_to_output_dictionary() { + cat $2 >> $1 +} + +# Runs a few cleanup commands which do the following: +# - Remove trailing whitespace +# - Sort and remove duplicates +# - Finally, add a colon at the start of each line to make it suitable for use in medusa +# +# $1 Temporary dictionary file +# $2 Output dictionary file +function clean_output_dictionary() { + cat $1 | sed -E 's/\s+$//' | sort -u | sed -E 's/^/:/' > $2 +} + +# Removes the necessary bits from the full dictionary to create separate files for usernames and passwords. +# $1 Output dictionary +# $2 Usernames file +# $3 Passwords file +function create_username_and_password_list_from_dictionary() { + cat $1 | sed -E 's/^://' | sed -E 's/:.*$//' > $2 + cat $1 | sed -E 's/^.*://' > $3 +} + +# Main function: + +echo Creating credential files... +create_dictionary $TMP_DICTIONARY $OUTPUT_DICTIONARY $DEFAULT_DICTIONARY_DIR + +echo Retrieving raw dictionaries from sources +retrieve_raw_dictionaries $MANUFACTURER_DEFAULTS_DICTIONARY $SSH_DICTIONARY $TELNET_DICTIONARY $RAW_DICTIONARY_DIR + +echo Parsing CSV file... +append_manufacturer_csv_to_output_dictionary $MANUFACTURER_DEFAULTS_DICTIONARY $TMP_DICTIONARY + +echo Parsing SSH passwords file... +append_colon_separated_file_to_output_dictionary $TMP_DICTIONARY $SSH_DICTIONARY + +echo Parsing telnet passwords file... +append_colon_separated_file_to_output_dictionary $TMP_DICTIONARY $TELNET_DICTIONARY + +echo Cleaning up output dictionary... +clean_output_dictionary $TMP_DICTIONARY $OUTPUT_DICTIONARY + +echo Creating extra dictionaries... +create_username_and_password_list_from_dictionary $OUTPUT_DICTIONARY $USERNAMES_LIST $PASSWORDS_LIST + +echo Removing temporary dictionary... +rm $TMP_DICTIONARY + +echo Done! diff --git a/subset/security/password/resources/default/dictionary.txt b/subset/security/password/resources/default/dictionary.txt new file mode 100644 index 0000000000..681fba73a6 --- /dev/null +++ b/subset/security/password/resources/default/dictionary.txt @@ -0,0 +1,1271 @@ +:11111111:11111111 +:11111:x-admin +:123:234 +:1234:1234 +:22222222:22222222 +:**23646:23646 +:**266344:266344 +:266344:266344 +:2800:2800 +:31994:31994 +:666666:666666 +:7654321:7654321 +:880175445:11223344 +:888888:888888 +:acer:acer +:acitoolkit:acitoolkit +:Adam:29111991 +:ADAMS:WOOD +:ADLDEMO:ADLDEMO +:adm:adm +:admin:0 +:admin:000000 +:admin:1111 +:admin:1111111 +:admin:123 +:admin:123123 +:admin:1234 +:admin:12345 +:admin:123456 +:Admin:123456 +:admin:1234admin +:Admin:123qwe +:admin:1988 +:Admin:1988 +:Admin1:Admin1 +:admin1:password +:admin:2222 +:admin:22222 +:admin2:changeme +:admin:4321 +:Admin:5001 +:admin:abc123 +:admin:access +:admin:admin +:admin:!admin +:Admin:admin +:Admin:Admin +:ADMIN:admin +:ADMIN:ADMIN +:admin:admin000 +:Admin:admin1 +:admin:admin123 +:admin:admin1234 +:admin:adminadmin +:admin:adslolitec +:admin:adslroot +:admin:AitbISP4eCiG +:admin:allot +:admin:alphaadmin +:ADMIN:alphacom +:admin:AlpheusDigital1010 +:admin:amigosw1 +:admin:asante +:admin:Ascend +:admin:asd +:Admin:atc456 +:admin:atlantis +:admin:avocent +:admin:axis2 +:admin:barney +:admin:barricade +:Admin:Barricade +:admin:bintec +:admin:broadband +:admin:brocade1 +:admin:cat1029 +:admin:changeit +:admin:changeme +:admin:cisco +:admin:comcomcom +:admin:conexant +:admin:default +:admin:demo +:admin:detmond +:admin:diamond +:admin:dmr99 +:admin:draadloos +:Admin:Emerson1 +:admin:epicrouter +:Admin:epicrouter +:admin@example.com:admin +:admin:extendnet +:admin:funkwerk +:admin:gvt12345 +:admin:hagpolm1 +:admin:hello +:admin:hipchat +:admin:hp.com +:Admin:ImageFolio +:admin:imss7.0 +:admin:infrant1 +:admin:insecure +:admin:ip20 +:admin:ip21 +:admin:ip3000 +:admin:ip305Beheer +:admin:ip400 +:admin:ironport +:admin:isee +:Administrator:0000 +:administrator:1234 +:Administrator:3ware +:Administrator:adaptec +:Administrator:admin +:ADMINISTRATOR:admin +:administrator:administrator +:Administrator:Administrator +:ADMINISTRATOR:ADMINISTRATOR +:administrator:Amx1234! +:administrator:asecret +:Administrator:changeme +:Administrator:Fiery.1 +:Administrator:Gateway +:Administrator:ggdaseuaimhrke +:Administrator:letmein +:Administrator:manage +:administrator:password +:Administrator:password +:administrator:PlsChgMe! +:Administrator:p@ssw0rd +:Administrator:public +:administrator:root +:administrator:RSAAppliance +:Administrator:smcadmin +:Administrator:storageserver +:Administrator:Unidesk1 +:Administrator:vision2 +:Administrator:Vision2 +:admin:j5Brn9 +:admin:Janitza +:admin:jboss4 +:ADMIN:JETSPEED +:admin:jvc +:admin:leviton +:admin:linga +:admin:ManagementConsole2015 +:admin:meinsm +:admin:michelangelo +:admin:microbusiness +:admin:mono +:admin:motorola +:admin:mp3mystic +:admin:mu +:admin:muze +:admin:my_DEMARC +:admin:netadmin +:admin:NetCache +:admin:netscreen +:admin:NetSeq +:admin:NetSurvibox +:Admin:No +:admin:none +:admin:novell +:admin:noway +:admin:OCS +:admin:OkiLAN +:admin:pass +:Admin:Pass +:admin:password +:Admin:password +:ADMIN:PASSWORD +:admin:passwort +:admin:peribit +:admin:pfsense +:admin:phplist +:admin:private +:admin:public +:admin:pwp +:admin:rainbow +:admin:raritan +:admin:readwrite +:admin:rmnetlm +:admin:root +:Admin:SECRET123 +:admin:secure +:admin:security +:admin:setup +:admin:Sharp +:admin:smallbusiness +:admin:smcadmin +:adminstat:OCS +:adminstrator:changeme +:Admin:Su +:admin:superuser +:admin:su@psir +:admin:surecom +:admin:switch +:admin:symantec +:admin:symbol +:admin:Symbol +:admin:synnet +:admin:sysAdmin +:admin:system +:admin:TANDBERG +:admin:tegile +:admin:tlJwpbo6 +:admin:tomcat +:admin:tsunami +:adminttd:adminttd +:admin:urchin +:adminuser:OCS +:admin:utstar +:adminview:OCS +:admin:waav +:Admin:wago +:admin:welcome +:ADMIN:WELCOME +:admin:x-admin +:admin:year2000 +:admin:ZmqVfoSIP +:admin:zoomadsl +:adsl:adsl1234 +:adtec:none +:ADVMAIL:HP +:Alphanetworks:wapnd03cm_dkbs_dap2555 +:Alphanetworks:wapnd04cm_dkbs_dap3525 +:Alphanetworks:wapnd15_dlob_dap1522b +:Alphanetworks:wrgac01_dlob.hans_dir865 +:Alphanetworks:wrgg15_di524 +:Alphanetworks:wrgg19_c_dlwbr_dir300 +:Alphanetworks:wrgn22_dlwbr_dir615 +:Alphanetworks:wrgn23_dlwbr_dir300b +:Alphanetworks:wrgn23_dlwbr_dir600b +:Alphanetworks:wrgn28_dlob_dir412 +:Alphanetworks:wrgn39_dlob.hans_dir645 +:Alphanetworks:wrgn39_dlob.hans_dir645_V1 +:Alphanetworks:wrgn49_dlob_dir600b +:Alphanetworks:wrgnd08_dlob_dir815 +:amx:Amx1234! +:amx:password +:ANDY:SWORDFISH +:anon:anon +:anonymous:anonymous +:anonymous:any +:anonymous:any@ +:anonymous:Exabyte +:anonymous:password +:Any:12345 +:Any:Any +:(any):TENmanUFactOryPOWER +:AP:AP +:aparker@geometrixx.info:aparker +:apc:apc +:APPLSYS:APPLSYS +:APPLSYS:FND +:APPLSYSPUB:FNDPUB +:APPS:APPS +:APPUSER:APPUSER +:AQ:AQ +:AQDEMO:AQDEMO +:AQJAVA:AQJAVA +:AQUSER:AQUSER +:ARAdmin:AR#Admin# +:ARCHIVIST:ARCHIVIST +:AUDIOUSER:AUDIOUSER +:AURORA@ORB@UNAUTHENTICATED:INVALID +:AURORA$ORB$UNAUTHENTICATED:INVALID +:author:author +:autocad:autocad +:BACKUP:BACKUP +:backuponly:backuponly1 +:backuprestore:backuprestore1 +:basisk:basisk +:Basisk:Basisk +:bbs:bbs +:bbsd-client:changeme2 +:bbsd-client:NULL +:BC4J:BC4J +:bciim:bciimpw +:bcim:bcimpw +:bcms:bcmspw +:bcnas:bcnaspw +:bewan:bewan +:bin:sys +:Blaeri:22332323 +:BLAKE:PAPER +:blue:bluepw +:Bobo:hello +:both:tomcat +:bpel:bpel +:BRIO_ADMIN:BRIO_ADMIN +:browse:browsepw +:browse:looker +:bubba:(unknown) +:cablecom:router +:cac_admin:cacadmin +:CATALOG:CATALOG +:c-comatic:xrtwk318 +:ccrusr:ccrusr +:CDEMO82:CDEMO82 +:CDEMOCOR:CDEMOCOR +:CDEMORID:CDEMORID +:CDEMOUCB:CDEMOUCB +:cellit:cellit +:CENTRA:CENTRA +:cgadmin:cgadmin +:checkfs:checkfs +:checkfsys:checkfsys +:checksys:checksys +:CHEY_ARCHSVR:CHEY_ARCHSVR +:CICSUSER:CISSUS +:CIDS:CIDS +:cirros:cubswin:) +:CIS:CIS +:CISCO15:otbu+1 +:cisco:cisco +:Cisco:Cisco +:CISINFO:CISINFO +:citel:password +:CLARK:CLOTH +:client:client +:cloudera:cloudera +:cmaker:cmaker +:CMSBATCH:CMSBATCH +:cn=orcladmin:welcome +:Coco:hello +:comcast:1234 +:COMPANY:COMPANY +:COMPIERE:COMPIERE +:computer:repair +:conferencing:admin +:config:biodata +:corecess:corecess +:core:phpreactor +:CQSCHEMAUSER:PASSWORD +:craft:craft +:craft:craftpw +:craft:crftpw +:Craft:crftpw +:(created):telus00 +:(created):telus99 +:crowd­-openid-­server:password +:Crowd:password +:CSG:SESAME +:CSMIG:CSMIG +:ctb_admin:sap123 +:CTXDEMO:CTXDEMO +:CTXSYS:CTXSYS +:cusadmin:highspeed +:cust:custpw +:customer:none +:dadmin:dadmin +:dadmin:dadmin01 +:daemon:daemon +:davox:davox +:db2fenc1:db2fenc1 +:db2inst1:db2inst1 +:dbase:dbase +:DBA:SQL +:DBDCCICS:DBDCCIC +:DBI:MUMBLEFRATZ +:DBSNMP:DBSNMP +:DDIC:19920706 +:debian:debian +:debian:sixaola +:debian:temppwd +:debug:d.e.b.u.g +:debug:gubed +:debug:synnet +:d.e.b.u.g:User +:default: +:default:antslq +:default:OxhlwSG8 +:default:S2fGqNFs +:default:video +:default:WLAN_AP +:defug:synnet +:DEMO8:DEMO8 +:DEMO9:DEMO9 +:demo:demo +:DEMO:DEMO +:demo:fai +:Demo:password +:demos:demos +:DES:DES +:deskalt:password +:deskman:changeme +:desknorm:password +:deskres:password +:DEV2000_DEMOS:DEV2000_DEMOS +:dev:dev +:Developer:isdev +:device:apc +:device:device +:diag:danger +:diag:switch +:DIP:DIP +:DISCOVERER_ADMIN:DISCOVERER_ADMIN +:distrib:distrib0 +:disttech:4tas +:disttech:disttech +:disttech:etas +:D-Link:D-Link +:dm:telnet +:dni:dni +:dos:dos +:dpn:changeme +:draytek:1234 +:Draytek:1234 +:DSGATEWAY:DSGATEWAY +:DSL:DSL +:DSSYS:DSSYS +:DTA:TJM +:dvstation:dvst10n +:eagle:eagle +:EARLYWATCH:SUPPORT +:echo:echo +:echo:User +:egcr:ergc +:EJSADMIN:EJSADMIN +:elk_user:forensics +:emaq:4133 +:EMP:EMP +:enable:cisco +:eng:engineer +:engmode:hawk201 +:enisa:enisa +:enquiry:enquirypw +:ESTOREUSER:ESTORE +:eurek:eurek +:EVENT:EVENT +:EXFSYS:EXFSYS +:expert:expert +:Factory:56789 +:factory:Fact4EMC +:fal:fal +:fam:fam +:fastwire:fw +:fax:fax +:FAX:FAX +:FAXUSER:FAXUSER +:FAXWORKS:FAXWORKS +:fg_sysadmin:password +:field:field +:FIELD:HPONLY +:FIELD:LOTUS +:FIELD:MANAGER +:FIELD:MGR +:FIELD:SERVICE +:field:support +:FIELD:SUPPORT +:FINANCE:FINANCE +:firstsite:firstsite +:Flo:hello +:FND:FND +:FORSE:FORSE +:FROSTY:SNOWMAN +:ftp_admi:kilo1987 +:ftp:ftp +:ftp_inst:pbxk1064 +:ftp_nmc:tuxalize +:ftp_oper:help1954 +:ftpuser:password +:ftp:video +:fwadmin:xceladmin +:fwupgrade:fwupgrade +:games:games +:GATEWAY:GATEWAY +:Gearguy:Geardog +:GE:GE +:geosolutions:Geos +:glftpd:glftpd +:GL:GL +:god1:12345 +:god2:12345 +:gopher:gopher +:GPFD:GPFD +:GPLD:GPLD +:guest:1234 +:guest:12345 +:guest1:guest +:guest1:guest1 +:guest:guest +:Guest:guest +:Guest:Guest +:GUEST:GUEST +:guest:guestgue +:GUEST:GUESTGUE +:GUEST:GUESTGUEST +:guest:Janitza +:guest:truetime +:GUEST:TSEUG +:guest:User +:guru:*3noguru +:halt:halt +:HCPARK:HCPARK +:HELLO:FIELD.SUPPORT +:hello:hello +:HELLO:MANAGER.SYS +:HELLO:MGR.SYS +:HELLO:OP.OPERATOR +:helpdesk:OCS +:HLW:HLW +:(hostname/ipaddress):sysadmin +:HPLASER:HPLASER +:HPSupport:badg3r5 +:HR:HR +:hsa:hsadb +:hscroot:abc123 +:HTTP:HTTP +:hunter:hunter +:hxeadm:HXEHana1 +:ibm:2222 +:ibm:password +:ibm:service +:IBMUSER:SYS1 +:iclock:timely +:ilom-admin:ilom-admin +:ilom-operator:ilom-operator +:images:images +:IMAGEUSER:IMAGEUSER +:IMEDIA:IMEDIA +:inads:inads +:inads:indspw +:informix:informix +:init:initpw +:installer:1000 +:installer:installer +:install:install +:install:secret +:intel:intel +:intermec:intermec +:internal:oracle +:IntraStack:Asante +:IntraSwitch:Asante +:ioFTPD:ioFTPD +:IS_$hostname:IS_$hostname +:itsadmin:init +:james:james +:jdoe@geometrixx.info:jdoe +:JMUSER:JMUSER +:Joe:hello +:joe:password +:JONES:STEEL +:JWARD:AIROPLANE +:keyscan:KEYSCAN +:khan:kahn +:kodi:kodi +:l2:l2 +:L2LDEMO:L2LDEMO +:l3:l3 +:LASER:LASER +:LASERWRITER:LASERWRITER +:LBACSYS:LBACSYS +:LDAP_Anonymous:LdapPassword_1 +:leo:leo +:LIBRARIAN:SHELVES +:Liebert:Liebert +:live:live +:LocalAdministrator:#l@$ak#.lk;0@P +:localadmin:localadmin +:locate:locatepw +:login:0000 +:login:access +:login:admin +:login:password +:lpadmin:lpadmin +:lpadm:lpadm +:lp:bin +:lp:lineprin +:lp:lp +:LR-ISDN:LR-ISDN +:lynx:lynx +:m1122:m1122 +:m202:m202 +:MAIL:HPOFFICE +:mail:mail +:MAIL:MAIL +:MAIL:MPE +:MAIL:REMOTE +:MAIL:TELESUP +:maintainer:admin +:maintainer:pbcpbn(add-serial-number) +:maint:maint +:MAINT:MAINT +:maint:maintpw +:maint:ntacdmax +:maint:password +:maint:rwmaint +:Manager:Admin +:MANAGER:COGNOS +:manager:friend +:MANAGER:HPOFFICE +:MANAGER:ITF3000 +:manager:manager +:Manager:Manager +:MANAGER:SECURITY +:managers:managers +:MANAGER:SYS +:MANAGER:TCH +:MANAGER:TELESUP +:man:man +:manuf:xxyyzz +:mary:password +:master:master +:MASTER:PASSWORD +:master:themaster01 +:MayGion:maygion.com +:McdataSE:redips +:MCUser:MCUser1 +:MD110:help +:MDDEMO_CLERK:CLERK +:MDDEMO:MDDEMO +:MDDEMO_MGR:MGR +:MDSYS:MDSYS +:mediator:mediator +:me:me +:memotec:supervisor +:Menara:Menara +:mfd:mfd +:MFG:MFG +:mg3500:merlin +:MGE:VESOFT +:MGR:CAROLIAN +:MGR:CCC +:MGR:CNAS +:MGR:COGNOS +:MGR:CONV +:MGR:HPDESK +:MGR:HPOFFICE +:MGR:HPONLY +:MGR:HPP187 +:MGR:HPP189 +:MGR:HPP196 +:MGR:INTX3 +:MGR:ITF3000 +:MGR:NETBASE +:MGR:REGO +:MGR:RJE +:MGR:ROBELLE +:MGR:SECURITY +:MGR:SYS +:MGR:TELESUP +:MGR:VESOFT +:MGR:WORD +:MGR:XLSERVER +:MGWUSER:MGWUSER +:MICRO:RSX +:MIGRATE:MIGRATE +:MILLER:MILLER +:misp:Password1234 +:mlusr:mlusr +:MMO2:MMO2 +:mobile:dottie +:MODTEST:YES +:Moe:hello +:monitor:monitor +:MOREAU:MOREAU +:mountfs:mountfs +:mountfsys:mountfsys +:mountsys:mountsys +:MSHOME:MSHOME +:mso:w0rkplac3rul3s +:MTSSYS:MTSSYS +:MTS_USER:MTS_PASSWORD +:MTYSYS:MTYSYS +:museadmin:Muse!Admin +:musi1921:Musi%1921 +:musi1921:Musii%1921 +:MXAGENT:MXAGENT +:myshake:shakeme +:naadmin:naadmin +:n.a:guardone +:NAMES:NAMES +:nao:nao +:NAU:NAU +:ncrm:ncrm +:netbotz:netbotz +:netlink:netlink +:NetLinx:password +:netman:netman +:netopia:netopia +:netrangr:attack +:netscreen:netscreen +:NETWORK:NETWORK +:news:news +:newuser:wampp +:nexthink:123456 +:NICONEX:NICONEX +:nm2user:nm2user +:nms:nmspw +:nobody:nobody +:none:0 +:none:4321 +:none:admin +:none:blank +:none:none +:none:private +:none:sysadm +:nop:12345 +:nop:123454 +:NSA:nsa +:OAS_PUBLIC:OAS_PUBLIC +:OCITEST:OCITEST +:ODM_MTR:MTRPW +:ODM:ODM +:ODSCOMMON:ODSCOMMON +:ods:ods +:ODS:ODS +:OEMADM:OEMADM +:OEMREP:OEMREP +:OE:OE +:OLAPDBA:OLAPDBA +:OLAPSVR:INSTANCE +:OLAPSYS:MANAGER +:OMWB_EMULATION:ORACLE +:onlime_r:12345 +:OO:OO +:openhabian:openhabian +:OPENSPIRIT:OPENSPIRIT +:OPERATIONS:OPERATIONS +:OPERATNS:OPERATNS +:operator:admin +:operator:$chwarzepumpe +:OPERATOR:COGNOS +:OPERATOR:DISC +:operator:mercury +:operator:operator +:Operator:Operator +:OPERATOR:SUPPORT +:OPERATOR:SYS +:OPERATOR:SYSTEM +:Oper:Oper +:OPER:OPER +:op:op +:op:operator +:oracle:oracle +:ORAREGSYS:ORAREGSYS +:ORASSO:ORASSO +:ORDPLUGINS:ORDPLUGINS +:ORDSYS:ORDSYS +:osbash:osbash +:osboxes:osboxes.org +:osmc:osmc +:OSP22:OSP22 +:OUTLN:OUTLN +:overseer:overseer +:OWA:OWA +:OWA_PUBLIC:OWA_PUBLIC +:OWNER:OWNER +:PACSLinkIP:NetServer +:PANAMA:PANAMA +:patrol:patrol +:PATROL:PATROL +:PBX:PBX +:PCUSER:SYS +:pepino:pepino +:PERFSTAT:PERFSTAT +:PFCUser:240653C9467E45 +:piranha:piranha +:piranha:q +:pi:raspberry +:PLEX:PLEX +:plexuser:rasplex +:PLMIMService:NetServer +:PLSQL:SUPERSECRET +:PM:PM +:pnadmin:pnadmin +:PO7:PO7 +:PO8:PO8 +:politically:correct +:poll:tech +:Polycom:SpIp +:PO:PO +:PORTAL30_DEMO:PORTAL30_DEMO +:PORTAL30:PORTAL30 +:PORTAL30:PORTAL31 +:PORTAL30_PUBLIC:PORTAL30_PUBLIC +:PORTAL30_SSO:PORTAL30_SSO +:PORTAL30_SSO_PS:PORTAL30_SSO_PS +:PORTAL30_SSO_PUBLIC:PORTAL30_SSO_PUBLIC +:POST:BASE +:postmaster:postmast +:POST:POST +:POWERCARTUSER:POWERCARTUSER +:POWERCHUTE:APC +:powerdown:powerdown +:praisenetwork:perfectpraise +:PRIMARY:PRIMARY +:primenet:primenet +:primenet:primeos +:primeos:prime +:primeos:primeos +:prime:prime +:prime:primeos +:primos_cs:prime +:primos_cs:primos +:PRINTER:PRINTER +:PRINT:PRINT +:PRODCICS:PRODCICS +:PRODDTA:PRODDTA +:PROG:PROG +:prtgadmin:prtgadmin +:PSEAdmin:$secure$ +:public:publicpass +:PUBSUB1:PUBSUB1 +:PUBSUB:PUBSUB +:pw:pwpw +:pwrchute:pwrchute +:pyimagesearch:deeplearning +:qbf77101:hexakisoctahedron +:QDBA:QDBA +:qpgmr:qpgmr +:QS_ADM:QS_ADM +:QS_CBADM:QS_CBADM +:QS_CB:QS_CB +:QS_CS:QS_CS +:qsecofr:11111111 +:qsecofr:22222222 +:qsecofr:qsecofr +:qserv:qserv +:QS_ES:QS_ES +:QS_OS:QS_OS +:QS:QS +:QSRV:11111111 +:QSRV:22222222 +:qsrvbas:qsrvbas +:qsrv:qsrv +:QSRV:QSRV +:qsvr:ibmcel +:qsvr:qsvr +:QS_WS:QS_WS +:qsysopr:qsysopr +:quser:quser +:radware:radware +:RAID:hpt +:rapport:r@p8p0r+ +:rcust:rcustpw +:rdc123:rdc123 +:readonly:apc +:readonly:lucenttech2 +:read:synnet +:readwrite:lucenttech1 +:recover:recover +:redline:redline +:remnux:malware +:REPADMIN:REPADMIN +:replication-receiver:replication-receiver +:Replicator:iscopy +:replicator:replicator +:REP_MANAGER:DEMO +:REPORTS_USER:OEM_TEMP +:REP_OWNER:DEMO +:REP_OWNER:REP_OWNER +:RE:RE +:restoreonly:restoreonly1 +:rje:rje +:RMAIL:RMAIL +:RMAN:RMAN +:RMUser1:password +:RNIServiceManager:NetServer +:Rodopi:Rodopi +:role1:role1 +:role1:tomcat +:role:changethis +:root:00000000 +:root:1001chin +:root:1111 +:root:1234 +:root:12345 +:root:123456 +:root:20080826 +:root:3ep5w2u +:root:54321 +:root:5up +:root:666666 +:root:7ujMko0admin +:root:7ujMko0vizxv +:root:888888 +:root:8RttoTriz +:root:admin +:root:ahetzip8 +:root:alpine +:root:anko +:root:anni2013 +:root:arcsight +:root:ascend +:root:attack +:root:ax400 +:root:bagabu +:root:blablabla +:root:blackarch +:root:blender +:root:brightmail +:root:calvin +:root:cat1029 +:root:ceadmin +:root:changeme +:root:changeonfirstlogin +:root:changethis +:root:china123 +:root:Cisco +:root:ciwuxe +:root:cms500 +:root:cubox-i +:root:cxlinux +:root:D13HH[ +:root:dasdec1 +:root:davox +:root:debian +:root:default +:root:dottie +:root:dreambox +:root:fai +:root:fibranne +:root:fidel123 +:root:freenas +:root:ggdaseuaimhrke +:root:GM8182 +:root:hi3518 +:root:hp +:root:ikwb +:root:indigo +:root:juantech +:root:jvbzd +:root:klv123 +:root:klv1234 +:root:kn1TG7psLu +:root:leostream +:root:libreelec +:root:linux +:root:logapp +:root:manager +:root:max2play +:root:mozart +:root:mpegvideo +:root:Mua'dib +:root:MuZhlo9n%8!G +:root:nas4free +:root:NeXT +:root:NM1$88 +:root:nokia +:root:nosoup4u +:root:nsi +:root:oelinux123 +:root:openelec +:root:openmediavault +:root:orion99 +:root:osboxes.org +:root:palosanto +:root:par0t +:root:pass +:root:passw0rd +:root:password +:root:p@ck3tf3nc3 +:root:pixmet2003 +:root:plex +:root:qwasyx21 +:root:rasplex +:root:realtek +:root:resumix +:root:root +:root:!root +:ROOT:ROOT +:root:root01 +:root:ROOT500 +:root:rootme +:root:rootpasswd +:root:screencast +:root:secur4u +:root:Serv4EMC +:root:sipwise +:root:sixaola +:root:stxadmin +:root:sun123 +:root:system +:root:t00lk1t +:root:t0talc0ntr0l4! +:root:TANDBERG +:root:timeserver +:root:toor +:root:tslinux +:root:ubnt +:root:ubuntu1404 +:root:uClinux +:root:unitrends1 +:root:user +:root:vagrant +:root:vertex25 +:root:video +:root:vizxv +:Root:wago +:root:wyse +:root:xc3511 +:root:xmhdipc +:root:xoa +:root:ys123456 +:root:zlxx +:root:zlxx. +:root:Zte521 +:ro:ro +:RSBCMON:SYS +:rwa:rwa +:rw:rw +:sa:changeonfirstlogin +:SAMPLE:SAMPLE +:sansforensics:forensics +:sans:training +:SAP*:06071992 +:SAP*:7061992 +:SA:PASSWORD +:SAPCPIC:admin +:SAPCPIC:ADMIN +:SAP*:PASS +:SAPR3:SAP +:SAP:SAPR3 +:sa:sasasa +:savelogs:crash +:scmadmin:scmchangeme +:sconsole:12345 +:SCOTT:TIGER +:SDOS_ICSAP:SDOS_ICSAP +:SECDEMO:SECDEMO +:secofr:secofr +:security:security +:sedacm:secacm +:self:system +:SERVICECONSUMER1:SERVICECONSUMER1 +:service:service +:Service:Service +:service:smile +:servlet:manager +:setpriv:system +:setup:changeme +:setup:changeme! +:setup:setup +:SH:SH +:shutdown:shutdown +:signa:signa +:siteadmin:siteadmin +:siteadmin:toplayer +:SITEMINDER:SITEMINDER +:SLIDE:SLIDEPW +:smc:smcadmin +:SMDR:SECONDARY +:snmp:nopasswd +:snmp:snmp +:spcl:0000 +:SPOOLMAN:HPOFFICE +:$SRV:$SRV +:ssladmin:ssladmin +:ssp:ssp +:stackato:stackato +:STARTER:STARTER +:status:readonly +:stratacom:stratauser +:STRAT_USER:STRAT_PASSWD +:stuccoboy:100198 +:super:5777364 +:__super:(caclulated) +:superdba:admin +:super:juniper123 +:superman:21241036 +:superman:talent +:super:super +:super.super:master +:super:superpass +:super:surt +:superuser:123456 +:superuser:admin +:SUPERUSER:ANS#150 +:superuser:asante +:SuperUser:kronites +:superuser:superuser +:SUPERVISOR:HARRIS +:SUPERVISOR:NETFRAME +:SUPERVISOR:NF +:SUPERVISOR:NFI +:supervisor:PlsChgMe! +:supervisor:supervisor +:SUPERVISOR:SUPERVISOR +:SUPERVISOR:SYSTEM +:supervisor:visor +:support:h179350 +:support:support +:support:supportpw +:support:symantec +:su:super +:sweex:mysweex +:SWPRO:SWPRO +:SWUSER:SWUSER +:Symbol:Symbol +:SYMPA:SYMPA +:sync:sync +:sysadm:admin +:sysadm:Admin +:sysadm:admpw +:sysadmin:master +:sysadmin:nortel +:sysadmin:password +:sysadmin:sysadmin +:sysadm:sysadm +:SYSADM:SYSADM +:sysadm:sysadmpw +:sysadm:syspw +:SYSA:SYSA +:sys:bin +:sysbin:sysbin +:sys:change_on_install +:SYS:CHANGE_ON_INSTALL +:SYSDBA:masterkey +:SYS:D_SYSPW +:SYSMAN:oem_temp +:SYSMAN:OEM_TEMP +:sysopr:sysopr +:Sysop:Sysop +:sys:sys +:sys:system +:system:adminpwd +:system_admin:system_admin +:SYSTEM:D_SYSTPW +:system:isp +:system:manager +:SYSTEM:MANAGER +:system/manager:sys/change_on_install +:system:mnet +:system:password +:system:prime +:system:security +:system:sys +:system:system +:system:weblogic +:sys:uplink +:t3admin:Trintech +:TAHITI:TAHITI +:target:password +:tasman:tasmannet +:Tasman:Tasmannet +:TDOS_ICSAP:TDOS_ICSAP +:teacher:password +:tech:field +:tech:nician +:technician:yZgO8Bvj +:tech:tech +:telecom:telecom +:Telecom:Telecom +:tele:tele +:tellabs:tellabs#1 +:temp1:password +:TESTPILOT:TESTPILOT +:test:test +:TEST:TEST +:tiger:tiger123 +:tomcat:changethis +:tomcat:tomcat +:toor:logapp +:topicalt:password +:topicnorm:password +:topicres:password +:TRACESRV:TRACE +:TRACESVR:TRACE +:TRAVEL:TRAVEL +:trmcnfg:trmcnfg +:trouble:trouble +:TSDEV:TSDEV +:TSUSER:TSUSER +:TURBINE:TURBINE +:ubnt:ubnt +:ucenik23:ucenik +:ULTIMATE:ULTIMATE +:umountfs:umountfs +:umountfsys:umountfsys +:umountsys:umountsys +:unix:unix +:USER0:USER0 +:User:1001 +:User:1234 +:User:19750407 +:USER1:USER1 +:USER2:USER2 +:USER3:USER3 +:USER4:USER4 +:USER5:USER5 +:USER6:USER6 +:USER7:USER7 +:USER8:USER8 +:USER9:USER9 +:user_analyst:demo +:user_approver:demo +:user_author:demo +:user_checker:demo +:user_designer:demo +:user_editor:demo +:user_expert:demo +:USERID:PASSW0RD +:USERID:PASSWORD +:user:Janitza +:user_marketer:demo +:username:password +:Username:password +:Username:Password +:user:none +:userNotUsed:userNotU +:user:password +:User:Password +:user_pricer:demo +:user:public +:user_publisher:demo +:USER_TEMPLATE:USER_TEMPLATE +:user:tivonpw +:user:user +:User:user +:User:User +:USER:USER +:user:user0000 +:user:USERP +:UTLBSTATU:UTLESTAT +:uucpadm:uucpadm +:uucp:uucp +:uwmadmin:password +:vagrant:vagrant +:VCSRV:VCSRV +:veda:12871 +:vgnadmin:vgnadmin +:viewuser:viewuser1 +:VIF_DEVELOPER:VIF_DEV_PWD +:vikram:singh +:VIRUSER:VIRUSER +:VNC:winterm +:volition:volition +:vpasp:vpasp +:VRR1:VRR1 +:VTAM:VTAM +:WANGTEK:WANGTEK +:webadmin:1234 +:WebAdmin:Admin +:webadmin:webadmin +:WebAdmin:WebBoard +:webadmin:webibm +:WEBADM:password +:WEBCAL01:WEBCAL01 +:webdb:webdb +:WEBDB:WEBDB +:webguest:1 +:weblogic:weblogic +:webmaster:webmaster +:WEBREAD:WEBREAD +:webshield:webshieldchangeme +:web:web +:whd:whd +:WINDOWS_PASSTHRU:WINDOWS_PASSTHRU +:WINSABRE:SABRE +:WINSABRE:WINSABRE +:WKSYS:WKSYS +:wlcsystem:wlcsystem +:wlpisystem:wlpisystem +:wlseuser:wlsepassword +:wlse:wlsedb +:WP:HPOFFICE +:wpsadmin:wpsadmin +:wradmin:trancell +:write:private +:write:synnet +:wVQxyQec:eomjbOBLLwbZeiKV +:WWWUSER:WWWUSER +:www:www +:WWW:WWW +:xd:xd +:xmi_demo:sap123 +:XPRT:XPRT +:XXSESS_MGRYY:X#1833 diff --git a/subset/security/password/resources/default/passwords.txt b/subset/security/password/resources/default/passwords.txt new file mode 100644 index 0000000000..d9f319e79c --- /dev/null +++ b/subset/security/password/resources/default/passwords.txt @@ -0,0 +1,1271 @@ +11111111 +x-admin +234 +1234 +22222222 +23646 +266344 +266344 +2800 +31994 +666666 +7654321 +11223344 +888888 +acer +acitoolkit +29111991 +WOOD +ADLDEMO +adm +0 +000000 +1111 +1111111 +123 +123123 +1234 +12345 +123456 +123456 +1234admin +123qwe +1988 +1988 +Admin1 +password +2222 +22222 +changeme +4321 +5001 +abc123 +access +admin +!admin +admin +Admin +admin +ADMIN +admin000 +admin1 +admin123 +admin1234 +adminadmin +adslolitec +adslroot +AitbISP4eCiG +allot +alphaadmin +alphacom +AlpheusDigital1010 +amigosw1 +asante +Ascend +asd +atc456 +atlantis +avocent +axis2 +barney +barricade +Barricade +bintec +broadband +brocade1 +cat1029 +changeit +changeme +cisco +comcomcom +conexant +default +demo +detmond +diamond +dmr99 +draadloos +Emerson1 +epicrouter +epicrouter +admin +extendnet +funkwerk +gvt12345 +hagpolm1 +hello +hipchat +hp.com +ImageFolio +imss7.0 +infrant1 +insecure +ip20 +ip21 +ip3000 +ip305Beheer +ip400 +ironport +isee +0000 +1234 +3ware +adaptec +admin +admin +administrator +Administrator +ADMINISTRATOR +Amx1234! +asecret +changeme +Fiery.1 +Gateway +ggdaseuaimhrke +letmein +manage +password +password +PlsChgMe! +p@ssw0rd +public +root +RSAAppliance +smcadmin +storageserver +Unidesk1 +vision2 +Vision2 +j5Brn9 +Janitza +jboss4 +JETSPEED +jvc +leviton +linga +ManagementConsole2015 +meinsm +michelangelo +microbusiness +mono +motorola +mp3mystic +mu +muze +my_DEMARC +netadmin +NetCache +netscreen +NetSeq +NetSurvibox +No +none +novell +noway +OCS +OkiLAN +pass +Pass +password +password +PASSWORD +passwort +peribit +pfsense +phplist +private +public +pwp +rainbow +raritan +readwrite +rmnetlm +root +SECRET123 +secure +security +setup +Sharp +smallbusiness +smcadmin +OCS +changeme +Su +superuser +su@psir +surecom +switch +symantec +symbol +Symbol +synnet +sysAdmin +system +TANDBERG +tegile +tlJwpbo6 +tomcat +tsunami +adminttd +urchin +OCS +utstar +OCS +waav +wago +welcome +WELCOME +x-admin +year2000 +ZmqVfoSIP +zoomadsl +adsl1234 +none +HP +wapnd03cm_dkbs_dap2555 +wapnd04cm_dkbs_dap3525 +wapnd15_dlob_dap1522b +wrgac01_dlob.hans_dir865 +wrgg15_di524 +wrgg19_c_dlwbr_dir300 +wrgn22_dlwbr_dir615 +wrgn23_dlwbr_dir300b +wrgn23_dlwbr_dir600b +wrgn28_dlob_dir412 +wrgn39_dlob.hans_dir645 +wrgn39_dlob.hans_dir645_V1 +wrgn49_dlob_dir600b +wrgnd08_dlob_dir815 +Amx1234! +password +SWORDFISH +anon +anonymous +any +any@ +Exabyte +password +12345 +Any +TENmanUFactOryPOWER +AP +aparker +apc +APPLSYS +FND +FNDPUB +APPS +APPUSER +AQ +AQDEMO +AQJAVA +AQUSER +AR#Admin# +ARCHIVIST +AUDIOUSER +INVALID +INVALID +author +autocad +BACKUP +backuponly1 +backuprestore1 +basisk +Basisk +bbs +changeme2 +NULL +BC4J +bciimpw +bcimpw +bcmspw +bcnaspw +bewan +sys +22332323 +PAPER +bluepw +hello +tomcat +bpel +BRIO_ADMIN +browsepw +looker +(unknown) +router +cacadmin +CATALOG +xrtwk318 +ccrusr +CDEMO82 +CDEMOCOR +CDEMORID +CDEMOUCB +cellit +CENTRA +cgadmin +checkfs +checkfsys +checksys +CHEY_ARCHSVR +CISSUS +CIDS +) +CIS +otbu+1 +cisco +Cisco +CISINFO +password +CLOTH +client +cloudera +cmaker +CMSBATCH +welcome +hello +1234 +COMPANY +COMPIERE +repair +admin +biodata +corecess +phpreactor +PASSWORD +craft +craftpw +crftpw +crftpw +telus00 +telus99 +password +password +SESAME +CSMIG +sap123 +CTXDEMO +CTXSYS +highspeed +custpw +none +dadmin +dadmin01 +daemon +davox +db2fenc1 +db2inst1 +dbase +SQL +DBDCCIC +MUMBLEFRATZ +DBSNMP +19920706 +debian +sixaola +temppwd +d.e.b.u.g +gubed +synnet +User + +antslq +OxhlwSG8 +S2fGqNFs +video +WLAN_AP +synnet +DEMO8 +DEMO9 +demo +DEMO +fai +password +demos +DES +password +changeme +password +password +DEV2000_DEMOS +dev +isdev +apc +device +danger +switch +DIP +DISCOVERER_ADMIN +distrib0 +4tas +disttech +etas +D-Link +telnet +dni +dos +changeme +1234 +1234 +DSGATEWAY +DSL +DSSYS +TJM +dvst10n +eagle +SUPPORT +echo +User +ergc +EJSADMIN +forensics +4133 +EMP +cisco +engineer +hawk201 +enisa +enquirypw +ESTORE +eurek +EVENT +EXFSYS +expert +56789 +Fact4EMC +fal +fam +fw +fax +FAX +FAXUSER +FAXWORKS +password +field +HPONLY +LOTUS +MANAGER +MGR +SERVICE +support +SUPPORT +FINANCE +firstsite +hello +FND +FORSE +SNOWMAN +kilo1987 +ftp +pbxk1064 +tuxalize +help1954 +password +video +xceladmin +fwupgrade +games +GATEWAY +Geardog +GE +Geos +glftpd +GL +12345 +12345 +gopher +GPFD +GPLD +1234 +12345 +guest +guest1 +guest +guest +Guest +GUEST +guestgue +GUESTGUE +GUESTGUEST +Janitza +truetime +TSEUG +User +*3noguru +halt +HCPARK +FIELD.SUPPORT +hello +MANAGER.SYS +MGR.SYS +OP.OPERATOR +OCS +HLW +sysadmin +HPLASER +badg3r5 +HR +hsadb +abc123 +HTTP +hunter +HXEHana1 +2222 +password +service +SYS1 +timely +ilom-admin +ilom-operator +images +IMAGEUSER +IMEDIA +inads +indspw +informix +initpw +1000 +installer +install +secret +intel +intermec +oracle +Asante +Asante +ioFTPD +IS_$hostname +init +james +jdoe +JMUSER +hello +password +STEEL +AIROPLANE +KEYSCAN +kahn +kodi +l2 +L2LDEMO +l3 +LASER +LASERWRITER +LBACSYS +LdapPassword_1 +leo +SHELVES +Liebert +live +#l@$ak#.lk;0@P +localadmin +locatepw +0000 +access +admin +password +lpadmin +lpadm +bin +lineprin +lp +LR-ISDN +lynx +m1122 +m202 +HPOFFICE +mail +MAIL +MPE +REMOTE +TELESUP +admin +pbcpbn(add-serial-number) +maint +MAINT +maintpw +ntacdmax +password +rwmaint +Admin +COGNOS +friend +HPOFFICE +ITF3000 +manager +Manager +SECURITY +managers +SYS +TCH +TELESUP +man +xxyyzz +password +master +PASSWORD +themaster01 +maygion.com +redips +MCUser1 +help +CLERK +MDDEMO +MGR +MDSYS +mediator +me +supervisor +Menara +mfd +MFG +merlin +VESOFT +CAROLIAN +CCC +CNAS +COGNOS +CONV +HPDESK +HPOFFICE +HPONLY +HPP187 +HPP189 +HPP196 +INTX3 +ITF3000 +NETBASE +REGO +RJE +ROBELLE +SECURITY +SYS +TELESUP +VESOFT +WORD +XLSERVER +MGWUSER +RSX +MIGRATE +MILLER +Password1234 +mlusr +MMO2 +dottie +YES +hello +monitor +MOREAU +mountfs +mountfsys +mountsys +MSHOME +w0rkplac3rul3s +MTSSYS +MTS_PASSWORD +MTYSYS +Muse!Admin +Musi%1921 +Musii%1921 +MXAGENT +shakeme +naadmin +guardone +NAMES +nao +NAU +ncrm +netbotz +netlink +password +netman +netopia +attack +netscreen +NETWORK +news +wampp +123456 +NICONEX +nm2user +nmspw +nobody +0 +4321 +admin +blank +none +private +sysadm +12345 +123454 +nsa +OAS_PUBLIC +OCITEST +MTRPW +ODM +ODSCOMMON +ods +ODS +OEMADM +OEMREP +OE +OLAPDBA +INSTANCE +MANAGER +ORACLE +12345 +OO +openhabian +OPENSPIRIT +OPERATIONS +OPERATNS +admin +$chwarzepumpe +COGNOS +DISC +mercury +operator +Operator +SUPPORT +SYS +SYSTEM +Oper +OPER +op +operator +oracle +ORAREGSYS +ORASSO +ORDPLUGINS +ORDSYS +osbash +osboxes.org +osmc +OSP22 +OUTLN +overseer +OWA +OWA_PUBLIC +OWNER +NetServer +PANAMA +patrol +PATROL +PBX +SYS +pepino +PERFSTAT +240653C9467E45 +piranha +q +raspberry +PLEX +rasplex +NetServer +SUPERSECRET +PM +pnadmin +PO7 +PO8 +correct +tech +SpIp +PO +PORTAL30_DEMO +PORTAL30 +PORTAL31 +PORTAL30_PUBLIC +PORTAL30_SSO +PORTAL30_SSO_PS +PORTAL30_SSO_PUBLIC +BASE +postmast +POST +POWERCARTUSER +APC +powerdown +perfectpraise +PRIMARY +primenet +primeos +prime +primeos +prime +primeos +prime +primos +PRINTER +PRINT +PRODCICS +PRODDTA +PROG +prtgadmin +$secure$ +publicpass +PUBSUB1 +PUBSUB +pwpw +pwrchute +deeplearning +hexakisoctahedron +QDBA +qpgmr +QS_ADM +QS_CBADM +QS_CB +QS_CS +11111111 +22222222 +qsecofr +qserv +QS_ES +QS_OS +QS +11111111 +22222222 +qsrvbas +qsrv +QSRV +ibmcel +qsvr +QS_WS +qsysopr +quser +radware +hpt +r@p8p0r+ +rcustpw +rdc123 +apc +lucenttech2 +synnet +lucenttech1 +recover +redline +malware +REPADMIN +replication-receiver +iscopy +replicator +DEMO +OEM_TEMP +DEMO +REP_OWNER +RE +restoreonly1 +rje +RMAIL +RMAN +password +NetServer +Rodopi +role1 +tomcat +changethis +00000000 +1001chin +1111 +1234 +12345 +123456 +20080826 +3ep5w2u +54321 +5up +666666 +7ujMko0admin +7ujMko0vizxv +888888 +8RttoTriz +admin +ahetzip8 +alpine +anko +anni2013 +arcsight +ascend +attack +ax400 +bagabu +blablabla +blackarch +blender +brightmail +calvin +cat1029 +ceadmin +changeme +changeonfirstlogin +changethis +china123 +Cisco +ciwuxe +cms500 +cubox-i +cxlinux +D13HH[ +dasdec1 +davox +debian +default +dottie +dreambox +fai +fibranne +fidel123 +freenas +ggdaseuaimhrke +GM8182 +hi3518 +hp +ikwb +indigo +juantech +jvbzd +klv123 +klv1234 +kn1TG7psLu +leostream +libreelec +linux +logapp +manager +max2play +mozart +mpegvideo +Mua'dib +MuZhlo9n%8!G +nas4free +NeXT +NM1$88 +nokia +nosoup4u +nsi +oelinux123 +openelec +openmediavault +orion99 +osboxes.org +palosanto +par0t +pass +passw0rd +password +p@ck3tf3nc3 +pixmet2003 +plex +qwasyx21 +rasplex +realtek +resumix +root +!root +ROOT +root01 +ROOT500 +rootme +rootpasswd +screencast +secur4u +Serv4EMC +sipwise +sixaola +stxadmin +sun123 +system +t00lk1t +t0talc0ntr0l4! +TANDBERG +timeserver +toor +tslinux +ubnt +ubuntu1404 +uClinux +unitrends1 +user +vagrant +vertex25 +video +vizxv +wago +wyse +xc3511 +xmhdipc +xoa +ys123456 +zlxx +zlxx. +Zte521 +ro +SYS +rwa +rw +changeonfirstlogin +SAMPLE +forensics +training +06071992 +7061992 +PASSWORD +admin +ADMIN +PASS +SAP +SAPR3 +sasasa +crash +scmchangeme +12345 +TIGER +SDOS_ICSAP +SECDEMO +secofr +security +secacm +system +SERVICECONSUMER1 +service +Service +smile +manager +system +changeme +changeme! +setup +SH +shutdown +signa +siteadmin +toplayer +SITEMINDER +SLIDEPW +smcadmin +SECONDARY +nopasswd +snmp +0000 +HPOFFICE +$SRV +ssladmin +ssp +stackato +STARTER +readonly +stratauser +STRAT_PASSWD +100198 +5777364 +(caclulated) +admin +juniper123 +21241036 +talent +super +master +superpass +surt +123456 +admin +ANS#150 +asante +kronites +superuser +HARRIS +NETFRAME +NF +NFI +PlsChgMe! +supervisor +SUPERVISOR +SYSTEM +visor +h179350 +support +supportpw +symantec +super +mysweex +SWPRO +SWUSER +Symbol +SYMPA +sync +admin +Admin +admpw +master +nortel +password +sysadmin +sysadm +SYSADM +sysadmpw +syspw +SYSA +bin +sysbin +change_on_install +CHANGE_ON_INSTALL +masterkey +D_SYSPW +oem_temp +OEM_TEMP +sysopr +Sysop +sys +system +adminpwd +system_admin +D_SYSTPW +isp +manager +MANAGER +sys/change_on_install +mnet +password +prime +security +sys +system +weblogic +uplink +Trintech +TAHITI +password +tasmannet +Tasmannet +TDOS_ICSAP +password +field +nician +yZgO8Bvj +tech +telecom +Telecom +tele +tellabs#1 +password +TESTPILOT +test +TEST +tiger123 +changethis +tomcat +logapp +password +password +password +TRACE +TRACE +TRAVEL +trmcnfg +trouble +TSDEV +TSUSER +TURBINE +ubnt +ucenik +ULTIMATE +umountfs +umountfsys +umountsys +unix +USER0 +1001 +1234 +19750407 +USER1 +USER2 +USER3 +USER4 +USER5 +USER6 +USER7 +USER8 +USER9 +demo +demo +demo +demo +demo +demo +demo +PASSW0RD +PASSWORD +Janitza +demo +password +password +Password +none +userNotU +password +Password +demo +public +demo +USER_TEMPLATE +tivonpw +user +user +User +USER +user0000 +USERP +UTLESTAT +uucpadm +uucp +password +vagrant +VCSRV +12871 +vgnadmin +viewuser1 +VIF_DEV_PWD +singh +VIRUSER +winterm +volition +vpasp +VRR1 +VTAM +WANGTEK +1234 +Admin +webadmin +WebBoard +webibm +password +WEBCAL01 +webdb +WEBDB +1 +weblogic +webmaster +WEBREAD +webshieldchangeme +web +whd +WINDOWS_PASSTHRU +SABRE +WINSABRE +WKSYS +wlcsystem +wlpisystem +wlsepassword +wlsedb +HPOFFICE +wpsadmin +trancell +private +synnet +eomjbOBLLwbZeiKV +WWWUSER +www +WWW +xd +sap123 +XPRT +X#1833 diff --git a/subset/security/password/resources/default/usernames.txt b/subset/security/password/resources/default/usernames.txt new file mode 100644 index 0000000000..cd9867b8cb --- /dev/null +++ b/subset/security/password/resources/default/usernames.txt @@ -0,0 +1,1271 @@ +11111111 +11111 +123 +1234 +22222222 +**23646 +**266344 +266344 +2800 +31994 +666666 +7654321 +880175445 +888888 +acer +acitoolkit +Adam +ADAMS +ADLDEMO +adm +admin +admin +admin +admin +admin +admin +admin +admin +admin +Admin +admin +Admin +admin +Admin +Admin1 +admin1 +admin +admin +admin2 +admin +Admin +admin +admin +admin +admin +Admin +Admin +ADMIN +ADMIN +admin +Admin +admin +admin +admin +admin +admin +admin +admin +admin +ADMIN +admin +admin +admin +admin +admin +Admin +admin +admin +admin +admin +admin +Admin +admin +admin +admin +admin +admin +admin +admin +admin +admin +admin +admin +admin +admin +admin +admin +Admin +admin +Admin +admin@example.com +admin +admin +admin +admin +admin +admin +admin +Admin +admin +admin +admin +admin +admin +admin +admin +admin +admin +admin +Administrator +administrator +Administrator +Administrator +Administrator +ADMINISTRATOR +administrator +Administrator +ADMINISTRATOR +administrator +administrator +Administrator +Administrator +Administrator +Administrator +Administrator +Administrator +administrator +Administrator +administrator +Administrator +Administrator +administrator +administrator +Administrator +Administrator +Administrator +Administrator +Administrator +admin +admin +admin +ADMIN +admin +admin +admin +admin +admin +admin +admin +admin +admin +admin +admin +admin +admin +admin +admin +admin +admin +admin +Admin +admin +admin +admin +admin +admin +admin +Admin +admin +Admin +ADMIN +admin +admin +admin +admin +admin +admin +admin +admin +admin +admin +admin +admin +Admin +admin +admin +admin +admin +admin +admin +adminstat +adminstrator +Admin +admin +admin +admin +admin +admin +admin +admin +admin +admin +admin +admin +admin +admin +admin +admin +adminttd +admin +adminuser +admin +adminview +admin +Admin +admin +ADMIN +admin +admin +admin +admin +adsl +adtec +ADVMAIL +Alphanetworks +Alphanetworks +Alphanetworks +Alphanetworks +Alphanetworks +Alphanetworks +Alphanetworks +Alphanetworks +Alphanetworks +Alphanetworks +Alphanetworks +Alphanetworks +Alphanetworks +Alphanetworks +amx +amx +ANDY +anon +anonymous +anonymous +anonymous +anonymous +anonymous +Any +Any +(any) +AP +aparker@geometrixx.info +apc +APPLSYS +APPLSYS +APPLSYSPUB +APPS +APPUSER +AQ +AQDEMO +AQJAVA +AQUSER +ARAdmin +ARCHIVIST +AUDIOUSER +AURORA@ORB@UNAUTHENTICATED +AURORA$ORB$UNAUTHENTICATED +author +autocad +BACKUP +backuponly +backuprestore +basisk +Basisk +bbs +bbsd-client +bbsd-client +BC4J +bciim +bcim +bcms +bcnas +bewan +bin +Blaeri +BLAKE +blue +Bobo +both +bpel +BRIO_ADMIN +browse +browse +bubba +cablecom +cac_admin +CATALOG +c-comatic +ccrusr +CDEMO82 +CDEMOCOR +CDEMORID +CDEMOUCB +cellit +CENTRA +cgadmin +checkfs +checkfsys +checksys +CHEY_ARCHSVR +CICSUSER +CIDS +cirros +CIS +CISCO15 +cisco +Cisco +CISINFO +citel +CLARK +client +cloudera +cmaker +CMSBATCH +cn=orcladmin +Coco +comcast +COMPANY +COMPIERE +computer +conferencing +config +corecess +core +CQSCHEMAUSER +craft +craft +craft +Craft +(created) +(created) +crowd­-openid-­server +Crowd +CSG +CSMIG +ctb_admin +CTXDEMO +CTXSYS +cusadmin +cust +customer +dadmin +dadmin +daemon +davox +db2fenc1 +db2inst1 +dbase +DBA +DBDCCICS +DBI +DBSNMP +DDIC +debian +debian +debian +debug +debug +debug +d.e.b.u.g +default +default +default +default +default +default +defug +DEMO8 +DEMO9 +demo +DEMO +demo +Demo +demos +DES +deskalt +deskman +desknorm +deskres +DEV2000_DEMOS +dev +Developer +device +device +diag +diag +DIP +DISCOVERER_ADMIN +distrib +disttech +disttech +disttech +D-Link +dm +dni +dos +dpn +draytek +Draytek +DSGATEWAY +DSL +DSSYS +DTA +dvstation +eagle +EARLYWATCH +echo +echo +egcr +EJSADMIN +elk_user +emaq +EMP +enable +eng +engmode +enisa +enquiry +ESTOREUSER +eurek +EVENT +EXFSYS +expert +Factory +factory +fal +fam +fastwire +fax +FAX +FAXUSER +FAXWORKS +fg_sysadmin +field +FIELD +FIELD +FIELD +FIELD +FIELD +field +FIELD +FINANCE +firstsite +Flo +FND +FORSE +FROSTY +ftp_admi +ftp +ftp_inst +ftp_nmc +ftp_oper +ftpuser +ftp +fwadmin +fwupgrade +games +GATEWAY +Gearguy +GE +geosolutions +glftpd +GL +god1 +god2 +gopher +GPFD +GPLD +guest +guest +guest1 +guest1 +guest +Guest +Guest +GUEST +guest +GUEST +GUEST +guest +guest +GUEST +guest +guru +halt +HCPARK +HELLO +hello +HELLO +HELLO +HELLO +helpdesk +HLW +(hostname/ipaddress) +HPLASER +HPSupport +HR +hsa +hscroot +HTTP +hunter +hxeadm +ibm +ibm +ibm +IBMUSER +iclock +ilom-admin +ilom-operator +images +IMAGEUSER +IMEDIA +inads +inads +informix +init +installer +installer +install +install +intel +intermec +internal +IntraStack +IntraSwitch +ioFTPD +IS_$hostname +itsadmin +james +jdoe@geometrixx.info +JMUSER +Joe +joe +JONES +JWARD +keyscan +khan +kodi +l2 +L2LDEMO +l3 +LASER +LASERWRITER +LBACSYS +LDAP_Anonymous +leo +LIBRARIAN +Liebert +live +LocalAdministrator +localadmin +locate +login +login +login +login +lpadmin +lpadm +lp +lp +lp +LR-ISDN +lynx +m1122 +m202 +MAIL +mail +MAIL +MAIL +MAIL +MAIL +maintainer +maintainer +maint +MAINT +maint +maint +maint +maint +Manager +MANAGER +manager +MANAGER +MANAGER +manager +Manager +MANAGER +managers +MANAGER +MANAGER +MANAGER +man +manuf +mary +master +MASTER +master +MayGion +McdataSE +MCUser +MD110 +MDDEMO_CLERK +MDDEMO +MDDEMO_MGR +MDSYS +mediator +me +memotec +Menara +mfd +MFG +mg3500 +MGE +MGR +MGR +MGR +MGR +MGR +MGR +MGR +MGR +MGR +MGR +MGR +MGR +MGR +MGR +MGR +MGR +MGR +MGR +MGR +MGR +MGR +MGR +MGR +MGWUSER +MICRO +MIGRATE +MILLER +misp +mlusr +MMO2 +mobile +MODTEST +Moe +monitor +MOREAU +mountfs +mountfsys +mountsys +MSHOME +mso +MTSSYS +MTS_USER +MTYSYS +museadmin +musi1921 +musi1921 +MXAGENT +myshake +naadmin +n.a +NAMES +nao +NAU +ncrm +netbotz +netlink +NetLinx +netman +netopia +netrangr +netscreen +NETWORK +news +newuser +nexthink +NICONEX +nm2user +nms +nobody +none +none +none +none +none +none +none +nop +nop +NSA +OAS_PUBLIC +OCITEST +ODM_MTR +ODM +ODSCOMMON +ods +ODS +OEMADM +OEMREP +OE +OLAPDBA +OLAPSVR +OLAPSYS +OMWB_EMULATION +onlime_r +OO +openhabian +OPENSPIRIT +OPERATIONS +OPERATNS +operator +operator +OPERATOR +OPERATOR +operator +operator +Operator +OPERATOR +OPERATOR +OPERATOR +Oper +OPER +op +op +oracle +ORAREGSYS +ORASSO +ORDPLUGINS +ORDSYS +osbash +osboxes +osmc +OSP22 +OUTLN +overseer +OWA +OWA_PUBLIC +OWNER +PACSLinkIP +PANAMA +patrol +PATROL +PBX +PCUSER +pepino +PERFSTAT +PFCUser +piranha +piranha +pi +PLEX +plexuser +PLMIMService +PLSQL +PM +pnadmin +PO7 +PO8 +politically +poll +Polycom +PO +PORTAL30_DEMO +PORTAL30 +PORTAL30 +PORTAL30_PUBLIC +PORTAL30_SSO +PORTAL30_SSO_PS +PORTAL30_SSO_PUBLIC +POST +postmaster +POST +POWERCARTUSER +POWERCHUTE +powerdown +praisenetwork +PRIMARY +primenet +primenet +primeos +primeos +prime +prime +primos_cs +primos_cs +PRINTER +PRINT +PRODCICS +PRODDTA +PROG +prtgadmin +PSEAdmin +public +PUBSUB1 +PUBSUB +pw +pwrchute +pyimagesearch +qbf77101 +QDBA +qpgmr +QS_ADM +QS_CBADM +QS_CB +QS_CS +qsecofr +qsecofr +qsecofr +qserv +QS_ES +QS_OS +QS +QSRV +QSRV +qsrvbas +qsrv +QSRV +qsvr +qsvr +QS_WS +qsysopr +quser +radware +RAID +rapport +rcust +rdc123 +readonly +readonly +read +readwrite +recover +redline +remnux +REPADMIN +replication-receiver +Replicator +replicator +REP_MANAGER +REPORTS_USER +REP_OWNER +REP_OWNER +RE +restoreonly +rje +RMAIL +RMAN +RMUser1 +RNIServiceManager +Rodopi +role1 +role1 +role +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +ROOT +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +root +Root +root +root +root +root +root +root +root +root +ro +RSBCMON +rwa +rw +sa +SAMPLE +sansforensics +sans +SAP* +SAP* +SA +SAPCPIC +SAPCPIC +SAP* +SAPR3 +SAP +sa +savelogs +scmadmin +sconsole +SCOTT +SDOS_ICSAP +SECDEMO +secofr +security +sedacm +self +SERVICECONSUMER1 +service +Service +service +servlet +setpriv +setup +setup +setup +SH +shutdown +signa +siteadmin +siteadmin +SITEMINDER +SLIDE +smc +SMDR +snmp +snmp +spcl +SPOOLMAN +$SRV +ssladmin +ssp +stackato +STARTER +status +stratacom +STRAT_USER +stuccoboy +super +__super +superdba +super +superman +superman +super +super.super +super +super +superuser +superuser +SUPERUSER +superuser +SuperUser +superuser +SUPERVISOR +SUPERVISOR +SUPERVISOR +SUPERVISOR +supervisor +supervisor +SUPERVISOR +SUPERVISOR +supervisor +support +support +support +support +su +sweex +SWPRO +SWUSER +Symbol +SYMPA +sync +sysadm +sysadm +sysadm +sysadmin +sysadmin +sysadmin +sysadmin +sysadm +SYSADM +sysadm +sysadm +SYSA +sys +sysbin +sys +SYS +SYSDBA +SYS +SYSMAN +SYSMAN +sysopr +Sysop +sys +sys +system +system_admin +SYSTEM +system +system +SYSTEM +system/manager +system +system +system +system +system +system +system +sys +t3admin +TAHITI +target +tasman +Tasman +TDOS_ICSAP +teacher +tech +tech +technician +tech +telecom +Telecom +tele +tellabs +temp1 +TESTPILOT +test +TEST +tiger +tomcat +tomcat +toor +topicalt +topicnorm +topicres +TRACESRV +TRACESVR +TRAVEL +trmcnfg +trouble +TSDEV +TSUSER +TURBINE +ubnt +ucenik23 +ULTIMATE +umountfs +umountfsys +umountsys +unix +USER0 +User +User +User +USER1 +USER2 +USER3 +USER4 +USER5 +USER6 +USER7 +USER8 +USER9 +user_analyst +user_approver +user_author +user_checker +user_designer +user_editor +user_expert +USERID +USERID +user +user_marketer +username +Username +Username +user +userNotUsed +user +User +user_pricer +user +user_publisher +USER_TEMPLATE +user +user +User +User +USER +user +user +UTLBSTATU +uucpadm +uucp +uwmadmin +vagrant +VCSRV +veda +vgnadmin +viewuser +VIF_DEVELOPER +vikram +VIRUSER +VNC +volition +vpasp +VRR1 +VTAM +WANGTEK +webadmin +WebAdmin +webadmin +WebAdmin +webadmin +WEBADM +WEBCAL01 +webdb +WEBDB +webguest +weblogic +webmaster +WEBREAD +webshield +web +whd +WINDOWS_PASSTHRU +WINSABRE +WINSABRE +WKSYS +wlcsystem +wlpisystem +wlseuser +wlse +WP +wpsadmin +wradmin +write +write +wVQxyQec +WWWUSER +www +WWW +xd +xmi_demo +XPRT +XXSESS_MGRYY diff --git a/subset/security/password/resources/faux/dictionary.txt b/subset/security/password/resources/faux/dictionary.txt new file mode 100644 index 0000000000..8caf47c4a5 --- /dev/null +++ b/subset/security/password/resources/faux/dictionary.txt @@ -0,0 +1,4 @@ +:user:pass +:admin:default +:root:user +:default:pass \ No newline at end of file diff --git a/subset/security/password/resources/faux/passwords.txt b/subset/security/password/resources/faux/passwords.txt new file mode 100644 index 0000000000..d2cc81dc7d --- /dev/null +++ b/subset/security/password/resources/faux/passwords.txt @@ -0,0 +1,4 @@ +pass +default +user +pass \ No newline at end of file diff --git a/subset/security/password/resources/faux/usernames.txt b/subset/security/password/resources/faux/usernames.txt new file mode 100644 index 0000000000..5b38a1c32c --- /dev/null +++ b/subset/security/password/resources/faux/usernames.txt @@ -0,0 +1,4 @@ +user +admin +root +default \ No newline at end of file diff --git a/subset/security/password/resources/raw/manufacturer.csv b/subset/security/password/resources/raw/manufacturer.csv new file mode 100644 index 0000000000..5f1ac893c3 --- /dev/null +++ b/subset/security/password/resources/raw/manufacturer.csv @@ -0,0 +1,2850 @@ +Vendor,Username,Password,Comments +"2Wire, Inc.",http,, +360 Systems,factory,factory, +3COM,3comcso,RIP000,Resets all passwords to defaults +3COM,,12345, +3COM,,1234admin, +3COM,,, +3COM,,ANYCOM, +3COM,,ILMI, +3COM,,PASSWORD, +3COM,,admin, +3COM,,comcomcom, +3COM,,, +3COM,,PASSWORD, +3COM,,admin, +3COM,Admin,Admin, +3COM,Administrator,, +3COM,Administrator,admin, +3COM,Type User: FORCE,, +3COM,User,Password, +3COM,adm,, +3COM,admin,1234admin, +3COM,admin,, +3COM,admin,admin, +3COM,admin,comcomcom, +3COM,admin,password, +3COM,admin,synnet, +3COM,adminttd,adminttd, +3COM,debug,synnet, +3COM,defug,synnet, +3COM,manager,manager, +3COM,monitor,monitor, +3COM,none,admin, +3COM,read,synnet, +3COM,recover,recover,http://support.3com.com/infodeli/tools/switches/ss3/4900/dha1770-0aaa04/htm/support/problemsolving/cliproblems.htm +3COM,recovery,recovery,Unit must be powered off +3COM,root,!root,http://support.3com.com/infodeli/tools/remote/ocradsl/20/812_cli20.pdfhttp://support.3com.com/infodeli/tools/remote/ocremote/brouters/840/2sysadmin.htm +3COM,security,security, +3COM,tech,, +3COM,tech,tech, +3COM,write,synnet, +3M,VOL-0215,,http://multimedia.3m.com/mws/mediawebserver?6666660Zjcf6lVs6EVs666xa9COrrrrQ- +3M,volition,,http://multimedia.3m.com/mws/mediawebserver?6666660Zjcf6lVs6EVs666xa9COrrrrQ- +3M,volition,volition, +3ware,Administrator,3ware, +ACCTON,,0000, +ACCTON,__super,(caclulated),http://www.vettebak.nl/hak/ +ACCTON,admin,, +ACCTON,manager,manager, +ACCTON,monitor,monitor, +ACCTON,none,0, +ADC Kentrox,,secret, +ADC Kentrox,,secret, +ADIC,admin,password, +ADIC,admin,secure, +ADP,sysadmin,master, +ADT,,2580,http://krebsonsecurity.com/2013/01/does-your-alarm-have-a-default-duress-code/ +ADTRAN,admin,password, +AIRAYA Corp,Airaya,Airaya,http://www.airaya.com/support/guides/WirelessGRID-Manual_O.pdf +ALLNET,admin,admin, +ALLNET,admin,password, +ALLNET,none,admin, +AMI,,A.M.I, +AMI,,AM, +AMI,,AMI, +AMI,,AMI!SW, +AMI,,AMI.KEY, +AMI,,AMI.KEZ, +AMI,,AMI?SW, +AMI,,AMIPSWD, +AMI,,AMISETUP, +AMI,,AMI_SW, +AMI,,AMI~, +AMI,,BIOSPASS, +AMI,,CMOSPWD, +AMI,,HEWITT RAND, +AMI,,aammii, +AMI,,A.M.I, +AMI,,AM, +AMI,,AMI, +AMI,,AMI!SW, +AMI,,AMI.KEY, +AMI,,AMI.KEZ, +AMI,,AMI?SW, +AMI,,AMIAMI, +AMI,,AMIDECOD, +AMI,,AMIPSWD, +AMI,,AMISETUP, +AMI,,AMI_SW, +AMI,,AMI~, +AMI,,BIOSPASS, +AMI,,HEWITT RAND, +AMI,,aammii, +AMX,,1988,http://www.amx.com/techsupport/PDFs/981.pdf +AMX,,,http://www.amx.com/techsupport/PDFs/981.pdf +AMX,,admin,http://www.amx.com/techsupport/PDFs/981.pdf +AMX,Admin,1988,http://www.amx.com/techsupport/PDFs/981.pdf +AMX,Administrator,vision2,http://www.amx.com/techsupport/PDFs/981.pdf +AMX,NetLinx,password,http://www.amx.com/techsupport/PDFs/981.pdf +AMX,admin,1988,http://www.amx.com/techsupport/PDFs/981.pdf +AMX,admin,admin,http://www.amx.com/techsupport/PDFs/981.pdf +AMX,administrator,password,http://www.amx.com/techsupport/PDFs/981.pdf +AMX,guest,guest,http://www.amx.com/techsupport/PDFs/981.pdf +AMX,root,mozart,http://www.amx.com/techsupport/PDFs/981.pdf +AOC,,admin, +APACHE,admin,jboss4, +APC,(any),TENmanUFactOryPOWER, +APC,,serial number of the Call-UPS, +APC,,serial number of the Share-UPS, +APC,,TENmanUFactOryPOWER, +APC,,backdoor, +APC,POWERCHUTE,APC, +APC,apc,apc, +APC,device,apc,https://www.jlab.org/Hall-D/Documents/manuals/APC%20stuff/AP9630%209631%20UPS%20Network%20Management%20Card%202%20User's%20Guide%20firmware%20V5.1.1.pdf +APC,device,device, +APC,readonly,apc,https://www.jlab.org/Hall-D/Documents/manuals/APC%20stuff/AP9630%209631%20UPS%20Network%20Management%20Card%202%20User's%20Guide%20firmware%20V5.1.1.pdf +ARtem,,admin, +ASMAX,admin,epicrouter, +AST,,SnuFG5, +AST,,SnuFG5, +AT&T,,mcp, +ATL,Service,5678,Tape Library Service Access +ATL,operator,1234,Tape Library Operator Access +AVM,,0, +AVM,,, +AWARD,,1322222, +AWARD,,256256, +AWARD,,589589, +AWARD,,589721, +AWARD,,, +AWARD,,?award, +AWARD,,AWARD SW, +AWARD,,AWARD?SW, +AWARD,,AWARD_PW, +AWARD,,AWARD_SW, +AWARD,,Award, +AWARD,,BIOS, +AWARD,,CONCAT, +AWARD,,HELGA-S, +AWARD,,HEWITT RAND, +AWARD,,HLT, +AWARD,,PASSWORD, +AWARD,,SER, +AWARD,,SKY_FOX, +AWARD,,SWITCHES_SW, +AWARD,,SW_AWARD, +AWARD,,SZYX, +AWARD,,Sxyz, +AWARD,,TTPTHA, +AWARD,,TzqF, +AWARD,,ZAAADA, +AWARD,,aLLy, +AWARD,,aPAf, +AWARD,,admin, +AWARD,,alfarome, +AWARD,,award.sw, +AWARD,,award_?, +AWARD,,award_ps, +AWARD,,awkward, +AWARD,,biosstar, +AWARD,,biostar, +AWARD,,condo, +AWARD,,djonet, +AWARD,,efmukl, +AWARD,,g6PJ, +AWARD,,h6BB, +AWARD,,j09F, +AWARD,,j256, +AWARD,,j262, +AWARD,,j322, +AWARD,,j64, +AWARD,,lkw peter, +AWARD,,lkwpeter, +AWARD,,setup, +AWARD,,t0ch20x, +AWARD,,t0ch88, +AWARD,,wodj, +AWARD,,zbaaaca, +AWARD,,zjaaadc, +AXUS,,0,Storage DAS SATA to SCSI/FC +Accelerated Networks,sysadm,anicust, +Aceex,admin,, +Acer,,, +Actiontec,,, +Actiontec,admin,password,Verizon Fios Setup +AdComplete.com,Admin1,Admin1, +Adaptec,Administrator,adaptec, +AddPac Technology,root,router, +Addon,admin,admin, +Adobe,admin,admin,https://docs.adobe.com/docs/v5_2/html-resources/cq5_guide_power_user/ch07s02.html#sect_default_users_and_groups +Adobe,anonymous,anonymous,http://resources.infosecinstitute.com/adobe-cq-pentesting-guide-part-1/ +Adobe,aparker@geometrixx.info,aparker,http://resources.infosecinstitute.com/adobe-cq-pentesting-guide-part-1/ +Adobe,author,author,https://docs.adobe.com/docs/v5_2/html-resources/cq5_guide_power_user/ch07s02.html#sect_default_users_and_groups +Adobe,jdoe@geometrixx.info,jdoe,http://resources.infosecinstitute.com/adobe-cq-pentesting-guide-part-1/ +Adobe,replication-receiver,replication-receiver,http://resources.infosecinstitute.com/adobe-cq-pentesting-guide-part-1/ +Adobe,vgnadmin,vgnadmin,http://dev.day.com/content/docs/en/crx/connectors/vignette/current.html +Adtech,root,ax400, +Adtran,,adtran, +Adtran,admin,password,http://www.adtran.com/pub/Library/Quick_Start_Guides/Public_View/NetVanta%203430%20Quick%20Start%20Guide.pdf +Advanced Integration,,Advance, +Advanced Integration,,Advance, +Advantek Networks,admin,, +Aethra,admin,password, +AirLink Plus,,admin, +AirTies RT-210,admin,admin, +Airlink,,admin, +Aironet,,, +Airway,,0000, +Aladdin,root,kn1TG7psLu, +Alcatel,,,http://www.speedtouch.com/support.htm +Alcatel,,admin, +Alcatel,,1064, +Alcatel,SUPERUSER,ANS#150, +Alcatel Thomson,admin,admin, +Alcatel,adfexc,adfexc,thanks to Nicolas Gregoire +Alcatel,admin,switch, +Alcatel,at4400,at4400,thanks to Nicolas Gregoire +Alcatel,client,client, +Alcatel,dhs3mt,dhs3mt,thanks to Nicolas Gregoire +Alcatel,dhs3pms,dhs3pms,thanks to Nicolas Gregoire +Alcatel,diag,switch, +Alcatel,ftp_admi,kilo1987, +Alcatel,ftp_inst,pbxk1064, +Alcatel,ftp_nmc,tuxalize, +Alcatel,ftp_oper,help1954, +Alcatel,halt,tlah,thanks to Nicolas Gregoire +Alcatel,install,llatsni,thanks to Nicolas Gregoire +Alcatel,kermit,kermit,thanks to Nicolas Gregoire +Alcatel,mtch,mtch,thanks to Nicolas Gregoire +Alcatel,mtcl,, +Alcatel,mtcl,mtcl,thanks to Nicolas Gregoire +Alcatel,root,letacla,thanks to Nicolas Gregoire +Alcatel,root,permit,Perm/Config port 38036 +Alcatel,superuser,superuser, +Alien Technology,alien,alien,http://seclists.org/fulldisclosure/2010/May/63 +Alien Technology,root,alien,http://seclists.org/fulldisclosure/2010/May/63 +Allied Telesyn,,manager, +Allied Telesyn,,admin, +Allied Telesyn,admin,, +Allied Telesyn,manager,admin, +Allied Telesyn,manager,friend, +Allied Telesyn,manager,manager, +Allied Telesyn,root,, +Allied Telesyn,secoff,secoff, +Allnet,admin,admin,http://www.allnet.de/ +Allot,admin,allot, +Allot,root,bagabu, +Alteon,admin,, +Alteon,admin,admin, +Alteon,admin,linga, +Ambit,root,, +Ambit,root,root, +Ambit,user,user, +Amigo,admin,epicrouter, +Amino,,leaves,http://www.vsicam.com/files/documents/AmiNet/AmiNet_and_AVN_Configuration_Manual.pdf +Amino,,snake,http://www.vsicam.com/files/documents/AmiNet/AmiNet_and_AVN_Configuration_Manual.pdf +Amitech,admin,admin, +AmpJuke,admin,pass, +Amptron,,Polrty, +Amptron,,Polrty, +Andover Controls,acc,acc, +Apache Project,jj,, +Apache,admin,, +Apache,admin,admin, +Apache,admin,j5Brn9, +Apache,admin,tomcat, +Apache,both,tomcat, +Apache,role,changethis, +Apache,role1,role1, +Apache,role1,tomcat, +Apache,root,changethis, +Apache,root,root, +Apache,tomcat,changethis, +Apache,tomcat,tomcat, +Apple,,public,See Apple article number 58613 +Apple,,xyzzy, +Apple,,admin,see Apple article number 107518 +Apple,,password,See Apple article number 106597 +Apple Computer,,public, +Apple Computer,,xyzzy, +Apple,admin,public, +Apple,mobile,dottie, +Apple,root,admin, +Apple,root,alpine, +Applied Innovations,scout,scout, +Areca,admin,0, +Arescom,,atc123, +Arlotto,admin,123456, +Arris,admin,password, +Arrowpoint,,, +Arrowpoint,admin,system, +Aruba,admin,admin, +Arun,123,234, +Asante,IntraStack,Asante, +Asante,IntraSwitch,Asante, +Asante,admin,asante, +Asante,superuser,, +Asante,superuser,asante, +Ascend,,ascend, +Ascend,,ascend, +Ascend,readonly,lucenttech2, +Ascend,readwrite,lucenttech1, +Ascend,root,ascend, +Ascom,,3ascotel, +Aspect,DTA,TJM, +Aspect,customer,none, +Asus,,admin, +Asus,admin,admin, +Asus,adsl,adsl1234, +Atlantis,admin,atlantis, +Atlassian,Crowd,password,http://www.commandfive.com/papers/C5_TA_2013_3925_AtlassianCrowd.pdf +Atlassian,Demo,password,http://www.commandfive.com/papers/C5_TA_2013_3925_AtlassianCrowd.pdf +Atlassian,Username,password,http://www.commandfive.com/papers/C5_TA_2013_3925_AtlassianCrowd.pdf +Atlassian,crowd­-openid-­server,password,http://www.commandfive.com/papers/C5_TA_2013_3925_AtlassianCrowd.pdf +Attachmate,,PASSWORD, +Audioactive,,telos, +Autodesk,autocad,autocad, +Avaya,,Craftr4, +Avaya,,, +Avaya,,admin, +Avaya,Administrator,ggdaseuaimhrke, +Avaya,Craft,crftpw, +Avaya,admin,admin,https://downloads.avaya.com/css/P8/documents/100173462 +Avaya,admin,admin123, +Avaya,admin,barney, +Avaya,admin,password,https://downloads.avaya.com/css/P8/documents/100181785 +Avaya,craft,, +Avaya,craft,crftpw, +Avaya,dadmin,dadmin, +Avaya,dadmin,dadmin01, +Avaya,diag,danger, +Avaya,manuf,xxyyzz, +Avaya,root,ROOT500, +Avaya,root,cms500, +Avaya,root,ggdaseuaimhrke, +Avaya,root,root, +Avenger News System (ANS),,Administrative, +Avocent,root,tslinux, +Award,,lkwpeter, +Award,,1322222, +Award,,256256, +Award,,?award, +Award,,AWARD_SW, +Award,,BIOS, +Award,,CONCAT, +Award,,CONDO, +Award,,HELGA-S, +Award,,HEWITT RAND, +Award,,HLT, +Award,,PASSWORD, +Award,,SER, +Award,,SKY_FOX, +Award,,SWITCHES_SW, +Award,,SY_MB, +Award,,SZYX, +Award,,Sxyz, +Award,,TTPTHA, +Award,,TzqF, +Award,,aLLy, +Award,,aPAf, +Award,,admin, +Award,,alfarome, +Award,,award, +Award,,awkward, +Award,,biosstar, +Award,,biostar, +Award,,g6PJ, +Award,,h6BB, +Award,,j09F, +Award,,j256, +Award,,j262, +Award,,j322, +Award,,j64, +Award,,lkw peter, +Award,,lkwpeter, +Award,,setup, +Award,,t0ch20x, +Award,,t0ch88, +Award,,wodj, +Award,,zbaaaca, +Axis,,, +Axis Communications,root,pass, +Axis,root,pass, +Axway,setup,setup,https://cdn.axway.com/u/documentation/secure_transport/5.3.0/SecureTransport_GettingStartedGuide_allOS_en.pdf +Aztech,admin,admin, +Aztech,isp,isp,backdoor � not in all f/w versions +Aztech,root,admin, +BBR-4MG and,root,, +BEA,system,weblogic, +BECU,musi1921,Musii%1921, +BLACKBOX,Administrator,public, +BMC Software,Administrator,the same all over, +BMC Software,Best1_User,BackupU$r,http://krebsonsecurity.com/2014/01/new-clues-in-the-target-breach/ +BMC,patrol,patrol, +BNI,USER,USER, +BT,admin,admin, +"Barco, Inc.",,clickshare,https://www.barco.com/tde/(2331390682231610)/R5900004/08/Barco_InstallationManual_R5900004_08__ClickShare-CSC-1-Installation-Guide.pdf +"Barco, Inc.",admin,admin,https://www.barco.com/tde/(2331390682231610)/R5900004/08/Barco_InstallationManual_R5900004_08__ClickShare-CSC-1-Installation-Guide.pdf +Barracuda,admin,admin,http://www.barracudanetworks.com/ns/downloads/Quick_Start_Guides/QSG_Barracuda_SSLVPN_US.pdf +Barracuda,ssladmin,ssladmin,http://www.barracudanetworks.com/ns/downloads/Quick_Start_Guides/QSG_Barracuda_SSLVPN_US.pdf +Bausch Datacom,admin,epicrouter, +Bay Networks,,NetICs, +Bay Networks,,NetICs, +Bay Networks,Manager,, +Bay Networks,User,, +Bay Networks,security,security, +Beetel,admin,admin, +Beetel,admin,password, +Belkin,,MiniAP, +Belkin,,admin, +Belkin,admin,none, +Benq,admin,admin, +Best Practical Solutions,root,password,http://requesttracker.wikia.com/wiki/RecoverRootPassword +BestPractical,root,password, +Bewan,bewan,bewan, +Billion,,, +Billion,admin,admin, +BinTec,,snmp-Trap,by rootkid +BinTec,Admin,No, +BinTec,admin,bintec, +Bintec,admin,bintec, +Bintec,admin,funkwerk, +Biodata,,Babylon, +Biodata,config,biodata, +Biostar,,Biostar, +Biostar,,Q54arwms, +Biostar,,Biostar, +Biostar,,Q54arwms, +Biscom,admin,admin,http://ticsoftware.helpserve.com/Knowledgebase/Article/GetAttachment/48/40 +BizDesign,Admin,ImageFolio, +Black Widow Web Design Ltd,admin,nimda, +Blaeri,Blaeri,22332323, +Blitzz Technologies,admin,admin, +Blue Coat Systems,admin,articon, +Bluecoat,admin,admin, +Bomgar,admin,password, +Borland,,, +Borland,politically,correct, +Bosch,live,live, +Bosch,service,service, +Bosch,user,user, +Breezecom,,, +Breezecom,,Helpdesk, +Breezecom,,Master, +Breezecom,,Super, +Breezecom,,laflaf, +Breezecom,,Helpdesk, +Breezecom,,Master, +Breezecom,,Super, +Breezecom,,laflaf, +Broadlogic,admin,admin, +Broadlogic,installer,installer, +Broadlogic,webadmin,webadmin, +Brocade,admin,brocade1, +Brocade,admin,password, +Brocade,factory,Fact4EMC, +Brocade,root,Serv4EMC, +Brocade,root,fibranne, +Brocade,root,fivranne,by Nicolas Gregoire +Brocade,user,password,Also on other SAN equipment +Brother,,access, +Brother,,access, +Brother Industries Ltd.,,00000000, +Brother Industries Ltd.,,12345678, +Brother Industries Ltd.,admin,access, +Brother,admin,access, +Buffalo Technology,admin,password, +Buffalo,root,, +Buffalo/MELCO,root,, +Busybox,admin,admin, +CA Process Automation,pamadmin,pamadmin, +CGI World,,protection, +CNET,admin,1234, +CNet,Admin,admin, +COM3,admin,admin, +CTX International,,CTX_123, +CTX International,,CTX_123, +Cable And Wireless,admin,1234, +Cabletron,,, +Cabletron,netman,, +Canon/Brother,7654321,7654321, +Canon,,0, +Capricorn Infotech India,,1234567890,http://www.isecurity.info/downloads/eToken_Basic_Operation_Guide_1.0.pdf +CareStream Health,KeyOperator,DV5800,http://www.spectrumxray.com/sites/default/files/pdfs/Carestream-DryView-5800-5850.pdf +CareStream Health,LocalService,DV5800,http://www.spectrumxray.com/sites/default/files/pdfs/Carestream-DryView-5800-5850.pdf +Carsten Schmitz,admin,password,http://docs.limesurvey.org/Installation&structure=English+Instructions+for+LimeSurvey#Connect_to_the_administration_script_for_the_first_time +Cayman,,, +Cayman,admin,(serial number), +Cayman,admin,, +Cayman,},, +Celerity,mediator,mediator, +Celerity,root,Mua'dib, +Cellit,cellit,cellit, +Ceragon Networks,root,tooridu,http://www.kb.cert.org/vuls/id/936356 +Chase Research,,iolan, +Check Point,admin,admin, +Check Point,admin,adminadmin, +Checkpoint,admin,abc123, +Checkpoint,admin,admin, +Chuming Chen,administrator,adminpass, +CipherTrust,admin,password, +Ciphertrust,admin,password, +Cisco, EAdmin,, +Cisco, UAMIS_,, +Cisco, UNITY_,, +Cisco, UOMNI_,, +Cisco, UVPIM_,, +Cisco,,, +Cisco,,Cisco, +Cisco,,Cisco router, +Cisco,,_Cisco, +Cisco,,c, +Cisco,,cc, +Cisco,,changeit,http://160.78.48.20/vpn/software/How_to_use_Webvpn_with_Citrix_Metaframe.pdf +Cisco,,cisco, +Cisco,,letmein, +Cisco,,public/private/secret, +Cisco,,riverhead,http://www.cisco.com/en/US/products/ps5888/prod_release_note09186a0080237333.html +Cisco,,Cisco router, +Cisco,,ILMI, +Cisco,,c, +Cisco,,cable-docsis, +Cisco,,cc, +Cisco,,cisco, +Cisco,Administrator,admin, +Cisco,Administrator,changeme, +Cisco,CISCO15,otbu+1, +Cisco,Cisco,Cisco, +Cisco,ESubscriber,, +Cisco,End User,7936, +Cisco,admin,, +Cisco,admin,admin, +Cisco,admin,changeme, +Cisco,admin,cisco, +Cisco,admin,default, +Cisco,admin,diamond, +Cisco,admin,tsunami, +Cisco,bbsd-client,NULL, +Cisco,bbsd-client,changeme2, +Cisco,bubba,(unknown), +Cisco,cisco,, +Cisco,cisco,cisco, +Cisco,cmaker,cmaker, +Cisco,enable,, +Cisco,enable,cisco, +Cisco,guest,, +Cisco,hsa,hsadb, +Cisco,hsa,hsadb , +Cisco,netrangr,attack, +Cisco,pnadmin,pnadmin, +Cisco,praisenetwork,perfectpraise, +Cisco,private ReadWrite access,secret, +Cisco,public ReadOnly access,secret, +Cisco,ripeop,, +Cisco,root ,attack, +Cisco,root,Cisco, +Cisco,root,attack, +Cisco,root,blender, +Cisco,root,password,Added by DPL admin. From +Cisco,root,secur4u,http://www.cisco.com/c/en/us/td/docs/security/physical_security/video_surveillance/network/vsm/6_3/user_guide/cvsm_6_3/overview.html#wp1035089 +Cisco,sa,, +Cisco,technician,2 + last 4 of Audio, +Cisco,uwmadmin,password,http://www.cisco.com/c/en/us/td/docs/cloud_services/cisco_modeling_labs/v100/installation/guide/administrator/b_cml_install_sys_admin/b_cml_install_sys_admin_chapter_0111.html +Cisco,wlse,wlsedb, +Cisco,wlseuser,wlsepassword, +Cisco-Arrowpoint,admin,system, +Citel,,citel, +Citel,citel,password, +"Citrix Systems, Inc.",nsroot,nsroot,http://support.citrix.com/proddocs/topic/access-gateway-hig-appliances/ag-using-setup-wizard-tsk.html +"Citrix Systems, Inc.",root,rootadmin, +Claris,,familymacintosh, +ClearOne Communications,ClearOne,RAV,http://www.clearone.com/uploads/resource/800_153_560_Rev1_0_Converge560_590Man-0.pdf +ClearOne Communications,clearone,converge,"http://pdf.textfiles.com/manuals/STARINMANUALS/ClearOne/Manuals/Archive/ConvergePro%208i,%20840T,%20880,%20TH20%20v0.91.pdf" +Cnet,Admin,epicrouter, +Cnet,admin,password, +Cobalt,admin,admin, +Colubris Networks,admin,admin, +Colubris,admin,admin, +Comcast Home Networking,comcast,, +Comcast SMC,cusadmin,highspeed, +Comcast SMC,cusadmin,CantTouchThis, +Comersus,admin,dmr99, +"Comodo Group, Inc",mydlp,mydlp,https://www.mydlp.com/wp-content/uploads/Comodo_MyDLP_Admin_guide.pdf +Compaq,,,use ALT+G at boot to reset config +Compaq,,Compaq, +Compaq,,Compaq, +Compaq,PFCUser,240653C9467E45, +Compaq,administrator,administrator, +Compaq,anonymous,, +Compaq,operator,operator, +Compaq,root,manager, +Compaq,root,rootme, +Compaq,user,public, +Compaq,user,user, +Compualynx,administrator,asecret, +Comtrend,admin,1234, +Comtrend,admin,, +Comtrend,admin,admin, +Conceptronic,admin,1234, +Conceptronic,admin,password, +Conceptronic,anonymous,password, +Concord,,last, +Concord,,last, +Conexant,,admin, +Conexant,,epicrouter, +Conexant,Administrator,admin, +Conexant,admin,amigosw1, +Conexant,admin,conexant, +Conexant,admin,epicrouter, +Conexant,admin,password, +Conitec,Adam,29111991, +Control4,,ducati900ss,"http://www.digitalmunition.com/_/Blog/Entries/2010/10/13_Control4_gear_is_umm..._backdoored,_I_guess.html" +Control4,root,t0talc0ntr0l4!,"http://www.digitalmunition.com/_/Blog/Entries/2010/10/13_Control4_gear_is_umm..._backdoored,_I_guess.html" +Corecess,Administrator,admin, +Corecess,admin,, +Corecess,corecess,corecess, +CoronaMatrix,admin,admin, +Covertix,Admin,Admin,http://www.kagoon.com/smartcipher-installation-guide-docx/main +Creative,,, +Crossbeam,,x40rocks,At the LILO boot prompt type CTC +Crystalview,,Crystal, +CyberMax,,Congress, +CyberMax,,Congress, +Cyberguard,cgadmin,cgadmin, +Cyclades,root,, +Cyclades,root,tslinux, +Cyclades,super,surt, +D-Link,,admin, +D-Link,,private, +D-Link,,public, +D-Link,,admin, +D-Link,Admin,, +D-Link,Alphanetworks,wrgg15_di524, +D-Link,D-Link,D-Link, +D-Link,admin,, +D-Link,admin,admin, +D-Link,admin,gvt12345, +D-Link,admin,none, +D-Link,admin,password,hardcoded for Verizon FiOS +D-Link,admin,public, +D-Link,admin,year2000, +D-Link,dont need one,admin, +D-Link,none,none, +D-Link,none,private, +D-Link,root,admin, +D-Link,user,,by rootkid +D-Link,user,none, +D9287ar,Clarissa,, +DIGICOM,root,admin, +DVB,dvstation,dvst10n, +DVB,root,pixmet2003, +Daewoo,,Daewuu, +Daewoo,,Daewuu, +Dallas Semiconductors,root,tini, +Dassault Systemes,Test Everything,,http://public.dhe.ibm.com/partnerworld/pub/whitepaper/193d6.pdf +Data General,op,op, +Data General,op,operator, +Data General,operator,operator, +DataWizard Technologies Inc.,anonymous,, +DataWizard Technologies Inc.,test,test, +Datacom,,letmein, +Datacom,,letmein, +Datacom,sysadm,sysadm, +Datawizard.net,anonymous,any, +Datawizard.net,anonymous,any@, +Davolink,user,user, +Davox,admin,admin, +Davox,davox,davox, +Davox,root,davox, +Davox,sa,, +Daytek,,Daytec, +Daytek,,Daytec, +Debian,,tatercounter2000, +Deerfield,MDaemon,MServer,web interface to manage MDaemon. fixed June 2002 +Dell,,Dell, +Dell,,Fireport,http://www.vennercorp.com/blog/2014/09/08/what-are-the-default-wyse-admin-passwords/ +Dell,,nz0u4bbe, +Dell,,1RRWTTOOI, +Dell,,Dell, +Dell,,admin, +Dell,Admin,,case sensitive username +Dell,Administrator,storageserver, +Dell,VNC,winterm,http://www.vennercorp.com/blog/2014/09/08/what-are-the-default-wyse-admin-passwords/ +Dell,admin,admin, +Dell,admin,password, +Dell,rapport,r@p8p0r+,http://www.vennercorp.com/blog/2014/09/08/what-are-the-default-wyse-admin-passwords/ +Dell,root,calvin, +Dell,root,wyse,http://www.vennercorp.com/blog/2014/09/08/what-are-the-default-wyse-admin-passwords/ +Demarc,admin,my_DEMARC, +Deutsche Telekom,,0, +Deutsche Telekom,admin,, +Develcon,,BRIDGE, +Develcon,,password, +Develcon,,BRIDGE, +Develcon,,password, +Dictaphone,NETOP,, +Dictaphone,NETWORK,NETWORK, +Dictaphone,PBX,PBX, +Digicom,admin,michelangelo, +Digicom,user,password, +Digicorp,,BRIDGE, +Digicorp,,password, +Digicorp,,BRIDGE, +Digicorp,,password, +Digicraft Software,Yak,asd123, +Digital Equipment,1,manager, +Digital Equipment,1,operator, +Digital Equipment,1,syslib, +Digital Equipment,1.1,SYSTEM, +Digital Equipment,2,maintain, +Digital Equipment,2,manager, +Digital Equipment,2,operator, +Digital Equipment,2,syslib, +Digital Equipment,30,games, +Digital Equipment,5,games, +Digital Equipment,7,maintain, +Digital Equipment,,1, +Digital Equipment,,ACCESS, +Digital Equipment,,SYSTEM, +Digital Equipment,,access, +Digital Equipment,,komprie, +Digital Equipment,,system, +Digital Equipment,,ACCESS, +Digital Equipment,,SYSTEM, +Digital Equipment,,komprie, +Digital Equipment,ALLIN1,ALLIN1, +Digital Equipment,ALLIN1MAIL,ALLIN1MAIL, +Digital Equipment,ALLINONE,ALLINONE, +Digital Equipment,BACKUP,BACKUP, +Digital Equipment,BATCH,BATCH, +Digital Equipment,DCL,DCL, +Digital Equipment,DECMAIL,DECMAIL, +Digital Equipment,DECNET,DECNET, +Digital Equipment,DECNET,NONPRIV, +Digital Equipment,DEFAULT,DEFAULT, +Digital Equipment,DEFAULT,USER, +Digital Equipment,DEMO,DEMO, +Digital Equipment,FIELD,DIGITAL, +Digital Equipment,FIELD,FIELD, +Digital Equipment,FIELD,SERVICE, +Digital Equipment,FIELD,TEST, +Digital Equipment,GUEST,GUEST, +Digital Equipment,HELP,HELP, +Digital Equipment,HELPDESK,HELPDESK, +Digital Equipment,HOST,HOST, +Digital Equipment,INFO,INFO, +Digital Equipment,INGRES,INGRES, +Digital Equipment,LINK,LINK, +Digital Equipment,MAILER,MAILER, +Digital Equipment,MBMANAGER,MBMANAGER, +Digital Equipment,MBWATCH,MBWATCH, +Digital Equipment,NETCON,NETCON, +Digital Equipment,NETMGR,NETMGR, +Digital Equipment,NETNONPRIV,NETNONPRIV, +Digital Equipment,NETPRIV,NETPRIV, +Digital Equipment,NETSERVER,NETSERVER, +Digital Equipment,NETWORK,NETWORK, +Digital Equipment,NEWINGRES,NEWINGRES, +Digital Equipment,NEWS,NEWS, +Digital Equipment,OPERVAX,OPERVAX, +Digital Equipment,PDP11,PDP11, +Digital Equipment,PDP8,PDP8, +Digital Equipment,POSTMASTER,POSTMASTER, +Digital Equipment,PRIV,PRIV, +Digital Equipment,REPORT,REPORT, +Digital Equipment,RJE,RJE, +Digital Equipment,STUDENT,STUDENT, +Digital Equipment,SYS,SYS, +Digital Equipment,SYSMAINT,DIGITAL, +Digital Equipment,SYSMAINT,SERVICE, +Digital Equipment,SYSMAINT,SYSMAINT, +Digital Equipment,SYSTEM,MANAGER, +Digital Equipment,SYSTEM,OPERATOR, +Digital Equipment,SYSTEM,SYSLIB, +Digital Equipment,SYSTEM,SYSTEM, +Digital Equipment,SYSTEST,UETP, +Digital Equipment,SYSTEST_CLIG,SYSTEST, +Digital Equipment,SYSTEST_CLIG,SYSTEST_CLIG, +Digital Equipment,TELEDEMO,TELEDEMO, +Digital Equipment,TEST,TEST, +Digital Equipment,UETP,UETP, +Digital Equipment,USER,PASSWORD, +Digital Equipment,USER,USER, +Digital Equipment,USERP,USERP, +Digital Equipment,VAX,VAX, +Digital Equipment,VMS,VMS, +Digital Equipment,accounting,accounting, +Digital Equipment,boss,boss, +Digital Equipment,demo,demo, +Digital Equipment,manager,manager, +Digital Equipment,software,software, +"Digium, Inc.",admin,password,ftp://ftp.gtlib.gatech.edu/pub/asterisknow/quickstart_asterisknow.pdf +Divar,admin,,http://www.google.com/url?sa=t&source=web&cd=3&ved=0CBsQFjAC&url=http%3A%2F%2Fresource.boschsecurity.com%2Fdocuments%2FEX85MegapixelIP_TechnicalServiceNote_enUS_T6355740427.doc&ei=h55lTLeXCcT_lgfgkqyTDg&usg=AFQjCNGPOLSf4n0L9PAyJ8Jv7FFN0IDIVw +Divar,viewer,,http://www.google.com/url?sa=t&source=web&cd=3&ved=0CBsQFjAC&url=http%3A%2F%2Fresource.boschsecurity.com%2Fdocuments%2FEX85MegapixelIP_TechnicalServiceNote_enUS_T6355740427.doc&ei=h55lTLeXCcT_lgfgkqyTDg&usg=AFQjCNGPOLSf4n0L9PAyJ8Jv7FFN0IDIVw +Dlink,admin,, +Dlink,admin,admin, +Dlink,admin,public, +DotNetNuke Corporation,admin,dnnadmin, +DotNetNuke Corporation,host,dnnhost, +Draytek Corp,admin,, +Draytek,Draytek,1234, +Draytek,admin,, +Draytek,admin,admin, +Draytek,draytek,1234, +DuPont,root,par0t, +Ducati Motor Holding,,Last 4 digits of VIN,http://www.laresblog.com/2011/04/why-cant-i-just-buy-motorcycle-without.html +Dynalink,admin,admin, +Dynalink,admin,private, +Dynalink,userNotUsed,userNotU, +Dynix Library Systems,LIBRARY,, +Dynix Library Systems,SETUP,, +Dynix Library Systems,circ,, +E-Con,admin,epicrouter, +E-Tech,,admin, +E-Tech,admin,epicrouter, +E-Tech,admin,password, +E-Tech,none,admin, +EMC,MCUser,MCUser1,https://community.emc.com/message/525389 +EMC,admin,,EMC Fiber Switch +EMC,admin,changeme,https://community.emc.com/message/525389 +EMC,backuponly,backuponly1,https://community.emc.com/message/525389 +EMC,backuprestore,backuprestore1,https://community.emc.com/message/525389 +EMC,dpn,changeme,https://community.emc.com/message/525389 +EMC,restoreonly,restoreonly1,https://community.emc.com/message/525389 +EMC,root,8RttoTriz,https://community.emc.com/message/525389 +EMC,root,changeme,https://community.emc.com/message/525389 +EMC,viewuser,viewuser1,https://community.emc.com/message/525389 +EPISD,computer,repair, +EPiServer AB,admin,store,http://world.episerver.com/Documentation/Items/Installation-Instructions/EPiServer-Commerce/Installation-Instructions---EPiServer-Commerce/#First%20Time%20Login +EZPhotoSales,admin,admin, +Eaton,admin,admin, +Echelon Corporation,ilon,ilon, +Edimax,admin,123, +Edimax,admin,1234, +Edimax,admin,, +Edimax,admin,epicrouter, +Edimax,admin,password, +Edimax,admin,su@psir, +Edimax,edimax,software01,for most Edimax HW???? +Edimax,guest,1234, +Edimax,guest,, +Efficient,,, +Efficient,,admin, +Efficient,,admin, +Efficient Networks,,hs7mwxkk, +Efficient Networks,,4getme2, +Efficient Networks,login,admin, +Efficient,login,admin, +Efficient,login,password, +Efficient,superuser,admin, +Efficinet Networks,login,admin, +"Ektron, Inc.",builtin,builtin,http://dev.ektron.com/kb_article.aspx?id=1818 +"Ektron, Inc.",sa,Ektron,http://downloads2.ektron.com/software/released/CMS400/v48/SetupManual.pdf +Elron,(hostname/ipaddress),sysadmin, +Elsa,,, +Elsa,,cisco, +Elsa,,, +Elsa,,cisco, +Emerson,Admin,Emerson1, +Eminent,admin,admin, +EnGenius,admin,admin, +Enhydra ,admin,enhydra, +Enox,,xo11nE, +Enox,,xo11nE, +Enterasys,,netadmin, +Enterasys,admin,, +Enterasys,admin,netadmin, +Enterasys,tiger,tiger123, +Entrust,admin,admin, +Entrust,websecadm,changeme,Access to Admin Gui via /sek-bin/ +Epox,,central, +Epox,,central, +Ericsson ACC,public,, +Ericsson,MD110,help, +Ericsson,admin,default, +Ericsson,expert,expert, +Ericsson,netman,netman, +EverFocus,admin,admin, +EverFocus,operator,operator, +EverFocus,supervisor,supervisor, +Exabyte,anonymous,Exabyte, +Exacq Technologies,admin,admin256,http://d1ni7hpbick8ut.cloudfront.net/ev-desktop-IP-quickstart-0309.pdf +Exacq Technologies,user,user5710,http://d1ni7hpbick8ut.cloudfront.net/ev-desktop-IP-quickstart-0309.pdf +Exinda Networks,admin,exinda, +Extended Systems,admin,admin, +Extended Systems,admin,extendnet, +Extreme Networks,admin,, +F5,admin,admin, +F5,root,default, +F5,support,, +F5-Networks,,, +Fastream Technologies,root,, +Fastwire,fastwire,fw, +FatWire,firstsite,firstsite,http://www.vvgr.demon.co.uk/FatWire_Analytics.pdf +FatWire,fwadmin,xceladmin,http://www.vvgr.demon.co.uk/FatWire_Analytics.pdf +Firebird Project,SYSDBA,masterkey, +Firebird,SYSDBA,masterkey, +Flowpoint,,, +Flowpoint,,password, +Flowpoint,,, +Flowpoint,,password, +Flowpoint,admin,admin, +Fortigate,admin,, +Fortinet,,bcpb(serial number of the firewall), +Fortinet,admin,, +Fortinet,maintainer,admin, +Fortinet,maintainer,bcpb[SERIAL NO.], +Fortinet,maintainer,pbcpbn(add-serial-number), +Foscam,admin,,http://foscam.com/Private/ProductFiles/FI8918W%20user%20manual-v36.00.pdf +Foundry Networks,,, +Foundry Networks,admin,admin, +Freetech,,Posterie, +Freetech,,Posterie, +FrontRange Solutions,master,access, +Fujitsu Siemens,,connect, +Fujitsu Siemens,manage,!manage, +Funk Software,admin,radius, +"GE Security, Inc.",install,install,http://www.qdigital.us/soporte/CasiRusco/Casirusco-documentation/controllers/460972001B.pdf +GE,museadmin,Muse!Admin, +GVC,Administrator,admin, +Galacticomm,Sysop,Sysop, +Gandalf,,console, +Gandalf,,gandalf, +Gandalf,,system, +Gandalf,,xmux, +Gateway,admin,admin, +Geeklog,username,password, +General Instruments,test,test, +Gericom,Administrator,, +Gigabyte,admin,admin, +Globespan Virata,DSL,DSL, +GlobespanVirata,root,root, +Google,admin,urchin, +Gossamer Threads Inc.,admin,admin, +Gossamer Threads Inc.,author,author, +Gossamer Threads Inc.,guest,guest, +GrandStream,,admin, +GrandStream,Administrator,admin, +GrandStream,End User,123 (or blank), +"Grandstream Networks, Inc",End User,123,http://www.grandstream.com/user_manuals/HandyTone-486UserManual.pdf +"Grandstream Networks, Inc",admin,admin,http://www.grandstream.com/user_manuals/HandyTone-486UserManual.pdf +Grandstream,admin,1234, +Greatspeed,admin,broadband, +"Groupee, Inc.",Admin5,4tugboat, +GuardOne,,guardone, +GuardOne,n.a,guardone, +Guru,admin,admin, +H2O Project,admin,admin, +HP,,, +HP,,AUTORAID, +HP,Administrator,admin, +HP,Factory,56789, +HP,admin,!admin, +HP,admin,, +HP,admin,admin, +HP,admin,isee, +HP,root,password, +Hayes,system,isp, +Hemoco Software,lansweeperuser,mysecretpassword0*,http://www.lansweeper.com/documentation.pdf +Hewlett Packard,admin,admin, +Hewlett-Packard,,, +Hewlett-Packard,,hewlpack, +Hewlett-Packard,,hewlpack, +Hewlett-Packard,ADVMAIL,, +Hewlett-Packard,ADVMAIL,HP, +Hewlett-Packard,ADVMAIL,HPOFFICE DATA, +Hewlett-Packard,Admin,Admin, +Hewlett-Packard,Administrator,The last eight digits of the serial number,http://bizsupport1.austin.hp.com/bizsupport/TechSupport/Document.jsp?objectID=c01141537&lang=en&cc=us&taskId=101&prodSeriesId=428936&prodTypeId=15351 +Hewlett-Packard,Anonymous,, +Hewlett-Packard,FIELD,, +Hewlett-Packard,FIELD,HPONLY, +Hewlett-Packard,FIELD,HPP187 SYS, +Hewlett-Packard,FIELD,HPWORD PUB, +Hewlett-Packard,FIELD,LOTUS, +Hewlett-Packard,FIELD,MANAGER, +Hewlett-Packard,FIELD,MGR, +Hewlett-Packard,FIELD,SERVICE, +Hewlett-Packard,FIELD,SUPPORT, +Hewlett-Packard,HELLO,FIELD.SUPPORT, +Hewlett-Packard,HELLO,MANAGER.SYS, +Hewlett-Packard,HELLO,MGR.SYS, +Hewlett-Packard,HELLO,OP.OPERATOR, +Hewlett-Packard,HPSupport,badg3r5,http://www.lolware.net/hpstorage.html +Hewlett-Packard,MAIL,HPOFFICE, +Hewlett-Packard,MAIL,MAIL, +Hewlett-Packard,MAIL,MPE, +Hewlett-Packard,MAIL,REMOTE, +Hewlett-Packard,MAIL,TELESUP, +Hewlett-Packard,MANAGER,COGNOS, +Hewlett-Packard,MANAGER,HPOFFICE, +Hewlett-Packard,MANAGER,ITF3000, +Hewlett-Packard,MANAGER,SECURITY, +Hewlett-Packard,MANAGER,SYS, +Hewlett-Packard,MANAGER,TCH, +Hewlett-Packard,MANAGER,TELESUP, +Hewlett-Packard,MGE,VESOFT, +Hewlett-Packard,MGR,CAROLIAN, +Hewlett-Packard,MGR,CCC, +Hewlett-Packard,MGR,CNAS, +Hewlett-Packard,MGR,COGNOS, +Hewlett-Packard,MGR,CONV, +Hewlett-Packard,MGR,HPDESK, +Hewlett-Packard,MGR,HPOFFICE, +Hewlett-Packard,MGR,HPONLY, +Hewlett-Packard,MGR,HPP187, +Hewlett-Packard,MGR,HPP189, +Hewlett-Packard,MGR,HPP196, +Hewlett-Packard,MGR,INTX3, +Hewlett-Packard,MGR,ITF3000, +Hewlett-Packard,MGR,NETBASE, +Hewlett-Packard,MGR,REGO, +Hewlett-Packard,MGR,RJE, +Hewlett-Packard,MGR,ROBELLE, +Hewlett-Packard,MGR,SECURITY, +Hewlett-Packard,MGR,SYS, +Hewlett-Packard,MGR,TELESUP, +Hewlett-Packard,MGR,VESOFT, +Hewlett-Packard,MGR,WORD, +Hewlett-Packard,MGR,XLSERVER, +Hewlett-Packard,OPERATOR,COGNOS, +Hewlett-Packard,OPERATOR,DISC, +Hewlett-Packard,OPERATOR,SUPPORT, +Hewlett-Packard,OPERATOR,SYS, +Hewlett-Packard,OPERATOR,SYSTEM, +Hewlett-Packard,Oper,Oper, +Hewlett-Packard,PCUSER,SYS, +Hewlett-Packard,RSBCMON,SYS, +Hewlett-Packard,SPOOLMAN,HPOFFICE, +Hewlett-Packard,WP,HPOFFICE, +Hewlett-Packard,admin,admin,http://www.google.com/url?sa=t&source=web&cd=1&sqi=2&ved=0CBgQFjAA&url=http%3A%2F%2Fcdn.procurve.com%2Ftraining%2FManuals%2Fr52%2F42-10-5100-02_QS_MSC-5100_en.pdf&ei=b1DkTZ7HBInQgAfwzPDCBg&usg=AFQjCNEPTe_QUv1bf17RCW-0wYwrJmS24g +Hewlett-Packard,admin,hp.com, +Hewlett-Packard,admin,isee, +HighPOint,RAID,hpt,http://www.hptmac.com/image/PDF/RAID_Managment_Software_Download.pdf +Honeynet Project,roo,honey, +Honeynet Project,root,honey, +Honeywell,LocalComServer,LCS pwd 03, +Honeywell,TPSLocalServer,TLS pwd 03, +Horizon DataSys,,foolproof, +Hosting Controller,AdvWebadmin,advcomm500349, +Huawei,TMAR#HWMT8007079,, +Huawei Technologies Co,TMAR#HWMT8007079,, +Huawei Technologies Co,admin,admin, +Huawei,admin,admin, +"Hyperic, Inc.",hqadmin,hqadmin,http://support.hyperic.com/display/DOC/QuickStart+Installation +IBM,$ALOC$,, +IBM,$SRV,$SRV, +IBM,11111111,11111111, +IBM,22222222,22222222, +IBM,,IBM, +IBM,,MBIU0, +IBM,,ascend, +IBM,,sertafu, +IBM,,, +IBM,,IBM, +IBM,,MBIU0, +IBM,,R1QTPS,submitted by FX +IBM,,admin, +IBM,,ascend, +IBM,,sertafu, +IBM,ADMIN,, +IBM,AP2SVP,, +IBM,APL2PP,, +IBM,AUTOLOG1,, +IBM,Administrator,admin, +IBM,BATCH,, +IBM,BATCH1,, +IBM,BATCH2,, +IBM,CCC,, +IBM,CICSUSER,CISSUS, +IBM,CMSBATCH,, +IBM,CMSBATCH,CMSBATCH, +IBM,CMSUSER,, +IBM,CPNUC,, +IBM,CPRM,, +IBM,CSPUSER,, +IBM,CVIEW,, +IBM,DATAMOVE,, +IBM,DBDCCICS,DBDCCIC, +IBM,DEMO1,, +IBM,DEMO2,, +IBM,DEMO3,, +IBM,DEMO4,, +IBM,DIRECT,, +IBM,DIRMAINT,, +IBM,DISKCNT,, +IBM,EREP,, +IBM,ESSEX,, +IBM,FORSE,FORSE, +IBM,FSFADMIN,, +IBM,FSFTASK1,, +IBM,FSFTASK2,, +IBM,GCS,, +IBM,IBMUSER,SYS1, +IBM,IDMS,, +IBM,IDMSSE,, +IBM,IIPS,, +IBM,IPC,, +IBM,IPFSERV,, +IBM,ISPVM,, +IBM,IVPM1,, +IBM,IVPM2,, +IBM,MAINT,, +IBM,MAINT,MAINT, +IBM,MOESERV,, +IBM,NEVIEW,, +IBM,OLTSEP,, +IBM,OP1,, +IBM,OPER,OPER, +IBM,OPERATIONS,OPERATIONS, +IBM,OPERATNS,, +IBM,OPERATNS,OPERATNS, +IBM,OPERATOR,, +IBM,Operator,Operator, +IBM,PDMREMI,, +IBM,PENG,, +IBM,POST,BASE, +IBM,PROCAL,, +IBM,PRODBM,, +IBM,PRODCICS,PRODCICS, +IBM,PROG,PROG, +IBM,PROMAIL,, +IBM,PSFMAINT,, +IBM,PVM,, +IBM,QSRV,11111111, +IBM,QSRV,22222222, +IBM,QSRV,QSRV, +IBM,RDM470,, +IBM,ROUTER,, +IBM,RSCS,, +IBM,RSCSV2,, +IBM,SAVSYS,, +IBM,SFCMI,, +IBM,SFCNTRL,, +IBM,SMART,, +IBM,SQLDBA,, +IBM,SQLUSER,, +IBM,SYSA,SYSA, +IBM,SYSADMIN,, +IBM,SYSCKP,, +IBM,SYSDUMP1,, +IBM,SYSERR,, +IBM,SYSWRM,, +IBM,TDISK,, +IBM,TEMP,, +IBM,TSAFVM,, +IBM,USERID,PASSW0RD, +IBM,USERID,PASSWORD,http://pic.dhe.ibm.com/infocenter/sonasic/sonas1ic/index.jsp?topic=%2Fcom.ibm.sonas.doc%2Fcreate_sol.html +IBM,VASTEST,, +IBM,VCSRV,VCSRV, +IBM,VM3812,, +IBM,VMARCH,, +IBM,VMASMON,, +IBM,VMASSYS,, +IBM,VMBACKUP,, +IBM,VMBSYSAD,, +IBM,VMMAP,, +IBM,VMTAPE,, +IBM,VMTLIBR,, +IBM,VMUTIL,, +IBM,VSEIPO,, +IBM,VSEMAINT,, +IBM,VSEMAN,, +IBM,VTAM,, +IBM,VTAM,VTAM, +IBM,VTAMUSER,, +IBM,admin,, +IBM,admin,admin, +IBM,admin,password, +IBM,admin,secure, +IBM,db2fenc1,db2fenc1, +IBM,db2inst1,db2inst1, +IBM,fg_sysadmin,password,http://webcache.googleusercontent.com/search?q=cache:tjiEP5dFc6IJ:help.sterlingcommerce.com/SFG20/topic/T94571/SFGCreateUserAccts_5101_127332_22331.html+sterling+fg_sysadmin+password&cd=1&hl=en&ct=clnk&gl=us&client=ubuntu&source=www.google.com +IBM,guest,, +IBM,guest,guest, +IBM,hscroot,abc123, +IBM,ibm,2222, +IBM,ibm,password, +IBM,ibm,service, +IBM,qpgmr,qpgmr, +IBM,qsecofr,11111111, +IBM,qsecofr,22222222, +IBM,qsecofr,qsecofr, +IBM,qserv,qserv, +IBM,qsrv,qsrv, +IBM,qsrvbas,qsrvbas, +IBM,qsvr,ibmcel, +IBM,qsvr,qsvr, +IBM,qsysopr,qsysopr, +IBM,quser,quser, +IBM,root,,Also works for older 4400 printers +IBM,root,passw0rd,http://pic.dhe.ibm.com/infocenter/powersys/v3r1m5/index.jsp?topic=/iphai_p5/whychgprepwds.htm +IBM,secofr,secofr, +IBM,sedacm,secacm, +IBM,storwatch,specialist,By Nicolas Gregoire +IBM,superadmin,secret,Documented in Web Administration Guide +IBM,sysopr,sysopr, +IBM,user,USERP, +IBM,vt100,public,Swap MAC address chip from +IBM,webadmin,webibm, +IBM,wpsadmin,wpsadmin, +INOVA,iclock,timely, +IQinVision,root,system,http://www.iqeye.com/iqeye/images/uploads/File/manuals/Quick-Install.pdf +IRC,,FOOBAR, +Inedo,Admin,Admin,http://inedo.com/support/tutorials/getting-started-with-proget-private-npm-registries +Infoblox,admin,, +Informix,informix,informix, +Infosmart,admin,0, +Infrant,admin,infrant1, +Innovaphone,admin,ip20, +Innovaphone,admin,ip21,http://www.annexnet.cz/New_PDF/innovaphone/gwe_manual.pdf +Innovaphone,admin,ip3000, +Innovaphone,admin,ip305Beheer, +Innovaphone,admin,ip400, +Inova,iclock,timely, +Integral,Administrator,letmein, +Integrated Networks,Administrator,1234, +Integrated Networks,Administrator,12345678, +Integrated Networks,Administrator,19750407, +Intel,,Intel, +Intel,,isolation, +Intel,,shiva, +Intel,Guest,, +Intel,NICONEX,NICONEX, +Intel,intel,intel, +Intel,root,, +Intel,setup,setup, +Intel/Shiva,admin,hello, +IntelliTouch,administrator,1234, +Interbase,SYSDBA,masterkey, +Intermec,,intermec, +Intermec,intermec,intermec, +Internet Archive,admin,letmein, +Intershop,operator,$chwarzepumpe, +Intersystems,system,sys, +Intracom,admin,admin, +Inventel Wanadoo,Admin,Admin, +Inventel,admin,admin, +Ipswitch,XXSESS_MGRYY,X#1833, +Ipswitch,admin,admin,http://www.ipswitch.com/support/whatsup/guide/v700/7browsera3.html +Ipswitch,guest,,http://www.ipswitch.com/support/whatsup/guide/v700/7browsera3.html +IronPort,admin,ironport, +Irongate,admin,NetSurvibox, +Iwill,,iwill, +Iwill,,iwill, +JAHT,admin,epicrouter, +JAMF Software,jamfsoftware,jamfsw03,http://resources.jamfsoftware.com/archive/Casper_Suite_Administrators_Guide.pdf +JD Edwards,JDE,JDE, +JDE,PRODDTA,PRODDTA, +JDS Microprocessing,hydrasna,, +JDS,hydrasna,, +Janitza,Homepage Password,0th,https://wiki.janitza.de/display/GRIDVIS40/UMG+604+-+Passwort +Janitza,admin,Janitza,https://wiki.janitza.de/display/GRIDVIS40/UMG+604+-+Passwort +Janitza,guest,Janitza,https://wiki.janitza.de/display/GRIDVIS40/UMG+604+-+Passwort +Janitza,user,Janitza,https://wiki.janitza.de/display/GRIDVIS40/UMG+604+-+Passwort +Jaspersoft Corporation,demo,demo,http://community.jaspersoft.com/documentation/jasperreports-server-install-guide-community-edition +Jaspersoft Corporation,jasperadmin,jasperadmin,http://community.jaspersoft.com/documentation/jasperreports-server-install-guide-community-edition +Jaspersoft Corporation,joeuser,joeuser,http://community.jaspersoft.com/documentation/jasperreports-server-install-guide-community-edition +Jaspersoft Corporation,superuser,superuser,http://community.jaspersoft.com/documentation/jasperreports-server-install-guide-community-edition +Jean-Philippe Lang,admin,admin,http://www.redmine.org/projects/redmine/wiki/RedmineInstall +Jeebles Technology,,admin, +JetWay,,spooml, +JetWay,,spooml, +Jetform,Jetform,, +Johnson Controls,johnson,control, +Joss Technology,,57gbzb, +Joss Technology,,technolgi, +Joss Technology,,57gbzb, +Joss Technology,,technolgi, +Juniper,admin,abc123,https://kb.juniper.net/InfoCenter/index?page=content&id=KB26220&actp=search +Juniper,admin,netscreen, +Juniper,admin,peribit, +Juniper,netscreen,netscreen, +Juniper,redline,redline, +Juniper,serial#,serial#,Resets to factory settings +Juniper,super,juniper123,https://kb.juniper.net/InfoCenter/index?page=content&id=KB26220&actp=search +Justin Hagstrom,admin,admin,http://autoindex.sourceforge.net/ +Justin Hagstrom,test,test,http://autoindex.sourceforge.net/ +KASDA,admin,adslroot, +KTI,admin,123, +KTI,admin,123456, +KTI,superuser,123456, +Kalatel,,3477, +Kalatel,,8111, +Kentico Software,administrator,,http://www.kentico.com/downloads/kenticocms_quickguide.pdf +Kethinov,root,password,http://freshmeat.net/projects/kboardforum/ +Keyscan,keyscan,KEYSCAN, +Kodak,PACSLinkIP,NetServer,http://yeec.com/uploadimages1/forum/yingxiang/kodak/mim_service_manual_v6_1.pdf +Kodak,PLMIMService,NetServer,http://yeec.com/uploadimages1/forum/yingxiang/kodak/mim_service_manual_v6_1.pdf +Kodak,RNIServiceManager,NetServer,http://yeec.com/uploadimages1/forum/yingxiang/kodak/mim_service_manual_v6_1.pdf +Kodak,SA,PASSWORD,http://yeec.com/uploadimages1/forum/yingxiang/kodak/mim_service_manual_v6_1.pdf +Kodak,Service,Service,http://yeec.com/uploadimages1/forum/yingxiang/kodak/mim_service_manual_v6_1.pdf +Kodi,kodi,kodi, +Konica Minolta,,0000, +Konica Minolta,,1234, +Konica Minolta,,, +Konica Minolta,,MagiMFP,http://www.kn.nl/data/handleiding/182185/Reference%20Guide%20Magicolor%202490MF.pdf +Konica Minolta,,sysAdmin, +Konica Minolta,,0,Printer configuration interface +Konica Minolta,,sysadm, +Konica Minolta,admin,administrator, +Kronos,SuperUser,kronites,http://www.scribd.com/doc/56930986/System-Administrators-Guide#outer_page_29 +Kyocera,2800,2800, +Kyocera,,admin00, +Kyocera,,PASSWORD, +Kyocera,,admin00, +Kyocera,admin,, +Kyocera,admin,admin, +Kyocera,root,root, +LANCOM,,, +LANSA,WEBADM,password, +LANSA,admin,admin,http://support.lansa.com/download/temp18/aXes_Rapid_Install_Instructions.pdf +LANSA,dev,dev,http://support.lansa.com/download/temp18/aXes_Rapid_Install_Instructions.pdf +LAXO,admin,admin, +LG,,jannie, +LG,admin,epicrouter, +LG,vikram,singh, +LGIC,LR-ISDN,LR-ISDN, +LaCie,admin,admin, +Lanier,,sysadm, +Lanier,admin,, +Lanier,supervisor,, +Lantronics,,access, +Lantronics,,system, +Lantronix,,access, +Lantronix,,,secondary priv. password: system +Lantronix,,access, +Lantronix,,admin,secondary priv. password: +Lantronix,,lantronix, +Lantronix,,system, +Lantronix,login,access, +Lantronix,sysadmin,PASS,9600/N/8/1 XON/XOFF +Leading Edge,,MASTER, +Leading Edge,,MASTER, +Lenel,admin,admin, +Level1,admin,admin, +Leviton,admin,leviton, +Liebert,Liebert,Liebert,http://www.emersonnetworkpower.com/documentation/en-us/products/acpower/rackpdu/documents/sl-20826.pdf +Lindsay Electronics,ADMINISTRATOR,SENTINEL, +Lindsay Electronics,SENTINEL,SENTINEL, +Linksys,,admin, +Linksys,,epicrouter, +Linksys,,, +Linksys,,admin, +Linksys,Administrator,admin, +Linksys,admin,, +Linksys,admin,admin, +Linksys,comcast,1234, +Linksys,root,orion99, +Linksys,user,tivonpw, +Linux,gonzo,, +Linux,root,uClinux, +Linux,satan,, +Linux,snake,, +"Liquidware Labs, Inc.",ssadmin,sspassword,http://www.liquidwarelabs.com/content/pdf/documents/support/Liquidware-Labs-Stratusphere-UX-Quick-Start-Guide.pdf +Livingston,!root,, +Livingstone,root,, +Lockdown,setup,changeme!, +LogiLink,admin,1234, +Logitech,,0, +Loglogic,root,logapp, +Loglogic,toor,logapp, +Longshine,admin,0,http://www.tenable.com/4917.html +Lucent,(any 3 characters),cascade, +Lucent,(any 3 chars),cascade, +Lucent,,admin, +Lucent,,cascade, +Lucent,Administrator,, +Lucent,LUCENT01,UI-PSWD-01,requires GSI software +Lucent,LUCENT02,UI-PSWD-02,requires GSI software +Lucent,admin,AitbISP4eCiG, +Lucent,admin,Ascend, +Lucent,bciim,bciimpw, +Lucent,bcim,bcimpw, +Lucent,bcms,bcmspw, +Lucent,bcnas,bcnaspw, +Lucent,blue,bluepw, +Lucent,browse,browsepw, +Lucent,browse,looker, +Lucent,craft,craft, +Lucent,craft,craftpw, +Lucent,cust,custpw, +Lucent,enquiry,enquirypw, +Lucent,field,support, +Lucent,inads,inads, +Lucent,inads,indspw, +Lucent,init,initpw, +Lucent,locate,locatepw, +Lucent,maint,maintpw, +Lucent,maint,rwmaint, +Lucent,nms,nmspw, +Lucent,pw,pwpw, +Lucent,rcust,rcustpw, +Lucent,readonly,lucenttech2, +Lucent,readwrite,lucenttech1, +Lucent,root,ascend, +Lucent,super,super, +Lucent,support,supportpw, +Lucent,sysadm,admpw, +Lucent,sysadm,sysadmpw, +Lucent,sysadm,syspw, +Lucent,tech,field, +Luxon Communications,administrator,19750407, +M Technology,,mMmM, +M Technology,,mMmM, +MERCURY,Administrator,admin, +MP3Mystic,admin,mp3mystic, +MRV,admin,admin, +MTNL,admin,admin, +MachSpeed,,sp99dd, +MachSpeed,,sp99dd, +Macromedia,,admin, +Macsense,admin,admin, +Magento,admin,123123,http://www.magentocommerce.com/wiki/recover/resetting-admin-password +Magic-Pro,,prost, +Magic-Pro,,prost, +Main Street Softworks,MCVEADMIN,password, +Mambo,admin,admin,http://sourceforge.org/projects/mambo +ManageEngine,admin,admin,http://www.manageengine.com/products/self-service-password/help/admin-guide/index.html +Mandarin Library Automation,admin,boca raton,http://www.nassauboces.org/cms/lib5/NY18000988/Centricity/Domain/31/Automation_handouts/M3_Users_Guide_1.6_SP1.pdf +Mantis,administrator,root, +Marconi,ami,, +McAfee,admin,admin123, +McAfee,scmadmin,scmchangeme, +McAfee,webshield,webshieldchangeme, +McData,Administrator,password, +McData,McdataSE,redips, +Mediatrix,admin,1234, +Mediatrix,administrator,, +Megastar,,star, +Megastar,,star, +Memotec,memotec,supervisor, +Mentec,MICRO,RSX, +Mercury Interactive,admin,admin, +Meridian,service,smile, +Michiel,admin,phplist,http://freshmeat.net/projects/phplist/ +Microcom,admin,epicrouter, +Microcom,admin,superuser, +Microcom,user,password, +Micron,,sldkj754, +Micron,,xyzall, +Micron,,sldkj754, +Micron,,xyzall, +Micronet,admin,admin,http://archives.neohapsis.com/archives/bugtraq/2004-10/0078.html +Micronet,admin,epicrouter, +Micronet,mac,, +Micronet,root,default, +Micronics,,dn_04rjc, +Micronics,,dn_04rjc, +Microplex,root,root, +Microsoft,,, +Microsoft,,admin, +Microsoft,,sa, +Microsoft,Administrator,, +Microsoft,Administrator,Administrator, +Microsoft,Guest,, +Microsoft,Guest,Guest, +Microsoft,IS_$hostname,IS_$hostname, +Microsoft,LDAP_Anonymous,LdapPassword_1, +Microsoft,LessonUser1,, +Microsoft,LessonUser2,, +Microsoft,MSHOME,MSHOME, +Microsoft,User,User, +Microsoft,sa,, +Mike Peters,bsxuser,bsxpass,http://freshmeat.net/projects/basilix/ +MikroTik,admin,, +Mikrotik,admin,,also for SSH and Web access +Milan,root,root, +Minolta PagrPro,,sysadm, +Minolta QMS,admin,, +Minolta QMS,operator,, +Mintel,,SYSTEM, +Mintel,,SYSTEM, +Mitel,,, +Mitel Networks,1nstaller,5X2000,http://www.tek-tips.com/viewthread.cfm?qid=1036643 +Mitel Networks,installer,sx2000,http://www.tek-tips.com/viewthread.cfm?qid=1036643 +Mitel Networks,maint1,sx2000,http://www.tek-tips.com/viewthread.cfm?qid=1036643 +Mitel Networks,maint2,sx2000,http://www.tek-tips.com/viewthread.cfm?qid=1036643 +Mitel Networks,s1stem,5X2000,http://www.tek-tips.com/viewthread.cfm?qid=1036643 +Mitel Networks,system,sx2000,http://www.tek-tips.com/viewthread.cfm?qid=1036643 +Mitel,installer,1000, +Mitel,system,mnet, +Mitel,system,password, +Mobotix,admin,meinsm, +Mole,admin,admin, +Motive,admin,isee, +Motorola,,0000,http://rarara77.googlepages.com/ +Motorola,admin,motorola, +Motorola,admin,password, +Motorola,cablecom,router, +Motorola,service,smile, +Motorola,setup,, +Motorola,technician,yZgO8Bvj,https://community.rapid7.com/Rapid7_BlogPostDetail?id=a111400000AanBsAAJ +Mutare,,admin, +Muze,admin,muze, +MySQL,admin@example.com,admin, +MySQL,root,, +MySQL,superdba,admin, +MyioSoft,demo,demo, +NAI,GlobalAdmin,GlobalAdmin,By Nicolas Gregoire +NAI,admin,admin123,By Nicolas Gregoire +NCR,ncrm,ncrm, +NEC,,, +NEC,admin,password, +NGSEcure,admin,admin, +NGSec,admin,, +NGSec,admin,asd, +NICE Systems Ltd.,Administrator,nicecti, +NICE Systems Ltd.,Nice-admin,nicecti, +NOMADIX,admin,, +NRG or RICOH,,password, +NSI,root,nsi,http://www.nsi.com.au/vmpfw-install.htm +Nanoteq,admin,NetSeq, +NeXT,me,, +NeXT,root,NeXT, +NeXT,signa,signa, +NetApp,admin,NetCache, +NetApp,admin,admin123, +NetBotz,netbotz,netbotz, +NetGenesis,naadmin,naadmin, +Netasq,admin,admin, +Netcomm,,admin, +Netcomm,admin,password, +Netcomm,user,password, +Netcordia,admin,admin, +Netgear,,1234, +Netgear,,admin, +Netgear,,private, +Netgear,,zebra, +Netgear,,, +Netgear,,admin, +Netgear,,password, +Netgear,Admin,password, +Netgear,Gearguy,Geardog, +Netgear,admin,1234, +Netgear,admin,, +Netgear,admin,admin, +Netgear,admin,draadloos, +Netgear,admin,infrant1,Upto v3 firmware +Netgear,admin,netgear1,v4 firmware onwards +Netgear,admin,password, +Netgear,admin,setup, +Netgear,comcast,1234, +Netgear,cusadmin,highspeed, +Netgear,super,5777364, +Netgear,superman,21241036, +Netopia,,, +Netopia,,, +Netopia,admin,, +Netopia,admin,noway, +Netopia,factory,(see note),http://packetstormsecurity.org/files/91948/Netopia-Routers-Factory-Password-Generator.html +Netopia,netopia,netopia, +Netport,setup,setup, +Netscape,admin,admin, +Netscreen,,, +Netscreen,Administrator,, +Netscreen,admin,, +Netscreen,admin,netscreen, +Netscreen,netscreen,netscreen, +Netscreen,operator,, +Netstar,admin,password, +Network Appliance,admin,NetCache, +Network Associates,e250,e250changeme, +Network Associates,e500,e500changeme, +Network Everywhere,,admin, +NetworkICE,iceman,, +NewMedia-NET GmbH,root,admin,http://www.dd-wrt.com/wiki/index.php/Index:FAQ#What.27s_the_default_username_and_password.3F +Nexsan,ADMIN,PASSWORD, +Niksun,vcr,NetVCR,su after login with empty password +Nimble,,xdfk9874t3, +Nimble,,xdfk9874t3, +Nokia,,9999, +Nokia,,Telecom, +Nokia,,nokai, +Nokia,,nokia, +Nokia,Security Code,12345, +Nokia,Telecom,Telecom, +Nokia,client,client, +Nokia,m1122,m1122, +Nokia,nop,12345, +Nokia,nop,123454, +Nokia,root,nokia, +Nokia,root,rootme, +Nokia,telecom,telecom, +Norstar,**23646,23646, +Norstar,**266344,266344, +Nortel,266344,266344, +Nortel,,0, +Nortel,,, +Nortel,,l1, +Nortel,,l2, +Nortel,,ro, +Nortel,,rw, +Nortel,,rwa, +Nortel,,secure, +Nortel,,266344, +Nortel,,, +Nortel,,secure, +Nortel,Manager,, +Nortel,admin,000000,http://support.avaya.com/css/P8/documents/100097575 +Nortel,admin,,http://support.avaya.com/css/P8/documents/100097575 +Nortel,admin,admin, +Nortel,admin,admin000, +Nortel,admin,root, +Nortel,admin,setup, +Nortel,administrator,PlsChgMe!, +Nortel,ccrusr,ccrusr, +Nortel,conferencing,admin,http://support.avaya.com/css/P8/documents/100097575 +Nortel,debug,gubed,http://support.avaya.com/css/P8/documents/100097575 +Nortel,distrib,distrib0, +Nortel,disttech,4tas, +Nortel,disttech,disttech, +Nortel,disttech,etas, +Nortel,l2,l2, +Nortel,l3,l3, +Nortel,login,0,AUTH codes in LD 8 +Nortel,login,0000, +Nortel,login,1111,AUTH codes in LD 8 +Nortel,login,8429,AUTH codes in LD 8 +Nortel,maint,maint, +Nortel,maint,ntacdmax, +Nortel,mlusr,mlusr, +Nortel,ro,ro, +Nortel,root,3ep5w2u, +Nortel,rw,rw, +Nortel,rwa,rwa, +Nortel,service,smile, +Nortel,spcl,0,AUTH codes in LD 8 +Nortel,spcl,0000, +Nortel,supervisor,PlsChgMe!, +Nortel,supervisor,visor, +Nortel,sysadmin,nortel, +Nortel,system,adminpwd, +Nortel,tasman,tasmannet, +Nortel,trmcnfg,trmcnfg, +Nortel,user,, +Nortel,user,user, +Nortel,user,user0000, +Novell,,cr0wmt 911, +Novell,,root, +Novell,,san fran 8, +Novell,ADMIN,, +Novell,ADMIN,ADMIN, +Novell,ADMIN,admin, +Novell,ARCHIVIST,, +Novell,ARCHIVIST,ARCHIVIST, +Novell,BACKUP,, +Novell,BACKUP,BACKUP, +Novell,CHEY_ARCHSVR,, +Novell,CHEY_ARCHSVR,CHEY_ARCHSVR, +Novell,FAX,, +Novell,FAX,FAX, +Novell,FAXUSER,, +Novell,FAXUSER,FAXUSER, +Novell,FAXWORKS,, +Novell,FAXWORKS,FAXWORKS, +Novell,GATEWAY,, +Novell,GATEWAY,GATEWAY, +Novell,GUEST,, +Novell,GUEST,GUEST, +Novell,GUEST,GUESTGUE, +Novell,GUEST,GUESTGUEST, +Novell,GUEST,TSEUG, +Novell,HPLASER,, +Novell,HPLASER,HPLASER, +Novell,LASER,, +Novell,LASER,LASER, +Novell,LASERWRITER,, +Novell,LASERWRITER,LASERWRITER, +Novell,MAIL,, +Novell,MAIL,MAIL, +Novell,POST,, +Novell,POST,POST, +Novell,PRINT,, +Novell,PRINT,PRINT, +Novell,PRINTER,, +Novell,PRINTER,PRINTER, +Novell,ROOT,, +Novell,ROOT,ROOT, +Novell,ROUTER,, +Novell,SABRE,, +Novell,SUPERVISOR,, +Novell,SUPERVISOR,HARRIS, +Novell,SUPERVISOR,NETFRAME, +Novell,SUPERVISOR,NF, +Novell,SUPERVISOR,NFI, +Novell,SUPERVISOR,SUPERVISOR, +Novell,SUPERVISOR,SYSTEM, +Novell,TEST,, +Novell,TEST,TEST, +Novell,USER_TEMPLATE,, +Novell,USER_TEMPLATE,USER_TEMPLATE, +Novell,WANGTEK,, +Novell,WANGTEK,WANGTEK, +Novell,WINDOWS_PASSTHRU,, +Novell,WINDOWS_PASSTHRU,WINDOWS_PASSTHRU, +Novell,WINSABRE,SABRE, +Novell,WINSABRE,WINSABRE, +Novell,admin,admin,https://www.novell.com/documentation/vibe32/vibe32_admin/data/brchh4k.html +Novell,admin,novell, +Novell,sadmin,, +Novell,servlet,manager, +Nullsoft,admin,changeme, +Nurit,$system,, +OCE,,0 and the number of OCE printer, +ODS,ods,ods, +OMRON,,, +OPEN Networks,root,0P3N, +OSMC,osmc,osmc, +OTRS Inc.,root@localhost,root,http://doc.otrs.org/2.4/en/html/c444.html +Oki,admin,,Last 6 characters of the MAC address in uppercase +Oki,admin,OkiLAN, +Oki,root,,Last 6 characters of the MAC address in uppercase +Oleg Khabarov,username,password,https://github.com/comfy/comfortable-mexican-sofa/wiki/Installation-and-Quick-Start-Guide#quick-start-guide +Olicom,,AaBbCcDd, +Omnitronix,,SMDR, +Omnitronix,,SUPER, +Open-Xchange Inc.,mailadmin,secret, +OpenConnect,admin,OCS, +OpenConnect,adminstat,OCS, +OpenConnect,adminuser,OCS, +OpenConnect,adminview,OCS, +OpenConnect,helpdesk,OCS, +OpenMarket,Bobo,hello, +OpenMarket,Coco,hello, +OpenMarket,Flo,hello, +OpenMarket,Joe,hello, +OpenMarket,Moe,hello, +OpenMarket,admin,demo, +OpenMarket,user_analyst,demo, +OpenMarket,user_approver,demo, +OpenMarket,user_author,demo, +OpenMarket,user_checker,demo, +OpenMarket,user_designer,demo, +OpenMarket,user_editor,demo, +OpenMarket,user_expert,demo, +OpenMarket,user_marketer,demo, +OpenMarket,user_pricer,demo, +OpenMarket,user_publisher,demo, +Openlink,admin,admin, +Openwave,cac_admin,cacadmin, +Openwave,sys,uplink, +Optivision,root,mpegvideo, +Oracle,,, +Oracle,ADAMS,WOOD, +Oracle,ADLDEMO,ADLDEMO, +Oracle,ADMIN,JETSPEED, +Oracle,ADMIN,WELCOME, +Oracle,ADMINISTRATOR,ADMINISTRATOR, +Oracle,ADMINISTRATOR,admin, +Oracle,ANDY,SWORDFISH, +Oracle,AP,AP, +Oracle,APPLSYS,APPLSYS, +Oracle,APPLSYS,FND, +Oracle,APPLSYSPUB,FNDPUB, +Oracle,APPS,APPS, +Oracle,APPUSER,APPUSER, +Oracle,AQ,AQ, +Oracle,AQDEMO,AQDEMO, +Oracle,AQJAVA,AQJAVA, +Oracle,AQUSER,AQUSER, +Oracle,AUDIOUSER,AUDIOUSER, +Oracle,AURORA$JIS$UTILITY$,, +Oracle,AURORA$ORB$UNAUTHENTICATED,INVALID, +Oracle,AURORA@ORB@UNAUTHENTICATED,INVALID, +Oracle,BC4J,BC4J, +Oracle,BLAKE,PAPER, +Oracle,BRIO_ADMIN,BRIO_ADMIN, +Oracle,CATALOG,CATALOG, +Oracle,CDEMO82,CDEMO82, +Oracle,CDEMOCOR,CDEMOCOR, +Oracle,CDEMORID,CDEMORID, +Oracle,CDEMOUCB,CDEMOUCB, +Oracle,CENTRA,CENTRA, +Oracle,CIDS,CIDS, +Oracle,CIS,CIS, +Oracle,CISINFO,CISINFO, +Oracle,CLARK,CLOTH, +Oracle,COMPANY,COMPANY, +Oracle,COMPIERE,COMPIERE, +Oracle,CQSCHEMAUSER,PASSWORD, +Oracle,CSMIG,CSMIG, +Oracle,CTXDEMO,CTXDEMO, +Oracle,CTXSYS,, +Oracle,CTXSYS,CTXSYS, +Oracle,DBI,MUMBLEFRATZ, +Oracle,DBSNMP,DBSNMP, +Oracle,DEMO,DEMO, +Oracle,DEMO8,DEMO8, +Oracle,DEMO9,DEMO9, +Oracle,DES,DES, +Oracle,DEV2000_DEMOS,DEV2000_DEMOS, +Oracle,DIP,DIP, +Oracle,DISCOVERER_ADMIN,DISCOVERER_ADMIN, +Oracle,DSGATEWAY,DSGATEWAY, +Oracle,DSSYS,DSSYS, +Oracle,EJSADMIN,EJSADMIN, +Oracle,EMP,EMP, +Oracle,ESTOREUSER,ESTORE, +Oracle,EVENT,EVENT, +Oracle,EXFSYS,EXFSYS, +Oracle,FINANCE,FINANCE, +Oracle,FND,FND, +Oracle,FROSTY,SNOWMAN, +Oracle,GL,GL, +Oracle,GPFD,GPFD, +Oracle,GPLD,GPLD, +Oracle,HCPARK,HCPARK, +Oracle,HLW,HLW, +Oracle,HR,HR, +Oracle,IMAGEUSER,IMAGEUSER, +Oracle,IMEDIA,IMEDIA, +Oracle,JMUSER,JMUSER, +Oracle,JONES,STEEL, +Oracle,JWARD,AIROPLANE, +Oracle,L2LDEMO,L2LDEMO, +Oracle,LBACSYS,LBACSYS, +Oracle,LIBRARIAN,SHELVES, +Oracle,MASTER,PASSWORD, +Oracle,MDDEMO,MDDEMO, +Oracle,MDDEMO_CLERK,CLERK, +Oracle,MDDEMO_MGR,MGR, +Oracle,MDSYS,MDSYS, +Oracle,MFG,MFG, +Oracle,MGWUSER,MGWUSER, +Oracle,MIGRATE,MIGRATE, +Oracle,MILLER,MILLER, +Oracle,MMO2,MMO2, +Oracle,MODTEST,YES, +Oracle,MOREAU,MOREAU, +Oracle,MTSSYS,MTSSYS, +Oracle,MTS_USER,MTS_PASSWORD, +Oracle,MTYSYS,MTYSYS, +Oracle,MXAGENT,MXAGENT, +Oracle,NAMES,NAMES, +Oracle,OAS_PUBLIC,OAS_PUBLIC, +Oracle,OCITEST,OCITEST, +Oracle,ODM,ODM, +Oracle,ODM_MTR,MTRPW, +Oracle,ODS,ODS, +Oracle,ODSCOMMON,ODSCOMMON, +Oracle,OE,OE, +Oracle,OEMADM,OEMADM, +Oracle,OEMREP,OEMREP, +Oracle,OLAPDBA,OLAPDBA, +Oracle,OLAPSVR,INSTANCE, +Oracle,OLAPSYS,MANAGER, +Oracle,OMWB_EMULATION,ORACLE, +Oracle,OO,OO, +Oracle,OPENSPIRIT,OPENSPIRIT, +Oracle,ORACACHE,(random password), +Oracle,ORAREGSYS,ORAREGSYS, +Oracle,ORASSO,ORASSO, +Oracle,ORDPLUGINS,ORDPLUGINS, +Oracle,ORDSYS,ORDSYS, +Oracle,OSE$HTTP$ADMIN,(random password), +Oracle,OSP22,OSP22, +Oracle,OUTLN,OUTLN, +Oracle,OWA,OWA, +Oracle,OWA_PUBLIC,OWA_PUBLIC, +Oracle,OWNER,OWNER, +Oracle,PANAMA,PANAMA, +Oracle,PATROL,PATROL, +Oracle,PERFSTAT,PERFSTAT, +Oracle,PLEX,PLEX, +Oracle,PLSQL,SUPERSECRET, +Oracle,PM,PM, +Oracle,PO,PO, +Oracle,PO7,PO7, +Oracle,PO8,PO8, +Oracle,PORTAL30,PORTAL30, +Oracle,PORTAL30,PORTAL31, +Oracle,PORTAL30_DEMO,PORTAL30_DEMO, +Oracle,PORTAL30_PUBLIC,PORTAL30_PUBLIC, +Oracle,PORTAL30_SSO,PORTAL30_SSO, +Oracle,PORTAL30_SSO_PS,PORTAL30_SSO_PS, +Oracle,PORTAL30_SSO_PUBLIC,PORTAL30_SSO_PUBLIC, +Oracle,POWERCARTUSER,POWERCARTUSER, +Oracle,PRIMARY,PRIMARY, +Oracle,PUBSUB,PUBSUB, +Oracle,PUBSUB1,PUBSUB1, +Oracle,QDBA,QDBA, +Oracle,QS,QS, +Oracle,QS_ADM,QS_ADM, +Oracle,QS_CB,QS_CB, +Oracle,QS_CBADM,QS_CBADM, +Oracle,QS_CS,QS_CS, +Oracle,QS_ES,QS_ES, +Oracle,QS_OS,QS_OS, +Oracle,QS_WS,QS_WS, +Oracle,RE,RE, +Oracle,REPADMIN,REPADMIN, +Oracle,REPORTS_USER,OEM_TEMP, +Oracle,REP_MANAGER,DEMO, +Oracle,REP_OWNER,DEMO, +Oracle,REP_OWNER,REP_OWNER, +Oracle,RMAIL,RMAIL, +Oracle,RMAN,RMAN, +Oracle,SAMPLE,SAMPLE, +Oracle,SAP,SAPR3, +Oracle,SCOTT,TIGER, +Oracle,SDOS_ICSAP,SDOS_ICSAP, +Oracle,SECDEMO,SECDEMO, +Oracle,SERVICECONSUMER1,SERVICECONSUMER1, +Oracle,SH,SH, +Oracle,SITEMINDER,SITEMINDER, +Oracle,SLIDE,SLIDEPW, +Oracle,STARTER,STARTER, +Oracle,STRAT_USER,STRAT_PASSWD, +Oracle,SWPRO,SWPRO, +Oracle,SWUSER,SWUSER, +Oracle,SYMPA,SYMPA, +Oracle,SYS,CHANGE_ON_INSTALL, +Oracle,SYS,D_SYSPW, +Oracle,SYSADM,SYSADM, +Oracle,SYSMAN,OEM_TEMP, +Oracle,SYSMAN,oem_temp, +Oracle,SYSTEM,D_SYSTPW, +Oracle,SYSTEM,MANAGER, +Oracle,TAHITI,TAHITI, +Oracle,TDOS_ICSAP,TDOS_ICSAP, +Oracle,TESTPILOT,TESTPILOT, +Oracle,TRACESRV,TRACE, +Oracle,TRACESVR,TRACE, +Oracle,TRAVEL,TRAVEL, +Oracle,TSDEV,TSDEV, +Oracle,TSUSER,TSUSER, +Oracle,TURBINE,TURBINE, +Oracle,ULTIMATE,ULTIMATE, +Oracle,USER,USER, +Oracle,USER0,USER0, +Oracle,USER1,USER1, +Oracle,USER2,USER2, +Oracle,USER3,USER3, +Oracle,USER4,USER4, +Oracle,USER5,USER5, +Oracle,USER6,USER6, +Oracle,USER7,USER7, +Oracle,USER8,USER8, +Oracle,USER9,USER9, +Oracle,UTLBSTATU,UTLESTAT, +Oracle,VIDEOUSER,VIDEO USER, +Oracle,VIF_DEVELOPER,VIF_DEV_PWD, +Oracle,VIRUSER,VIRUSER, +Oracle,VRR1,VRR1, +Oracle,WEBCAL01,WEBCAL01, +Oracle,WEBDB,WEBDB, +Oracle,WEBREAD,WEBREAD, +Oracle,WKSYS,WKSYS, +Oracle,WWW,WWW, +Oracle,WWWUSER,WWWUSER, +Oracle,XPRT,XPRT, +Oracle,admin,admin,http://docs.oracle.com/cd/E22630_01/Platform.1002/pdf/ATGInstallGuide.pdf +Oracle,admin,adminadmin,http://www.oracle.com/technetwork/java/install-139173.html +Oracle,admin,security, +Oracle,admin,welcome, +Oracle,bpel,bpel, +Oracle,cn=orcladmin,welcome, +Oracle,demo,demo, +Oracle,ilom-admin,ilom-admin,http://seclists.org/fulldisclosure/2012/Nov/229 +Oracle,ilom-operator,ilom-operator,http://seclists.org/fulldisclosure/2012/Nov/229 +Oracle,internal,oracle, +Oracle,joe,password, +Oracle,mary,password, +Oracle,nm2user,nm2user,http://seclists.org/fulldisclosure/2012/Nov/229 +Oracle,oracle,oracle, +Oracle,scott,tiger or tigger, +Oracle,siteadmin,siteadmin,http://docs.oracle.com/cd/E24152_01/Platform.10-1/ATGMultisiteAdminGuide/html/s1505accesscontrol01.html +Oracle,sys,change_on_install, +Oracle,sys,sys, +Oracle,system,manager, +Oracle,system,password, +Oracle,system,security, +Oracle,system/manager,sys/change_on_install, +Oracle,webdb,webdb, +Oracle,weblogic,weblogic, +Oracle,wlcsystem,wlcsystem, +Oracle,wlpisystem,wlpisystem, +Orange,admin,admin, +Orange,root,1234, +Osicom,Manager,Admin, +Osicom,Manager,Manager, +Osicom,d.e.b.u.g,User, +Osicom,debug,d.e.b.u.g, +Osicom,echo,User, +Osicom,echo,echo, +Osicom,guest,User, +Osicom,guest,guest, +Osicom,sysadm,Admin, +Osicom,sysadm,sysadm, +Osicom,write,private, +Overland,Factory,56789, +Overland Storage,root,Password, +OvisLink Canada Inc.,root,root, +OvisLink Canada Inc.,user,user, +PBX,tech,nician, +PHPReactor,core,phpreactor,http://freshmeat.net/projects/phpreactor/ +PLANET Technology Corp.,admin,ISPMODE, +PLANET Technology Corp.,admin,[^_^], +POWERLOGIC,Administrator,Gateway,http://www.merlingerin.com/C12570CB00504485/all/83A902802C60F942412570D9003ABDC1/$File/63230-319-204.pdf +PRTG,prtgadmin,prtgadmin, +Pacific Micro Data,pmd,, +Packard Bell,,bell9, +Packard Bell,,bell9, +Packeteer,,touchpwd=, +Panasonic,,1234, +Panasonic,,, +Panasonic,admin,1234, +Panasonic,admin,12345,ftp://ftp.panasonic.com/pub/Panasonic/cctv/OperatingInstructions/WV-NS202A-Operating-Instructions.pdf +Pandatel,admin,admin, +Parallels,admin,setup, +Parrot,,0000, +Patton,monitor,monitor, +Patton,superuser,superuser, +PentaSafe,PSEAdmin,$secure$, +Pentagram,admin,password, +Pentaoffice,,pento, +Perle,admin,superuser, +Philips,admin,admin, +Phoenix v1.14,Administrator,admin, +Pikatel,DSL,DSL, +Pirelli,admin,admin, +Pirelli,admin,microbusiness, +Pirelli,admin,mu, +Pirelli,admin,smallbusiness, +Pirelli,user,password, +"Pivotal Software, Inc. ",guest,guest,https://www.rabbitmq.com/management.html +PlainTree,,default.password, +Planet,,default, +Planet,admin,1234, +Planet,admin,epicrouter, +Planex,admin,0, +PokerTracker Software,postgres,dbpass,http://www.pokertracker.com/products/PT3/docs/PokerTracker3_Quick_Start_Guide.pdf +PokerTracker Software,postgres,svcPASS83,http://www.pokertracker.com/products/PT3/docs/PokerTracker3_Quick_Start_Guide.pdf +Pollsafe,SMDR,SECONDARY, +Polycom,,, +Polycom,,ACCORD,"http://www.polycom.com/common/pw_cmp_updateDocKeywords/0,1687,6312,00.pdf" +Polycom,,admin, +Polycom,,x6zynd56, +Polycom,Polycom,456,username is case sensitive +Polycom,Polycom,SpIp, +Polycom,administrator,* * #, +PostgreSQL,postgres,, +Powerchute,pwrchute,pwrchute, +Prestige,admin,1234, +Prestigio,,, +Prime,dos,dos, +Prime,fam,fam, +Prime,guest,guest, +Prime,guest1,guest, +Prime,guest1,guest1, +Prime,mail,mail, +Prime,maint,maint, +Prime,mfd,mfd, +Prime,netlink,netlink, +Prime,prime,prime, +Prime,prime,primeos, +Prime,primenet,primenet, +Prime,primenet,primeos, +Prime,primeos,prime, +Prime,primeos,primeos, +Prime,primos_cs,prime, +Prime,primos_cs,primos, +Prime,system,prime, +Prime,system,system, +Prime,tele,tele, +Prime,test,test, +PrimeBase,Administrator,, +Prolink,admin,password, +"Promise Technology, Inc.",administrator,password,http://www.promise.com/media_bank/Download%20Bank/Manual/1_WebPAM%20User%20Manual%20v1.4.pdf +Promise,admin,admin, +Promise,engmode,hawk201, +Prostar,none,4321, +Protocraft,musi1921,Musi%1921, +Proxicast,,1234,http://www.proxicast.com/support/files/GPRS-QuickStartGuide.pdf +Proxim,,, +Proxim,,public, +Psionteklogix,admin,admin, +Psionteklogix,support,h179350, +Pyramid Computer,admin,admin, +Pyramid Computer,admin,gnumpf, +Q-Tec,Admin,, +QDI,,QDI, +QDI,,lesarotl, +QDI,,password, +QDI,,QDI, +QDI,,lesarotl, +QLogic,admin,password, +QLogic,images,images, +QualiTeam,master,master, +Quantex,,teX1, +Quantex,,xljlbj, +Quantex,,teX1, +Quantex,,xljlbj, +Quantum,,, +Quest Software,TOAD,TOAD, +Questra Corporation,guest,guest, +Questra Corporation,questra,questra, +Quintum Technologies Inc.,admin,admin, +RCA,,admin, +RM,,RM, +RM,,RM, +RM,RMUser1,password, +RM,admin,rmnetlm, +RM,admin2,changeme, +RM,adminstrator,changeme, +RM,deskalt,password, +RM,deskman,changeme, +RM,desknorm,password, +RM,deskres,password, +RM,guest,, +RM,replicator,replicator, +RM,setup,changeme, +RM,teacher,password, +RM,temp1,password, +RM,topicalt,password, +RM,topicnorm,password, +RM,topicres,password, +RNN,admin,demo, +RObiGVqUbQt,wVQxyQec,eomjbOBLLwbZeiKV, +RSA,admin,admin1234, +RSA,administrator,RSAAppliance, +RSA,master,themaster01, +Radio Shack,,744, +Radio Shack,[MULTIPLE],744, +Radvision,,MCUrv, +Radvision,admin,, +Radware,lp,lp, +Radware,radware,radware, +Raidzone,,raidzone, +Raidzone,,raidzone, +Rainbow,,PASSWORD, +Rainbow,,rainbow, +Ramp Networks,wradmin,trancell, +RapidStream,rsadmin,, +Raritan Inc.,admin,raritan,http://seclists.org/fulldisclosure/2015/Sep/33 +Raritan Inc.,epiq_api,raritan,http://seclists.org/fulldisclosure/2015/Sep/33 +Raritan Inc.,web_api,sl33p30F00dumass!,http://seclists.org/fulldisclosure/2015/Sep/33 +Raritan,admin,raritan, +RayTalk,root,root, +"Red Hat, Inc",,AMIAMI, +"Red Hat, Inc",,AMIDECOD, +"Red Hat, Inc",admin,admin,http://docs.jboss.org/jbossas/guides/installguide/r1/en/html_single/ +"Red Hat, Inc",piranha,piranha, +"Red Hat, Inc",piranha,q, +RedHat,piranha,piranha, +RedHat,piranha,q, +Redcreek Communications,,1234, +Redcreek Communications,,private, +Remedy,ARAdmin,AR#Admin#, +Remedy,Demo,, +Research,,Col2ogro2, +Research,,Col2ogro2, +Research Machines,manager,changeme, +Resumix,root,resumix, +Ricoh,,password, +Ricoh,,sysadm, +Ricoh,,password, +Ricoh,,sysadm, +Ricoh,admin,, +Ricoh,admin,no password, +Ricoh,admin,password, +Ricoh,sysadm,sysadm, +Ricoh,sysadmin,password, +Riverbed,Admin,password, +Rizen,Admin,123qwe,http://freshmeat.net/projects/webgui/ +RoamAbout,admin,password, +Rodopi,Rodopi,Rodopi, +RuggedCom,Admin,admin, +SAF Tehnika,administrator,d1scovery, +SAF Tehnika,integrator,p1nacate, +SAF Tehnika,monitor,monitor, +SAF Tehnika,operator,col1ma, +SAGEM,admin,epicrouter, +SAP,Administrator,manage, +SAP,DDIC,19920706, +SAP,Developer,isdev, +SAP,EARLYWATCH,SUPPORT, +SAP,Replicator,iscopy, +SAP,SAP*,06071992, +SAP,SAP*,7061992, +SAP,SAP*,PASS, +SAP,SAPCPIC,ADMIN, +SAP,SAPCPIC,admin, +SAP,SAPR3,SAP, +SAP,TMSADM,, +SAP,admin,axis2,https://spl0it.wordpress.com/2010/11/23/axis2-deployer-metasploit-modules-upload-exec-via-soap/ +SAP client EARLYWATCH,admin,Support, +SAP,ctb_admin,sap123, +SAP,itsadmin,init, +SAP,xmi_demo,sap123, +SMA America,,sma,http://files.sma.de/dl/4253/SWebBox-BUS-eng-111033.pdf +SMC,,0000, +SMC,,, +SMC,,smcadmin, +SMC,,smcadmin, +SMC,Admin,Barricade, +SMC,Administrator,smcadmin, +SMC,admin,, +SMC,admin,admin, +SMC,admin,barricade, +SMC,admin,smcadmin, +SMC,cusadmin,highspeed, +SMC,default,WLAN_AP, +SMC,mso,w0rkplac3rul3s, +SMC,none,none, +SMC,smc,smcadmin, +SOPHIA (Schweiz),admin,Protector, +SOPHIA (Schweiz),root,root, +SSA,SSA,SSA,rarely changed/used for +SUN,root,sun123, +SWEEX,sweex,mysweex, +Saba,admin,admin, +Safecom,admin,epicrouter, +Sagem,Menara,Menara, +Sagem,admin,admin, +Sagem,root,1234, +Samba,Any,Any, +Sambar Technologies,admin,, +Sambar Technologies,anonymous,, +Sambar Technologies,billy-bob,, +Sambar Technologies,ftp,, +Sambar Technologies,guest,guest, +Samsung,,s!a@m#n$p%c,http://l8security.com/post/36715280176/uv-281284-samsung-printer-snmp-backdoor +Samsung,,, +Samsung,admin,password,after reset +Samsung,public,public,def. WEP keys: 0123456789 +Samuel Abels,user,password, +Schneider Electric,,admin, +Schneider Electric,USER,USER, +Schneider Electric,ntpupdate,ntpupdate, +Scientific Atlanta,admin,w2402, +Seagate,admin,admin, +Seagull Scientific,ADMIN,admin, +Seagull Scientific,USER,USER, +Seclore,root,changeonfirstlogin, +Seclore,sa,changeonfirstlogin, +Secure Computing,admin,, +Securicor3NET,manager,friend, +Semaphore,DESQUETOP,, +Semaphore,DS,, +Semaphore,DSA,, +Semaphore,PHANTOM,, +Sempre,admin,admin, +Senao,admin,, +Sercom,admin,admin, +Server Technology,ADMN,admn,Telnet port 2001 +Server Technology,GEN1,gen1,Telnet port 2001 +Server Technology,GEN2,gen2,Telnet port 2001 +"Seyeon Technology Co., Ltd",root,root,http://www.flexwatch.com/pro_down/fw_all/M4028%20-%20FlexWATCH%20User%20Manual%20Part2.pdf +Sharp,,sysadm, +Sharp,Administrator,admin, +Sharp,admin,Sharp, +Sharp,admin,admin,Different to other Sharp units +Sharp,none,sysadm, +Shiva,admin,hello, +Shiva,guest,, +Shiva,hello,hello, +Shiva,root,, +ShoreTel,Admin,admin1, +Shoretel,admin,changeme, +Shuttle,,Spacve, +Shuttle,,Spacve, +Siemens,31994,31994, +Siemens,,0, +Siemens,,123456,http://wiki.unify.com/wiki/OpenStage_SIP_FAQ#What_are_the_default_passwords.3F +Siemens,,admin, +Siemens,,123456, +Siemens,,, +Siemens,,SKY_FOX, +Siemens,,admin, +Siemens,,gubed, +Siemens Corp,18140815,18140815, +Siemens Corp,31994,31994, +Siemens Corp,,SKY_FOX, +Siemens Corp,,uboot, +Siemens Corp,WinCCAdmin,2WSXcde,http://iadt.siemens.ru/forum/viewtopic.php?p=2974&sid=58cedcf3a0fc7a0b6c61c7bc46530928 +Siemens Corp,WinCCConnect,2WSXcder,http://iadt.siemens.ru/forum/viewtopic.php?p=2974&sid=58cedcf3a0fc7a0b6c61c7bc46530928 +Siemens Corp,admin,, +Siemens Corp,admin,pwp, +Siemens Corp,eng,engineer, +Siemens Corp,op,op, +Siemens Corp,op,operator, +Siemens Corp,poll,poll, +Siemens Corp,poll,tech, +Siemens Corp,su,super, +Siemens Corp,sysadmin,sysadmin, +Siemens Corp,system,field, +Siemens Corp,system,system, +Siemens Corp,tech,tech, +Siemens,admin,, +Siemens,admin,, +Siemens,admin,admin,Also has an account with: +Siemens,admin,hagpolm1, +Siemens,admin,pwp, +Siemens,basisk,basisk,http://m.itworld.com/data-centerservers/190269/power-plant-hack-anybody-could-use +Siemens,eng,engineer, +Siemens,op,op, +Siemens,op,operator, +Siemens,poll,tech, +Siemens,su,super, +Siemens,superuser,admin, +Siemens,sysadmin,sysadmin, +Siemens,tech,field, +Siemens,tech,tech, +Sierra Wireless,user,12345,http://mycusthelp.net/SIERRAWIRELESS/_cs/AnswerDetail.aspx?sSessionID=&aid=468 +Sigma,admin,admin, +Signamax,admin,admin, +Siips,Administrator,ganteng,Thx silex +Silex Technology,root,,http://www.silexeurope.com/en/home/support/faq/usb-device-server.html#faq25 +Silicon Graphics,4Dgifts,4Dgifts, +Silicon Graphics,4Dgifts,, +Silicon Graphics,6.x,, +Silicon Graphics,Ezsetup,, +Silicon Graphics,OutOfBox,, +Silicon Graphics,demos,, +Silicon Graphics,field,field, +Silicon Graphics,guest,, +Silicon Graphics,lp,, +Silicon Graphics,tour,tour, +Silicon Graphics,tutor,, +Silicon Graphics,tutor,tutor, +Silvercrest,admin,admin, +Site Interactive,admin,pass, +Sitecom,,damin, +Sitecom,,sitecom, +Sitecom,admin,admin, +Sitecom,admin,password, +Sitecore Corporation,Audrey,a,http://www.procheckup.com/media/176566/pentesting_sitecore.pdf +Sitecore Corporation,Bill,b,http://www.procheckup.com/media/176566/pentesting_sitecore.pdf +Sitecore Corporation,Denny,d,http://www.procheckup.com/media/176566/pentesting_sitecore.pdf +Sitecore Corporation,Lonnie,l,http://www.procheckup.com/media/176566/pentesting_sitecore.pdf +Sitecore Corporation,Minnie,m,http://www.procheckup.com/media/176566/pentesting_sitecore.pdf +Sitecore Corporation,admin,b,http://sdn.sitecore.net/upload/sdn5/tools/v53_to_v6/sitecore_cms_53_to_cms_6_database_conversion_tool-a4.pdf +SmartSwitch,admin,, +Snap Appliance,admin,admin, +SnapGear,root,default, +Snapgear,root,admin, +Snom,Administrator,0000, +Software AG,Administrator,manage, +Softwarehouse,manager,manager, +SolarWinds,LocalAdministrator,#l@$ak#.lk;0@P,http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2004-2532 +SolarWinds,whd,whd,http://www.solarwinds.com/documentation/WebHelpDesk/docs/WHDAdminGuide.pdf +Solution 6,aaa,often blank, +Solwise,root,same as webui pwd, +Sonic-X,root,admin, +SonicWALL,admin,password, +Sonicwall,admin,password, +Sony Ericsson,,0000, +Sony,admin,admin, +Sorenson,,admin, +Sourcefire,admin,password, +Sourcefire,root,password, +Sovereign Hill,Admin,shs, +Sparklan,admin,admin, +Spectra Logic,administrator,, +Spectra Logic,operator,, +SpeedStream,,admin, +SpeedStream,,adminttd, +SpeedStream,Administrator,admin, +SpeedStream,admin,admin, +SpeedXess,,speedxess, +Sphairon,admin,passwort, +Spider Systems,,hello, +Spike,enable,, +Splunk,admin,changeme, +Ssangyoung,,2501, +Stan Ozier,admin,,http://taskfreak.com/ +Stratitec,root,ahetzip8, +SuSE GmbH,root,root, +Sun Microsystems,root,changeme, +Sun,admin,admin,submit by Nabil Ouchn +Sun,root,changeme, +Sun,root,t00lk1t, +Sun,ssp,ssp, +"Super Micro Computer, Inc.",ADMIN,ADMIN,http://www.supermicro.com/manuals/other/Onboard_BMC_IPMI.pdf +SuperMicro,,ksdjfg934t, +SuperMicro,,ksdjfg934t, +Supercook,admin,AlpheusDigital1010, +Supercook,super,super, +Supermicro,ADMIN,admin, +Surecom,admin,admin, +Surecom,admin,surecom, +Sweex,,, +Sweex,,admin, +Sweex,,mysweex, +Sweex,admin,1234, +Sweex,admin,epicrouter, +Sweex,none,blank, +Sweex,rdc123,rdc123, +Sweex,sweex,mysweex, +Swissvoice,target,password, +Syabas Technology,ftpuser,1234, +Syabas Technology,nmt,1234, +Sybase,12.x,, +Sybase,DBA,SQL, +Sybase,jagadmin,, +Sybase,sa,, +Sybase,sa,sasasa, +Symantec,,symantec, +Symantec,,symantec, +Symantec,admin,, +Symantec,admin,symantec, +Symantec,root,brightmail, +Symbol,,Symbol, +Symbol,Symbol,Symbol, +"Symbol Technologies, Inc",admin,superuser, +Symbol,admin,symbol, +Symmetricom,guest,truetime, +Symmetricom,operator,mercury, +Synology Inc,admin,,http://forum.synology.com/wiki/index.php/Quick_Install_Guide:_Installing_the_Synology_Server +SysKonnect,default.password,, +SysMaster,admin,12345, +System/32,install,secret, +T-Com,,0, +T-Com,,123456, +T-Com,,0, +T-Comfort,Administrator,, +T-com,veda,12871, +TELTRONIC S.A.U.,admin,tetra, +TIBCO,admin,admin,https://docs.tibco.com/pub/managed-file-transfer-internet-server/7.2.0-may-2012/MFT%20IS%20v7.2.0%20Installation%20Guide.pdf +TIBCO,admin,changeit,https://docs.tibco.com/pub/slingshot/1.9.3/doc/pdf/TIB_slingshot_1.9.3_installation.pdf +TMC,,BIGO, +TMC,,BIGO, +TOTOLINK,onlime_r,12345,https://pierrekim.github.io/advisories/2015-totolink-0x03.txt +TOTOLINK,root,12345,https://pierrekim.github.io/advisories/2015-totolink-0x03.txt +TP Link,admin,admin, +TVT System,,enter, +TVT System,craft,, +TYPO3,,joh316, +TYPO3,admin,password, +Tandberg,,GWrv, +Tandberg,,TANDBERG, +Tandberg,,10023, +Tandberg,Admin,, +Tandberg,admin,, +Tandberg,admin,TANDBERG, +Tandberg,root,TANDBERG, +Tandem,super.super,, +Tandem,super.super,master, +Tasman,Tasman,Tasmannet, +Team Xodus,xbox,xbox, +Tegile,admin,tegile,https://40centcoffee.wordpress.com/2014/09/17/register-vcenter-server-on-tegile/ +Teklogix,Administrator,, +Telappliant,admin,1234, +Telco Systems,telco,telco, +Telebit,setup,setup, +Telebit,snmp,nopasswd, +Teledat,admin,1234, +Telelec,eagle,eagle, +Teletronics,admin,1234, +Telewell,admin,admin, +Telewell,admin,password, +Telindus,,, +Telindus,admin,admin, +Tellabs,root,admin_1,telnet on port 3083 +Tellabs,tellabs,tellabs#1, +Telus,(created),telus00, +Telus,(created),telus99, +Terayon,,, +Terayon,admin,password, +TexBox,,123, +TextPortal,god1,12345, +TextPortal,god2,12345, +Thecus Tech,admin,admin,http://www.google.com/url?sa=t&source=web&cd=77&ved=0CC4QFjAGOEY&url=http%3A%2F%2Fwww.thecus.com%2Fdownload%2Fother%2FN5200_FAQ_2006-11-22.pdf&ei=ayJcTKXXEMOC8gb1qImLAg&usg=AFQjCNE0RnP34sEcHyg382gRoxnnKcNRKw +Thomson,,admin, +Thomson,,admin,SSID : SpeedTouch180 +Thomson,admin,admin, +Thomson,admin,password, +Tiara Networks,,tiara, +Tiara,tiara,tiaranet,also known as Tasman Networks +Tim Schaab,theman,changeit,http://freshmeat.net/projects/madthought/ +TimeTools,admin,admin, +Tiny,,Tiny, +Tinys,,tiny, +Tinys,,Tiny, +TopLayer,siteadmin,toplayer, +Topcom,admin,admin, +Toshiba,,24Banc81, +Toshiba,,Toshiba, +Toshiba,,toshy99, +Toshiba,,24Banc81, +Toshiba,,, +Toshiba,,Toshiba, +Toshiba,,toshy99, +Toshiba,Admin,123456, +Toshiba,admin,123456, +Toshiba,super,superpass, +Trend Micro,admin,admin, +Trend Micro,admin,imsa7.0,http://www.trendmicro.com/ftp/documentation/guides/IMSA-QSG.pdf +Trend Micro,root,trendimsa1.0, +TrendMicro,admin,imss7.0, +TrendNET,admin,password, +Trintech,t3admin,Trintech, +Tripp Lite,root,TrippLite, +Triumph-Adler,admin,0, +Troy,admin,extendnet, +Tsunami,managers,managers, +Tumbleweed,Admin,SECRET123, +Typo3 Association,admin,password, +U.S. Robotics,,12345, +U.S. Robotics,,admin, +U.S. Robotics,Any,12345, +U.S. Robotics,admin,, +U.S. Robotics,admin,admin, +U.S. Robotics,none,amber, +U.S. Robotics,root,12345, +U.S. Robotics,root,admin, +U.S. Robotics,support,support, +UNEX,,password, +UNIX,adm,, +UNIX,adm,adm, +UNIX,admin,admin, +UNIX,administrator,, +UNIX,administrator,administrator, +UNIX,anon,anon, +UNIX,bbs,, +UNIX,bbs,bbs, +UNIX,bin,sys, +UNIX,checkfs,checkfs, +UNIX,checkfsys,checkfsys, +UNIX,checksys,checksys, +UNIX,daemon,, +UNIX,daemon,daemon, +UNIX,demo,, +UNIX,demo,demo, +UNIX,demos,, +UNIX,demos,demos, +UNIX,dni,, +UNIX,dni,dni, +UNIX,fal,, +UNIX,fal,fal, +UNIX,fax,, +UNIX,fax,fax, +UNIX,ftp,, +UNIX,ftp,ftp, +UNIX,games,, +UNIX,games,games, +UNIX,gopher,gopher, +UNIX,gropher,, +UNIX,guest,, +UNIX,guest,guest, +UNIX,guest,guestgue, +UNIX,halt,, +UNIX,halt,halt, +UNIX,informix,informix, +UNIX,install,install, +UNIX,lp,, +UNIX,lp,bin, +UNIX,lp,lineprin, +UNIX,lp,lp, +UNIX,lpadm,lpadm, +UNIX,lpadmin,lpadmin, +UNIX,lynx,, +UNIX,lynx,lynx, +UNIX,mail,, +UNIX,mail,mail, +UNIX,man,, +UNIX,man,man, +UNIX,me,, +UNIX,me,me, +UNIX,mountfs,mountfs, +UNIX,mountfsys,mountfsys, +UNIX,mountsys,mountsys, +UNIX,news,, +UNIX,news,news, +UNIX,nobody,, +UNIX,nobody,nobody, +UNIX,nuucp,, +UNIX,operator,, +UNIX,operator,operator, +UNIX,oracle,, +UNIX,postmaster,, +UNIX,postmaster,postmast, +UNIX,powerdown,powerdown, +UNIX,rje,rje, +UNIX,root,, +UNIX,root,hp, +UNIX,root,root, +UNIX,service,smile, +UNIX,setup,, +UNIX,setup,setup, +UNIX,shutdown,, +UNIX,shutdown,shutdown, +UNIX,sync,, +UNIX,sync,sync, +UNIX,sys,bin, +UNIX,sys,sys, +UNIX,sys,system, +UNIX,sysadm,admin, +UNIX,sysadm,sysadm, +UNIX,sysadmin,sysadmin, +UNIX,sysbin,sysbin, +UNIX,system_admin,, +UNIX,system_admin,system_admin, +UNIX,trouble,trouble, +UNIX,umountfs,umountfs, +UNIX,umountfsys,umountfsys, +UNIX,umountsys,umountsys, +UNIX,unix,unix, +UNIX,user,user, +UNIX,uucp,uucp, +UNIX,uucpadm,uucpadm, +UNIX,web,, +UNIX,web,web, +UNIX,webmaster,, +UNIX,webmaster,webmaster, +UNIX,www,, +UNIX,www,www, +USRobotics,admin,admin,http://www.usr.com/support/doc-popup-template.asp?url=faqs/networking/wireless-security-07/wireless-security-07.htm&loc=unst +UT Lexar,lexar,, +UTStarcom,dbase,dbase, +UTStarcom,field,field, +UTStarcom,guru,*3noguru, +UTStarcom,snmp,snmp, +Unex,,password, +Unidesk,Administrator,Unidesk1,http://www.unidesk.com/support/learn/2.7.0/administer/manage_appliances/admin_ma_config +Unify,,123456,http://wiki.unify.com/wiki/OpenStage_SIP_FAQ#What_are_the_default_passwords.3F +Union,root,root, +Unisys,ADMINISTRATOR,ADMINISTRATOR, +Unisys,HTTP,HTTP, +Unisys,NAU,NAU, +United Technologies Corporation,admin,1234,http://www.interlogix.com/_/assets/library/1072627A%20TruVision%20IP%20Camera%20Configuration%20Manual.pdf +Unknown,,password, +Unknown,operator,operator, +Unknown,overseer,overseer, +Unknown,test,test, +UsRobotics,Any,12345, +Utstar,admin,utstar, +VASCO,admin,, +VBrick Systems,admin,admin, +VPASP,admin,admin, +VPASP,vpasp,vpasp, +Various,root,admin,Alternative firmware +Veramark,admin,password, +Verifone,,166816, +Verilink,,, +Veritas,admin,password, +Verity,admin,admin, +Verizon,admin,password,http://www22.verizon.com/Support/Residential/Internet/fiosinternet/networking/setup/vz9100em/124043.htm +Vextrec Technology,,Vextrex, +Vextrec Technology,,Vextrex, +VieNuke,admin,admin, +Vina Technologies,,, +Virtual Programming,admin,admin, +Virtual Programming,vpasp,vpasp, +Visa VAP,root,QNX, +Visual Networks,admin,visual, +Vobis,,merlin, +Vobis,,merlin, +VoiceGenie Technologies,pw,pw, +VoiceObjects Germany,voadmin,manager,http://developers.voiceobjects.com/docs/en/VO9/024-voiceobjectspreferences.htm +Vonage,user,user, +VxWorks,admin,admin, +VxWorks,guest,guest, +WAAV,admin,waav, +WLAN_3D,Administrator,admin, +WWWBoard,WebAdmin,WebBoard, +Wanadoo,admin,admin, +"Wanco, Inc.",,ABCD,http://www.scribd.com/doc/68216572/Wanco-Users-Guide-Ntcip-Message-Sign-Software-Dec-2004 +"Wanco, Inc.",,Guest,http://www.scribd.com/doc/68216572/Wanco-Users-Guide-Ntcip-Message-Sign-Software-Dec-2004 +"Wanco, Inc.",,NTCIP,http://www.scribd.com/doc/68216572/Wanco-Users-Guide-Ntcip-Message-Sign-Software-Dec-2004 +"Wanco, Inc.",,Public,http://www.scribd.com/doc/68216572/Wanco-Users-Guide-Ntcip-Message-Sign-Software-Dec-2004 +Wang,CSG,SESAME, +WatchGuard,,wg, +WatchGuard,admin,admin,http://www.watchguard.com/help/docs/v70FireboxXEdge_QS.pdf +WatchGuard,admin,readwrite,http://www.watchguard.com/help/docs/wsm/xtm_11/en-us/content/en-us/basicadmin/factory_default_about_c.html +WatchGuard,status,readonly,http://www.watchguard.com/help/docs/wsm/xtm_11/en-us/content/en-us/basicadmin/factory_default_about_c.html +Watchguard,,wg, +Watchguard,admin,, +Watchguard,user,pass,works only from the inside LAN +Web Wiz,Administrator,letmein,http://www.webwizguide.info/web_wiz_forums/default.asp +Webmin,admin,hp.com, +Webramp,wradmin,trancell, +Weidm�eller,admin,detmond, +Westell,CSG,SESAME, +Westell,admin,, +Westell,admin,password, +Westell,admin,password1,Verizon cable router (Model +Westell,admin,sysAdmin, +Wim Bervoets,,Compleri, +Wim Bervoets,,Compleri, +"Wireless, Inc.",root,rootpass, +WorldClient,WebAdmin,Admin, +Wyse,,Fireport, +Wyse,,password,by satadru +Wyse,VNC,winterm, +Wyse,rapport,r@p8p0r+, +Wyse,root,, +Wyse,root,wyse, +X-Micro,1502,1502,From BUGTRAQ +X-Micro,super,super,From BUGTRAQ +XAMPP,newuser,wampp, +Xavi,,, +Xavi,admin,admin, +Xerox,11111,x-admin, +Xerox,,11111, +Xerox,,0, +Xerox,Administrator,Fiery.1, +Xerox,NSA,nsa,http://download.support.xerox.com/pub/docs/FlowPort2/userdocs/any-os/en/fp_dc_setup_guide.pdf +Xerox,admin,1111, +Xerox,admin,2222, +Xerox,admin,22222,works for access panel 2 +Xerox,admin,, +Xerox,admin,admin, +Xerox,admin,x-admin, +Xerox,savelogs,crash, +Xinit Systems Ltd.,openfiler,password, +Xylan,admin,switch, +Xylan,diag,switch, +Xyplex,,access, +Xyplex,,system, +Xyplex,,, +Xyplex,,access, +Xyplex,,system, +Xyplex,setpriv,system, +Yakumo,admin,admin, +Yokogawa,,727,For model codes ending in E +Yokogawa,admin,!admin,TFGW410 ISA100 gateway +Yuxin,User,1234, +Yuxin,User,19750407, +ZEOS,,zeosx, +ZEOS,,zeosx, +ZTE,ADSL,expert03,Default Password if user does +Zcom,root,admin, +Zcomax,admin,password, +Zebra Technologies,admin,1234, +Zebra,admin,1234, +Zenith,,3098z, +Zenith,,Zenith, +Zenith,,3098z, +Zenith,,Zenith, +Zeus,admin,, +Zoom,admin,zoomadsl, +ZyWALL Series,,admin, +Zyxel,1234,1234, +Zyxel,192.168.1.1 60020,@dsl_xilno, +Zyxel,,1234, +Zyxel,,1234, +Zyxel,,, +Zyxel,,admin, +Zyxel,Admin,atc456, +Zyxel,admin,0000,Password is 4 zeros. Gray router +Zyxel,admin,1234, +Zyxel,admin,,terra +Zyxel,admin,admin, +Zyxel,root,1234, +Zyxel,webadmin,1234, +accton t-online,,0, +acer,acer,acer, +actiontec,admin,admin, +adtran,,, +adtran,,Password,CTRL-L +adtran,,adtran, +allied,,, +ast,,, +backtrack,root,toor, +boson,,, +canyon,Administrator,admin, +crt,egcr,ergc, +cuproplus,,, +cyberguard,cgadmin,cgadmin, +darkman,ioFTPD,ioFTPD, +decnet,operator,admin, +digicom,Admin,, +drupal.org,admin,admin, +eMachines,emaq,4133, +eQ-3,root,MuZhlo9n%8!G, +eSeSIX Computer GmbH,root,jstwo, +eZ Systems,admin,publish,https://doc.ez.no/eZ-Publish/User-manual/4.x/The-administration-interface/The-login-page +enCAD,,, +ericsson,,help, +ericsson,,, +fon,admin,admin, +giga,Administrator,admin, +glFtpD,glftpd,glftpd, +glftpd,glftpd,glftpd, +greatspeed,netadmin,nimdaten,ETB Colombia +haier,ucenik23,ucenik, +iDirect,admin,P@55w0rd!,to enable ssh connections to the +iDirect,root,iDirect,first enable sshd telnet to router: +iNTERFACEWARE Inc.,admn,password,http://help.interfaceware.com/kb/767 +iPSTAR,admin,operator,For CSLoxInfo and iPSTAR Customers +iblitzz,admin,admin, +inchon,admin,admin, +infacta,Administrator,, +intel,,, +intel,admin,, +intel,khan,kahn, +intel,root,admin, +intex,,, +ion,,admin,vreau ceva +ion,Administrator,admin,vreau ceva +iso sistemi,,, +kaptest,admin,, +latis network,,, +longshine,admin,0, +m0n0wall,admin,mono, +maxdata,,, +medion,,medion, +metro,client,client, +microRouter,,letmein, +mklencke,root,blablabla, +motorola,,, +mro software,SYSADM,sysadm, +nCircle,root,ciwuxe, +olitec (Trendchip),admin,admin, +olitec,admin,adslolitec, +oodie.com,admin,admin, +ovislink,root,, +penril datability,,system, +pfSense,admin,pfsense, +phoenix,,admin, +phpLiteAdmin,,admin,https://bitbucket.org/phpliteadmin/public/wiki/Configuration +phpMyAdmin,root,, +phpTest,admin,1234, +phpTest,guest,guest, +planet,admin,admin, +ptcl,admin,admin, +rPath,admin,password, +redline,admin,admin, +reg.pnu.ac.ir,880175445,11223344, +remote-exploit,root,toor, +rm,administrator,password/changeme or secret, +schneider,USER,USER, +securstar,admin,rainbow, +seninleyimben,admin,admin, +sharp,,, +sitara,root,, +smartBridges,admin,public, +sprint,self,system, +stratacom,stratacom,stratauser, +stuccoboy,stuccoboy,100198, +technology,root,,for telnet / HTTP +telecom,operator,, +tert,james,james, +topsec,superman,talent, +vertex,root,vertex25, +warraCorp,pepino,pepino, +weblogic,system,weblogic, +winwork,operator,, +wline,admin,1234, +xavi,admin,admin, +xd,xd,xd, +xerox,,admin, +xerox,admin,1111, +zenitel,admin,alphaadmin,https://wiki.zenitel.com/wiki/Password_(IP_Stations) +zenitel,ADMIN,alphacom +zenitel,,1851 +zenitel,,1234 +zoom,admin,zoomadsl, diff --git a/subset/security/password/resources/raw/ssh.txt b/subset/security/password/resources/raw/ssh.txt new file mode 100644 index 0000000000..89513db0fd --- /dev/null +++ b/subset/security/password/resources/raw/ssh.txt @@ -0,0 +1,121 @@ +root:calvin +root:root +root:toor +administrator:password +NetLinx:password +administrator:Amx1234! +amx:password +amx:Amx1234! +admin:1988 +admin:admin +Administrator:Vision2 +cisco:cisco +c-comatic:xrtwk318 +root:qwasyx21 +admin:insecure +pi:raspberry +user:user +root:default +root:leostream +leo:leo +localadmin:localadmin +fwupgrade:fwupgrade +root:rootpasswd +admin:password +root:timeserver +admin:password +admin:motorola +cloudera:cloudera +root:p@ck3tf3nc3 +apc:apc +device:apc +eurek:eurek +netscreen:netscreen +admin:avocent +root:linux +sconsole:12345 +root:5up +cirros:cubswin:) +root:uClinux +root:alpine +root:dottie +root:arcsight +root:unitrends1 +vagrant:vagrant +root:vagrant +m202:m202 +demo:fai +root:fai +root:ceadmin +maint:password +root:palosanto +root:ubuntu1404 +root:cubox-i +debian:debian +root:debian +root:xoa +root:sipwise +debian:temppwd +root:sixaola +debian:sixaola +myshake:shakeme +stackato:stackato +root:screencast +root:stxadmin +root:nosoup4u +root:indigo +root:video +default:video +default: +ftp:video +nexthink:123456 +ubnt:ubnt +root:ubnt +sansforensics:forensics +elk_user:forensics +osboxes:osboxes.org +root:osboxes.org +sans:training +user:password +misp:Password1234 +hxeadm:HXEHana1 +acitoolkit:acitoolkit +osbash:osbash +enisa:enisa +geosolutions:Geos +pyimagesearch:deeplearning +root:NM1$88 +remnux:malware +hunter:hunter +plexuser:rasplex +root:openelec +root:rasplex +root:plex +root:openmediavault +root:ys123456 +root:libreelec +openhabian:openhabian +admin:ManagementConsole2015 +public:publicpass +admin:hipchat +nao:nao +support:symantec +root:max2play +admin:pfsense +root:root01 +root:nas4free +USERID:PASSW0RD +Administrator:p@ssw0rd +root:freenas +root:cxlinux +admin:symbol +admin:Symbol +admin:superuser +admin:admin123 +root:D13HH[ +root:blackarch +root:dasdec1 +root:7ujMko0admin +root:7ujMko0vizxv +root:Zte521 +root:zlxx. diff --git a/subset/security/password/resources/raw/telnet.txt b/subset/security/password/resources/raw/telnet.txt new file mode 100644 index 0000000000..6ffa3a3c9c --- /dev/null +++ b/subset/security/password/resources/raw/telnet.txt @@ -0,0 +1,146 @@ +root:calvin +administrator:password +NetLinx:password +administrator:Amx1234! +amx:password +amx:Amx1234! +admin:1988 +admin:admin +Administrator:Vision2 +cisco:cisco +root:fidel123 +user:user +root:default +localadmin:localadmin +Root:wago +Admin:wago +User:user +Guest:guest +root:rootpasswd +admin:password +adtec:none +root:timeserver +root:password +Admin:Su +root:admin +admin:motorola +Admin:5001 +User:1001 +GE:GE +Admin:Pass +device:apc +apc:apc +root:anni2013 +root:xc3511 +root:dreambox +root:vizxv +admin:1111111 +admin:smcadmin +admin:4321 +888888:888888 +666666:666666 +ubnt:ubnt +admin:22222 +adminttd:adminttd +root:!root +admin:epicrouter +tech:tech +manager:manager +smc:smcadmin +netscreen:netscreen +netopia:netopia +root:888888 +root:xmhdipc +root:juantech +root:123456 +root:54321 +support:support +root:root +root:12345 +root:pass +admin:admin1234 +root:1111 +admin:1111 +root:666666 +root:1234 +root:klv123 +Administrator:admin +service:service +guest:guest +guest:12345 +admin1:password +administrator:1234 +root:klv1234 +root:Zte521 +root:hi3518 +root:jvbzd +root:anko +root:zlxx. +root:7ujMko0vizxv +root:7ujMko0admin +root:system +root:ikwb +root:dreambox +root:user +root:realtek +root:00000000 +admin:1234 +admin:12345 +default:OxhlwSG8 +admin:tlJwpbo6 +default:S2fGqNFs +admin:meinsm +supervisor:supervisor +admin:123456 +root:zlxx +dm:telnet +webguest:1 +Liebert:Liebert +User:User +admin:avocent +root:linux +admin:system +user:public +admin:private +guest:guest +admin:admin +root:root +qbf77101:hexakisoctahedron +ftpuser:password +USER:USER +Basisk:Basisk +sconsole:12345 +root:5up +root:cat1029 +MayGion:maygion.com +admin:cat1029 +admin:ZmqVfoSIP +default:antslq +admin:microbusiness +admin:jvc +root:GM8182 +root:uClinux +Alphanetworks:wrgg19_c_dlwbr_dir300 +Alphanetworks:wrgn49_dlob_dir600b +Alphanetworks:wrgn23_dlwbr_dir600b +Alphanetworks:wrgn22_dlwbr_dir615 +Alphanetworks:wrgnd08_dlob_dir815 +Alphanetworks:wrgg15_di524 +Alphanetworks:wrgn39_dlob.hans_dir645 +Alphanetworks:wapnd03cm_dkbs_dap2555 +Alphanetworks:wapnd04cm_dkbs_dap3525 +Alphanetworks:wapnd15_dlob_dap1522b +Alphanetworks:wrgac01_dlob.hans_dir865 +Alphanetworks:wrgn23_dlwbr_dir300b +Alphanetworks:wrgn28_dlob_dir412 +Alphanetworks:wrgn39_dlob.hans_dir645_V1 +root:oelinux123 +mg3500:merlin +root:cxlinux +root:1001chin +root:china123 +admin:symbol +admin:Symbol +admin:superuser +admin:admin123 +root:20080826 diff --git a/subset/security/password/run_password_test_for_protocol b/subset/security/password/run_password_test_for_protocol new file mode 100755 index 0000000000..5b4d0c4099 --- /dev/null +++ b/subset/security/password/run_password_test_for_protocol @@ -0,0 +1,165 @@ +#!/bin/bash + +# A test which runs a dictionary brute force attack using ncrack/medusa, saving the result into a file afterwards. +# +# Supports http, https, telnet and ssh protocols on their specified ports. +# +# Assumes the following files are in the dictionary directory: +# - dictionary.txt (File with format ":username:password") +# - usernames.txt (File with a list of usernames, one on each line) +# - passwords.txt (File with a list of passwords, one on each line) +# +# Usage: ./run_password_test_for_protocol $TARGET_IP, $PROTOCOL, $PORT, $DICTIONARY_DIR, $RESULTS_DIR + +TARGET_IP=$1 +PROTOCOL=$2 +PORT=$3 +DICTIONARY_DIR=$4 +RESULT_DIR=$5 + +DICTIONARY="$DICTIONARY_DIR/dictionary.txt" +USERNAMES="$DICTIONARY_DIR/usernames.txt" +PASSWORDS="$DICTIONARY_DIR/passwords.txt" +RESULT_FILE="${RESULT_DIR}/security_password_${PROTOCOL}.result" + +# Runs the nmap on a target host and port. Returns the output of the command. +# $1 Target IP +# $2 Target Port +function run_nmap_and_get_command() { + NMAP_OUTPUT=$(nmap -p $2 $1) + echo "$NMAP_OUTPUT" +} + +# Return true if grep finds a match for the nmap port open message which looks like: e.g. "80/tcp open http" +# $1 Nmap command output +# $2 Target protocol +# $3 Target port +function is_specified_port_open() { + echo "$1" | grep -q "$3.*open.*$2" +} + +# Returns true if grep can find the host down message from the Nmap output +# $1 Nmap command output +function is_host_down() { + echo "$1" | grep -q "Host seems down" +} + +# Checks if http or https has authentication. +# $1 Target protocol (HTTP or HTTPS) +# $2 Target IP +# $3 Target port +function does_http_or_https_have_authentication() { + if [[ $1 == "http" || $1 == "https" ]]; then + echo "$(curl -k -s -I $1://$2:$3)" | grep -q "401 Unauthorized" + fi +} + +# Runs the brute force using ncrack/medusa, and returns the output. Redirect stderr into stdout also. +# $1 Target IP +# $2 Target protocol +# $3 Target port +# $4 Colon separated brute force dictionary for medusa +# $5 Username list for ncrack +# $6 Password list for ncrack +function run_brute_force_and_get_command_new() { + if [ "$2" == "http" ]; then + ncrack_output=$(ncrack --pairwise -v -U $5 -P $6 http://$1:$3 2>&1) + echo "$ncrack_output" + elif [ "$2" == "https" ]; then + ncrack_output=$(ncrack --pairwise -v -U $5 -P $6 https://$1:$3 2>&1) + echo "$ncrack_output" + elif [ "$2" == "ssh" ]; then + medusa_output=$(medusa -C $4 -h $1 -M ssh -n $3 -v 4 2>&1) + echo "$medusa_output" + elif [ "$2" == "telnet" ]; then + ncrack_output=$(ncrack --pairwise -v -U $5 -P $6 -T2 telnet://$1:$3 2>&1) + echo "$ncrack_output" + fi +} + +# Returns true if grep can find the success message in the brute force output. +# $1 ncrack/medusa output +function brute_force_successful() { + echo "$1" | grep -qE "Discovered credentials|\[SUCCESS\]" +} + +# True if "timed-out/prematurely-closed" is present and their values are not zero. +# $1 ncrack/medusa output +function ncrack_brute_force_skip() { + echo "$1" | grep -oE "timed-out: [0-9]+ \| prematurely-closed: [0-9]+" | grep -qvE "timed-out: 0 \| prematurely-closed: 0" +} + +# True if ALERT or NOTICE are in the output. +# $1 ncrack/medusa output +function medusa_brute_force_skip() { + echo "$1" | grep -qE "NOTICE:|ALERT:|ERROR:|FATAL:" +} + +# Writes the test result into a file. +# $1 Target protocol +# $2 Target port +# $3 Result code +function write_to_result_file() { + mkdir -p $RESULT_DIR + + if [ -f $RESULT_FILE ]; then + rm $RESULT_FILE + fi + touch $RESULT_FILE + + if [ "$3" == "pass" ]; then + echo "RESULT pass security.passwords.$1 Was not able to brute force using dictionary." > $RESULT_FILE + elif [ "$3" == "fail" ]; then + echo "RESULT fail security.passwords.$1 Was able to brute force using dictionary." > $RESULT_FILE + elif [ "$3" == "skip_no_host" ]; then + echo "RESULT skip security.passwords.$1 Unable to connect to host." > $RESULT_FILE + elif [ "$3" == "skip_no_port" ]; then + echo "RESULT skip security.passwords.$1 Port $2 not open on target device." > $RESULT_FILE + elif [ "$3" == "skip_ncrack_error" ]; then + echo "RESULT skip security.passwords.$1 Skipping due to brute force issue with ncrack. Please see log." > $RESULT_FILE + elif [ "$3" == "skip_medusa_error" ]; then + echo "RESULT skip security.passwords.$1 Skipping due to brute force issue with medusa. Please see log." > $RESULT_FILE + elif [ "$3" == "skip_http_error" ]; then + echo "RESULT skip security.passwords.$1 Skipping due to http(s) server not having authentication method." > $RESULT_FILE + fi +} + +# Main function: + +NMAP_OUTPUT="$(run_nmap_and_get_command $TARGET_IP $PORT)" +echo "$NMAP_OUTPUT" + +if ! is_host_down "$NMAP_OUTPUT"; then + + if is_specified_port_open "$NMAP_OUTPUT" $PROTOCOL $PORT; then + BRUTE_FORCE_OUTPUT="$(run_brute_force_and_get_command_new $TARGET_IP $PROTOCOL $PORT $DICTIONARY $USERNAMES $PASSWORDS)" + echo "$BRUTE_FORCE_OUTPUT" + + if ! does_http_or_https_have_authentication $PROTOCOL $TARGET_IP $PORT; then + echo "Will not start brute force as http(s) server has no authentication." + RESULT="skip_http_error" + elif ncrack_brute_force_skip "$BRUTE_FORCE_OUTPUT"; then + echo "Could not brute force due to an issue with ncrack at runtime. Please check log." + RESULT="skip_ncrack_error" + elif medusa_brute_force_skip "$BRUTE_FORCE_OUTPUT"; then + echo "Could not brute force due to an issue with medusa at runtime. Please check log." + RESULT="skip_medusa_error" + elif brute_force_successful "$BRUTE_FORCE_OUTPUT"; then + echo "Was able to brute force using dictionary." + RESULT="fail" + else + echo "Could not brute force using dictionary." + RESULT="pass" + fi + + else + echo "Could not connect to specified port on host." + RESULT="skip_no_port" + fi + +else + echo "Could not connect to host." + RESULT="skip_no_host" +fi + +write_to_result_file $PROTOCOL $PORT $RESULT diff --git a/subset/security/password/test_password b/subset/security/password/test_password new file mode 100755 index 0000000000..9fe18b5bda --- /dev/null +++ b/subset/security/password/test_password @@ -0,0 +1,144 @@ +#!/bin/bash -e + +# Entry point for the security.admin.password test - Runs the test on all protocols in parallel +# and writes the output into reports file to be used by DAQ. + +source reporting.sh + +# Hard coded paths. +DAQ_REPORT="/tmp/report.txt" +RESULTS_DIR="/tmp/results" +LOG_DIR="/tmp/logs" +MODULE_CONFIG="/tmp/module_config.json" + +# Hard coded files and names. +HTTP_LOG="$LOG_DIR/security_password_http.log" +HTTPS_LOG="$LOG_DIR/security_password_https.log" +SSH_LOG="$LOG_DIR/security_password_ssh.log" +TELNET_LOG="$LOG_DIR/security_password_telnet.log" + +HTTP_RESULT="$RESULTS_DIR/security_password_http.result" +HTTPS_RESULT="$RESULTS_DIR/security_password_https.result" +SSH_RESULT="$RESULTS_DIR/security_password_ssh.result" +TELNET_RESULT="$RESULTS_DIR/security_password_telnet.result" + +# Hard coded json keys for jq +DICTIONARY_DIR_KEY=".modules.password.dictionary_dir" +HTTP_PORT_KEY=".modules.password.http_port" +HTTPS_PORT_KEY=".modules.password.https_port" +SSH_PORT_KEY=".modules.password.ssh_port" +TELNET_PORT_KEY=".modules.password.telnet_port" +USER_SPECIFIED_USERNAME_KEY=".device_info.default_username" +USER_SPECIFIED_PASSWORD_KEY=".device_info.default_password" + +# Default configuration values. +DICTIONARY_DIR="resources/default" +DEFAULT_PLACE_HOLDER="*** (optional) ***" +USER_SPECIFIED_DICTIONARY_DIR="resources/user_specified" +USER_SPECIFIED_DICTIONARY_FILE="resources/user_specified/dictionary.txt" +USER_SPECIFIED_USERNAME_FILE="resources/user_specified/usernames.txt" +USER_SPECIFIED_PASSWORD_FILE="resources/user_specified/passwords.txt" +HTTP_PORT=80 +HTTPS_PORT=443 +SSH_PORT=22 +TELNET_PORT=23 + +# Retrieves the value specified in specified key from the module config. +# $1 Module config file path +# $2 jq JSON key string +function get_module_config_value_from_key() { + cat $1 | jq $2 | tr -d '"' +} + +# Retrieve a modified version of the test description for a protocol. +# $1 Protocol name +function get_test_description() { + echo "Verify all device manufacturer default passwords are changed for protocol: $1, and new passwords are set." +} + +# Retrieve a modified version of the test name for a protocol. +# $1 Protocol name +function get_test_name() { + echo "security.admin.password.$1" +} + +# Removes whitespace and colon from user specified string to avoid format issues with the brute force tools. +# $1 String to clean +function clean_credentials() { + echo "$(echo $1 | sed -E 's/\s//' | tr -d ':')" +} + +# Create a new dictionary directory in resources for the user specified credentials. +# $1 Username +# $2 Password +function create_dictionary_for_user_specified_credentials() { + mkdir -p $USER_SPECIFIED_DICTIONARY_DIR + + username="$(clean_credentials "$1")" + password="$(clean_credentials "$2")" + + echo ":$username:$password" > $USER_SPECIFIED_DICTIONARY_FILE + echo "$username" > $USER_SPECIFIED_USERNAME_FILE + echo "$password" > $USER_SPECIFIED_PASSWORD_FILE +} + +# Main function + +echo "Password test starting on docker container: $TARGET_IP..." + +echo "Checking module_config.json for any default configurations to overwrite..." +NEW_DICTIONARY_DIR="$(get_module_config_value_from_key $MODULE_CONFIG $DICTIONARY_DIR_KEY)" +NEW_HTTP_PORT="$(get_module_config_value_from_key $MODULE_CONFIG $HTTP_PORT_KEY)" +NEW_HTTPS_PORT="$(get_module_config_value_from_key $MODULE_CONFIG $HTTPS_PORT_KEY)" +NEW_SSH_PORT="$(get_module_config_value_from_key $MODULE_CONFIG $SSH_PORT_KEY)" +NEW_TELNET_PORT="$(get_module_config_value_from_key $MODULE_CONFIG $TELNET_PORT_KEY)" +USER_SPECIFIED_USERNAME="$(get_module_config_value_from_key $MODULE_CONFIG $USER_SPECIFIED_USERNAME_KEY)" +USER_SPECIFIED_PASSWORD="$(get_module_config_value_from_key $MODULE_CONFIG $USER_SPECIFIED_PASSWORD_KEY)" + +echo "Overwriting default configurations with user specified values... (If any). User specified credentials takes precedence over user specified dictionaries." + +if [[ $USER_SPECIFIED_USERNAME != "null" && \ + $USER_SPECIFIED_USERNAME != $DEFAULT_PLACE_HOLDER && \ + $USER_SPECIFIED_PASSWORD != "null" && \ + $USER_SPECIFIED_PASSWORD != $DEFAULT_PLACE_HOLDER ]]; then + + create_dictionary_for_user_specified_credentials "$USER_SPECIFIED_USERNAME" "$USER_SPECIFIED_PASSWORD" + DICTIONARY_DIR=$USER_SPECIFIED_DICTIONARY_DIR + echo "User specified username/password pair found! -> $(clean_credentials "$USER_SPECIFIED_USERNAME") $(clean_credentials "$USER_SPECIFIED_PASSWORD")" + echo "Proceeding to use these credentials! Dictionary directory is now -> $DICTIONARY_DIR" + +elif [[ $NEW_DICTIONARY_DIR != "null" ]]; then + + DICTIONARY_DIR=$NEW_DICTIONARY_DIR + echo "User specified username/password pair not found!" + echo "Proceeding to use default/user specifed dictionary_dir -> $DICTIONARY_DIR" + +fi + +[ $NEW_HTTP_PORT != "null" ] && HTTP_PORT=$NEW_HTTP_PORT +[ $NEW_HTTPS_PORT != "null" ] && HTTPS_PORT=$NEW_HTTPS_PORT +[ $NEW_SSH_PORT != "null" ] && SSH_PORT=$NEW_SSH_PORT +[ $NEW_TELNET_PORT != "null" ] && TELNET_PORT=$NEW_TELNET_PORT + +echo "Print out configurations set..." +echo "DICTIONARY_DIR: $DICTIONARY_DIR" +echo "HTTP_PORT: $HTTP_PORT" +echo "HTTPS_PORT: $HTTPS_PORT" +echo "SSH_PORT: $SSH_PORT" +echo "TELNET_PORT: $TELNET_PORT" + +echo "Running password test for each protocol..." +mkdir -p $LOG_DIR +./run_password_test_for_protocol $TARGET_IP http $HTTP_PORT $DICTIONARY_DIR $RESULTS_DIR &> $HTTP_LOG & +./run_password_test_for_protocol $TARGET_IP https $HTTPS_PORT $DICTIONARY_DIR $RESULTS_DIR &> $HTTPS_LOG & +./run_password_test_for_protocol $TARGET_IP ssh $SSH_PORT $DICTIONARY_DIR $RESULTS_DIR &> $SSH_LOG & +./run_password_test_for_protocol $TARGET_IP telnet $TELNET_PORT $DICTIONARY_DIR $RESULTS_DIR &> $TELNET_LOG & +wait + +echo "Writing test results and logs to DAQ report..." +write_out_result $DAQ_REPORT "$(get_test_name "http")" "$(get_test_description "http")" "$(cat $HTTP_LOG)" "$(cat $HTTP_RESULT)" +write_out_result $DAQ_REPORT "$(get_test_name "https")" "$(get_test_description "https")" "$(cat $HTTPS_LOG)" "$(cat $HTTPS_RESULT)" +write_out_result $DAQ_REPORT "$(get_test_name "ssh")" "$(get_test_description "ssh")" "$(cat $SSH_LOG)" "$(cat $SSH_RESULT)" +write_out_result $DAQ_REPORT "$(get_test_name "telnet")" "$(get_test_description "telnet")" "$(cat $TELNET_LOG)" "$(cat $TELNET_RESULT)" + +echo "Done!" diff --git a/subset/security/readme.md b/subset/security/readme.md index 2143155dc0..fc4653e5e6 100644 --- a/subset/security/readme.md +++ b/subset/security/readme.md @@ -3,9 +3,9 @@ ## test_tls The TLS test attempts to verify various versions of TLS support. Separate connections will be attempted with different SSL context with the associated TLS support, 1.0, 1.2 and 1.3. - ### Testing procedure - After establishing connections to devices, the test will proceed to validate the available certificates with the following criteria: - 1. The certificat is in the x509 format +### Testing procedure +After establishing connections to devices, the test will proceed to validate the available certificates with the following criteria: + 1. The certificate is in the x509 format 2. The public key length is at least 2048. Currently handles both RSA and DSA public key formats. 3. The certificate is not expired and active for the current date. The cipher suite used is also checked but does not currently affect the outcome of the results. Currently the expected cipher suites are ECDH and ECSA. If these are not present, a warning message will be logged in the activate.log of the switch node. @@ -43,6 +43,49 @@ The functional test code is included in the `tlstest/src/main/java` folder. - pass -> If the device responds to a connection with TLS 1.3 support and provides a valid certificate. - fail -> If the device responds to a connection with TLS 1.3 support and provides an invalid certificate. - skip -> If no connection to the device can be established. + +## test_password +The password test runs a dictionary brute force on protocols HTTP, HTTPS, SSH and Telnet to check if the device has changed login credentials from defaults to a more secure combination. + +### Testing Procedure: +1. Use Nmap tool to check if needed port is open, and whether the target host is down. +2. If target port is open, and target host is not down, then start the brute force. +3. Run the brute force command for ncrack/medusa as appropriate, and collect the output. +4. Depending on the messages read on the command output, the test will return a specific result case. + - PASS: Test was able to run the brute force but not find the username/password(s). + - FAIL: Test was able to run the brute force and find the username/password(s). + - SKIP: Test was not able to run a brute force successfully due to a variety of issues. In this case: + - Target host is down. + - Target protocol is down. + - HTTP server does not have authentication. + - Brute force tool related issues such as disconnect, missing parameters etc. + +### Available Configurations: +The password test can be run from DAQ without specifying any further configurations, but it is possible to tweak these to your needs by modifying the password field in your local copy of module_config.json to have the following, for example: + +Note the examples shown are the available configurations and the default values used by the password test. +``` +# local/module_config.json +{ + "device_info": { + # Both must be specified for these to be used. Should not be the default value/null/empty string. Spaces and colons are automatically removed. + "default_username": "*** (optional) ***", # If specified, only uses this to brute force. + "default_password": "*** (optional) ***" # If specified, only uses this to brute force. + }, + "modules": { + "password": { + "enabled": true, + "dictionary_dir": "resources/default", # Default are resources/default (full), or resources/faux (debug), user can also create their own custom version. + "http_port": 80, # Custom port to use when brute forcing HTTP + "https_port": 443, # Custom port to use when brute forcing HTTPS + "ssh_port": 22, # Custom port to use when brute forcing SSH + "telnet_port": 23 # Custom port to use when brute forcing Telnet + } + } +} +``` + +Ideally one should specify only either "default_username" and "default_password" OR "dictionary_dir" - If both are specified, the default username/passwords will take precedence and dictionary_dir will be used as a backup if they are considered invalid. ## test_ssh The SSH test will check that if a device has an SSH server, this only supports SSHv2 @@ -50,4 +93,4 @@ The SSH test will check that if a device has an SSH server, this only supports S ### Conditions for seucrity.ssh.version - pass -> If the device runs an SSH server which only supports SSHv2 - fail -> If the device runs an SSH server which supports SSHv1 -- skip -> If the device does not run an SSH server \ No newline at end of file +- skip -> If the device does not run an SSH server diff --git a/subset/security/security_passwords/.classpath b/subset/security/security_passwords/.classpath deleted file mode 100755 index 540156aa7c..0000000000 --- a/subset/security/security_passwords/.classpath +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/subset/security/security_passwords/.gitignore b/subset/security/security_passwords/.gitignore deleted file mode 100755 index 10e776c937..0000000000 --- a/subset/security/security_passwords/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -.idea/* -.settings/* -/bin/* -/reports/* diff --git a/subset/security/security_passwords/build.gradle b/subset/security/security_passwords/build.gradle deleted file mode 100755 index d82a3535c6..0000000000 --- a/subset/security/security_passwords/build.gradle +++ /dev/null @@ -1,38 +0,0 @@ -buildscript { - repositories { - jcenter() - } - dependencies { - classpath "com.github.jengelman.gradle.plugins:shadow:6.0.0" - } -} -apply plugin: 'com.github.johnrengelman.shadow' -apply plugin: 'idea' -apply plugin: 'java-library' -apply plugin: 'java' -apply plugin: 'application' - -group 'com.redstone' -version '1.0-SNAPSHOT' - -sourceCompatibility = 1.8 - -apply plugin: 'application' -mainClassName = 'TestPassword' - -repositories { - mavenCentral() -} - -dependencies { - compile group: 'com.google.code.gson', name: 'gson', version: '2.7' - testCompile group: 'junit', name: 'junit', version: '4.13' -} - -jar { - manifest { - attributes( - 'TestPassword-Class': 'TestPassword' - ) - } -} \ No newline at end of file diff --git a/subset/security/security_passwords/gradle/wrapper/gradle-wrapper.jar b/subset/security/security_passwords/gradle/wrapper/gradle-wrapper.jar deleted file mode 100755 index 94336fcae912db8a11d55634156fa011f4686124..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56177 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 i;x|p)^~-yfPOPa3(|vBayXKz \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - -exec "$JAVACMD" "$@" diff --git a/subset/security/security_passwords/gradlew.bat b/subset/security/security_passwords/gradlew.bat deleted file mode 100755 index e95643d6a2..0000000000 --- a/subset/security/security_passwords/gradlew.bat +++ /dev/null @@ -1,84 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/subset/security/security_passwords/settings.gradle b/subset/security/security_passwords/settings.gradle deleted file mode 100755 index d454a26df8..0000000000 --- a/subset/security/security_passwords/settings.gradle +++ /dev/null @@ -1,2 +0,0 @@ -rootProject.name = 'security_passwords' - diff --git a/subset/security/security_passwords/src/main/java/BruteForceTester.java b/subset/security/security_passwords/src/main/java/BruteForceTester.java deleted file mode 100755 index 5ded435909..0000000000 --- a/subset/security/security_passwords/src/main/java/BruteForceTester.java +++ /dev/null @@ -1,71 +0,0 @@ -/* Runs pentesting tools ncrack and hydra to crack the passwords of the device. */ - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; - -public class BruteForceTester { - - private static final String SSH = "ssh"; - private static final String TELNET = "telnet"; - private static final String HYDRA_SUCCESS_MESSAGE = "successfully completed"; - private static final String NCRACK_SUCCESS_MESSAGE = "Discovered credentials"; - private static final String NCRACK_COMMAND = "ncrack %s %s://%s:%s -U %s -P %s"; - private static final String HYDRA_COMMAND = "hydra -L %s -P %s %s %s -s %s"; - - private static String getCommand( - final String domain, - final String protocol, - final String host, - final String port, - final String usersFile, - final String passwordsFile - ) { - if (protocol.equals(SSH) || protocol.equals(TELNET)) { - return String.format(HYDRA_COMMAND, usersFile, passwordsFile, host, protocol, port); - } - else { - return String.format(NCRACK_COMMAND, domain, protocol, host, port, usersFile, passwordsFile); - } - } - - private static BufferedReader runCommandGetReader(final String commandToRun) throws IOException { - final Process process = Runtime.getRuntime().exec(commandToRun); - return new BufferedReader(new InputStreamReader(process.getInputStream())); - } - - private static boolean lineIndicatesCredentialsFound(final String protocol, final String line) { - if (protocol.equals(SSH) || protocol.equals(TELNET)) { - return line.contains(HYDRA_SUCCESS_MESSAGE); - } - else { - return line.contains(NCRACK_SUCCESS_MESSAGE); - } - } - - public static String start( - final String domain, - final String protocol, - final String host, - final String port, - final String usernamesFile, - final String passwordsFile - ) throws IOException { - final String command = getCommand(domain, protocol, host, port, usernamesFile, passwordsFile); - final BufferedReader outputReader = runCommandGetReader(command); - - ReportHandler.printMessage(command); - String result = ReportHandler.PASS; - String currentLine; - - while ((currentLine = outputReader.readLine()) != null) { - ReportHandler.printMessage(currentLine); - if (lineIndicatesCredentialsFound(protocol, currentLine)) { - result = ReportHandler.FAIL; - } - } - - return result; - } - -} diff --git a/subset/security/security_passwords/src/main/java/DefaultCredentials.java b/subset/security/security_passwords/src/main/java/DefaultCredentials.java deleted file mode 100755 index 05fc3dafd1..0000000000 --- a/subset/security/security_passwords/src/main/java/DefaultCredentials.java +++ /dev/null @@ -1,88 +0,0 @@ -/* Reads from defaultPasswords.json to retrieve default username and password data for a mac. */ - -import com.google.gson.Gson; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; - -import java.io.*; - -public class DefaultCredentials { - - public static final String DEFAULT_PASSWORDS_FILE = "/tmp/%s_passwords.txt"; - public static final String DEFAULT_USERNAMES_FILE = "/tmp/%s_usernames.txt"; - - private static final String DEFAULT_PASSWORDS = "/defaultPasswords.json"; - private static final String JSON_USERNAME_ELEMENT = "Usernames"; - private static final String JSON_PASSWORD_ELEMENT = "Passwords"; - private static final String WRITE_ELEMENT_LINE = "%s\n"; - private static final String MAC_SEPARATOR = ":"; - private static final String EMPTY = ""; - private static final int MAC_ADDRESS_START = 0; - private static final int MAC_ADDRESS_END = 6; - - private static String getFormattedMacAddress(final String macAddress) { - final String simpleMacAddress = macAddress.replace(MAC_SEPARATOR, EMPTY); - final String macAddressOUI = simpleMacAddress.substring(MAC_ADDRESS_START, MAC_ADDRESS_END); - return macAddressOUI.toUpperCase(); - } - - private static JsonObject getJsonFileContentsAsObject() { - final Gson gsonController = new Gson(); - final InputStream jsonStream = DefaultCredentials.class.getResourceAsStream(DEFAULT_PASSWORDS); - return gsonController.fromJson(new InputStreamReader(jsonStream), JsonObject.class); - } - - private static void writeArrayToCredentialFiles( - final JsonArray array, - final String filePath - ) throws IOException { - final File file = new File(filePath); - final BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file)); - - for (final JsonElement element : array) { - bufferedWriter.write(String.format(WRITE_ELEMENT_LINE, element.getAsString())); - } - - bufferedWriter.close(); - } - - public static String getUsernameFilePath(final String protocol) { - return String.format(DEFAULT_USERNAMES_FILE, protocol); - } - - public static String getPasswordFilePath(final String protocol) { - return String.format(DEFAULT_PASSWORDS_FILE, protocol); - } - - public static void writeUsernamesToFile( - final String macAddress, - final String protocol - ) throws IOException { - final String formattedMac = getFormattedMacAddress(macAddress); - final String formattedUsernameFile = getUsernameFilePath(protocol); - final JsonObject fileContents = getJsonFileContentsAsObject(); - final JsonObject credentialsForMac = fileContents.getAsJsonObject(formattedMac); - final JsonArray usernameJsonArray = credentialsForMac.getAsJsonArray(JSON_USERNAME_ELEMENT); - - writeArrayToCredentialFiles(usernameJsonArray, formattedUsernameFile); - } - - public static void writePasswordsToFile( - final String macAddress, - final String protocol - ) throws IOException { - final String formattedMac = getFormattedMacAddress(macAddress); - final String formattedPasswordFile = getPasswordFilePath(protocol); - final JsonObject fileContents = getJsonFileContentsAsObject(); - final JsonObject credentialsForMac = fileContents.getAsJsonObject(formattedMac); - final JsonArray passwordJsonArray = credentialsForMac.getAsJsonArray(JSON_PASSWORD_ELEMENT); - - writeArrayToCredentialFiles(passwordJsonArray, formattedPasswordFile); - } - - public static boolean credentialsFileHasMacAddress(final String macAddress) { - final String formattedMac = getFormattedMacAddress(macAddress); - return getJsonFileContentsAsObject().has(formattedMac); - } -} diff --git a/subset/security/security_passwords/src/main/java/PortChecker.java b/subset/security/security_passwords/src/main/java/PortChecker.java deleted file mode 100755 index ae95a0d4fe..0000000000 --- a/subset/security/security_passwords/src/main/java/PortChecker.java +++ /dev/null @@ -1,62 +0,0 @@ -/* Runs nmap to check if HTTP, HTTPS, Telnet and SSH ports are open. */ - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; - -public class PortChecker { - - private static final String NMAP_COMMAND_STRING = "nmap %s"; - private static final String PORT_CHECK_STRING = "%s/tcp"; - private static final String OPEN_CHECK_STRING = "open"; - - private static String getCommand(final String host) { - return String.format(NMAP_COMMAND_STRING, host); - } - - private static BufferedReader runCommandGetReader(final String command) throws IOException { - final Process process = Runtime.getRuntime().exec(command); - return new BufferedReader(new InputStreamReader(process.getInputStream())); - } - - private static boolean checkIfDesiredPortOpen( - final BufferedReader bufferedReader, - final String port, - final String protocol - ) throws IOException { - boolean isPortOpen = false; - - String currentLine; - while ((currentLine = bufferedReader.readLine()) != null) { - ReportHandler.printMessage(currentLine); - if (currentLine.contains(String.format(PORT_CHECK_STRING, port)) && - currentLine.contains(protocol) && - currentLine.contains(OPEN_CHECK_STRING)) { - isPortOpen = true; - } - } - - return isPortOpen; - } - - private static void closeBufferedReader(final BufferedReader bufferedReader) throws IOException { - bufferedReader.close(); - } - - public static boolean checkDesiredPortOpen( - final String hostAddress, - final String port, - final String protocol - ) throws IOException { - final String command = getCommand(hostAddress); - final BufferedReader bufferedReader = runCommandGetReader(command); - final boolean desiredPortIsOpen = checkIfDesiredPortOpen(bufferedReader, port, protocol); - - ReportHandler.printMessage(command); - - closeBufferedReader(bufferedReader); - - return desiredPortIsOpen; - } - -} diff --git a/subset/security/security_passwords/src/main/java/ReportHandler.java b/subset/security/security_passwords/src/main/java/ReportHandler.java deleted file mode 100755 index 9d47a0dbf9..0000000000 --- a/subset/security/security_passwords/src/main/java/ReportHandler.java +++ /dev/null @@ -1,108 +0,0 @@ -/* ReportHandler writes test results for the current protocol, and also does console output. */ - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; - -public class ReportHandler { - - public final static String PASS = "pass"; - public final static String FAIL = "fail"; - public final static String SKIP_NOPORT = "skip_noport"; - public final static String SKIP_NOMAC = "skip_mac"; - public final static String SKIP_NOMAC_NOPORT = "skip_nomac_noport"; - - private final static String PRINT_MESSAGE_STRING = "%s"; - private final static String UNABLE_TO_WRITE_REPORT_MESSAGE = "Unable to write message."; - private final static String REPORT_FILE_PATH = "reports/%s_result.txt"; - - private final static String SKIP_MESSAGE_NOMAC = - "RESULT skip security.passwords.%s Could not lookup password info for mac-key: %s\n"; - private final static String SKIP_MESSAGE_NOPORT = - "RESULT skip security.passwords.%s Port %s is not open on target device.\n"; - private final static String SKIP_MESSAGE_NOMAC_NOPORT = - "RESULT skip security.passwords.%s Port %s is not open, %s not in password file.\n"; - private final static String FAIL_MESSAGE = - "RESULT fail security.passwords.%s Default passwords have not been changed.\n"; - private final static String PASS_MESSAGE = - "RESULT pass security.passwords.%s Default passwords have been changed.\n"; - private final static String NO_MESSAGE = - "RESULT Unable to get message."; - - private static String getReportFilePath(final String protocol) { - return String.format(REPORT_FILE_PATH, protocol); - } - - private static File setupReportFile(final String reportFilePath) { - final File reportFile = new File(reportFilePath); - reportFile.getParentFile().mkdirs(); - return reportFile; - } - - private static BufferedWriter getFileWriter(final File reportFile) throws IOException { - return new BufferedWriter(new FileWriter(reportFile)); - } - - private static String getReportMessage( - final String result, - final String protocol, - final String port, - final String mac - ) { - String reportMessage; - - switch (result) { - case PASS: { - reportMessage = String.format(PASS_MESSAGE, protocol); - break; - } - case FAIL: { - reportMessage = String.format(FAIL_MESSAGE, protocol); - break; - } - case SKIP_NOMAC: { - reportMessage = String.format(SKIP_MESSAGE_NOMAC, protocol, mac); - break; - } - case SKIP_NOPORT: { - reportMessage = String.format(SKIP_MESSAGE_NOPORT, protocol, port); - break; - } - case SKIP_NOMAC_NOPORT: { - reportMessage = String.format(SKIP_MESSAGE_NOMAC_NOPORT, protocol, port, mac); - break; - } - default: { - reportMessage = NO_MESSAGE; - } - } - - return reportMessage; - } - - public static void writeReportMessage( - final String result, - final String protocol, - final String port, - final String mac - ) { - final String reportFilePath = getReportFilePath(protocol); - final File reportFile = setupReportFile(reportFilePath); - final String reportMessage = getReportMessage(result, protocol, port, mac); - - try { - final BufferedWriter reportWriter = getFileWriter(reportFile); - reportWriter.write(reportMessage); - reportWriter.close(); - } catch (final IOException e) { - printMessage(UNABLE_TO_WRITE_REPORT_MESSAGE); - printMessage(e.getMessage()); - } - } - - public static void printMessage(final String message) { - System.out.println(String.format(PRINT_MESSAGE_STRING, message)); - } - -} diff --git a/subset/security/security_passwords/src/main/java/TestPassword.java b/subset/security/security_passwords/src/main/java/TestPassword.java deleted file mode 100755 index 332d1394b6..0000000000 --- a/subset/security/security_passwords/src/main/java/TestPassword.java +++ /dev/null @@ -1,76 +0,0 @@ -/* Main entry point for test. */ - -import java.io.IOException; - -public class TestPassword { - - private static final int REQUIRED_PARAMETERS = 5; - private static final String NMAP_MESSAGE = "Starting NMAP check..."; - private static final String BRUTE_FORCE_MESSAGE = "Starting brute force..."; - private static final String FINISH_MESSAGE = "Done."; - - private static final String HELP_STRING = - "Usage: target_ip protocol(http(s)/ssh/telnet) target_port target_mac domain"; - private static final String STARTUP_MESSAGE = - "[STARTING WITH IP:%s, MAC:%s, PROTOCOL: %s]"; - - private String host; - private String protocol; - private String port; - private String mac; - private String domain; - - public TestPassword(final String[] args) { - if (args.length != REQUIRED_PARAMETERS) { - throw new IllegalArgumentException(HELP_STRING); - } - else { - host = args[0]; - protocol = args[1]; - port = args[2]; - mac = args[3]; - domain = args[4]; - } - } - - public void runPasswordTest() { - try { - ReportHandler.printMessage(String.format(STARTUP_MESSAGE, host, mac, protocol)); - ReportHandler.printMessage(NMAP_MESSAGE); - final boolean desiredPortOpen = PortChecker.checkDesiredPortOpen(host, port, protocol); - final boolean macIsInCredentialsFile = DefaultCredentials.credentialsFileHasMacAddress(mac); - - if (macIsInCredentialsFile && desiredPortOpen) { - DefaultCredentials.writeUsernamesToFile(mac, protocol); - DefaultCredentials.writePasswordsToFile(mac, protocol); - - final String users = DefaultCredentials.getUsernameFilePath(protocol); - final String passwords = DefaultCredentials.getPasswordFilePath(protocol); - - ReportHandler.printMessage(BRUTE_FORCE_MESSAGE); - final String result = BruteForceTester.start(domain, protocol, host, port, users, passwords); - ReportHandler.writeReportMessage(result, protocol, port, mac); - } - else if (!macIsInCredentialsFile && !desiredPortOpen) { - ReportHandler.writeReportMessage(ReportHandler.SKIP_NOMAC_NOPORT, protocol, port, mac); - } - else if (!macIsInCredentialsFile) { - ReportHandler.writeReportMessage(ReportHandler.SKIP_NOMAC, protocol, port, mac); - } - else { - ReportHandler.writeReportMessage(ReportHandler.SKIP_NOPORT, protocol, port, mac); - } - - ReportHandler.printMessage(FINISH_MESSAGE); - } - catch (final IOException e) { - ReportHandler.printMessage(e.getMessage()); - } - } - - public static void main(final String[] args) { - final TestPassword testPassword = new TestPassword(args); - testPassword.runPasswordTest(); - } - -} diff --git a/subset/security/security_passwords/src/main/resources/defaultPasswords.json b/subset/security/security_passwords/src/main/resources/defaultPasswords.json deleted file mode 100755 index 957ca01e69..0000000000 --- a/subset/security/security_passwords/src/main/resources/defaultPasswords.json +++ /dev/null @@ -1,131 +0,0 @@ -{ - "Axis2":{ - "Usernames":["admin","root" - ], - "Passwords":["axis2","1988" - ] - }, - "DB2":{ - "Usernames":["admin","dasusr1","db2admin","db2fenc1","db2inst1"], - "Passwords":[ - "admin","dasusr1","db2admin","db2fenc1","db2inst1","db2pass","db2password","db2pw" - ] - }, - "FTP":{ - "Usernames":["admin","anonymous","ftp","ftp_admi","ftp_inst","ftp_nmc","ftp_oper", - "ftpuser","login","rapport","root","user","xbox" - ], - "Passwords":["1234","access","chrome@example.com","Exabyte","ftp","help1954","IEUser@", - "kilo1987","mozilla@example.com","pass","password","pbxk1064","r@p8p0r","tuxalize","xbox" - ] - }, - "HTTP":{ - "Usernames":["admin","apc","axis2","cisco","connect","manager","newuser","pass","private", - "root","security","sitecom","sys","system","tomcat","user","wampp","xampp","xampp-dav-unsecure" - ], - "Passwords":["1234","admin","apc","cisco","connect","default","letmein","manager","none","pass", - "password","ppmax2011","root","sanfran","security","sitecom","sys","system","tomcat", - "turnkey","user","wampp","xampp" - ] - }, - "MSSQL":{ - "Usernames":["Administrator","ARAdmin","entldbdbo","entldbreader","mon_user","probe", - "repl_publisher","repl_subscriber","sa","WinCCConnect" - ], - "Passwords":["2WSXcder","AR#Admin#","blank","dbopswd","pass","pass1","password", - "rdrpswd" - ] - }, - "MySQL":{ - "Usernames":["admin","mysql","root" - ], - "Passwords":["blank","pass","pass1","password","vicidia1now" - ] - }, - "PostgreSQL":{ - "Usernames":["admin","postgres","scott","tom"], - "Passwords":["admin","password","postgres","tiger" - ] - }, - "SMB":{ - "Usernames":["backuphelpdesk"], - "Passwords":["backuphpinvent" - ] - }, - "SNMP":{ - "Usernames":["" - ], - "Passwords":["0392a0","1234","2read","4changes","access.adm","Admin","admin", - "agent","agent_steal","all","allprivate","allpublic","ANYCOM","apc","bintec", - "blue","c","C0de","cable-d","canon_admin","cc","CISCO","cisco" - ] - }, - "SSH":{ - "Usernames":["admin","administrator","root" - ], - "Passwords":["1234","admin","changeme123","password","password1","password123","password123!", - "toor" - ] - }, - "Telnet":{ - "Usernames":["admin","administrator","Alphanetworks","cisco","helpdesk","pix","root" - ], - "Passwords":["100","admin","changeme123","cisco","password","password1","password123", - "password123!","sanfran","root","wrgg15_di524" - ] - }, - "VNC":{ - "Usernames":["admin","administrator","root" - ], - "Passwords":["100","1234","admin","changeme123","password","password1","password123","password123!","toor"] - }, - "WinRM":{ - "Usernames":["admin","administrator","root" - ], - "Passwords":["1234","admin","changeme123","password","password1","password123", - "password123!","toor" - ] - }, - "EC1127":{ - "Usernames":["cpt-dev","admin","administrator","root" - ], - "Passwords":["hellocpt","admin","root","Admin" - ] - }, - "38D135":{ - "Usernames":["cpt-dev","admin","administrator","root" - ], - "Passwords":["hellocpt,,admin,root,Admin" - ] - }, - "001AEB":{ - "Usernames":["admin","root","manager" - ], - "Passwords":["root","fire","friend" - ] - }, - "40BD32":{ - "Usernames":["root","Admin","admin" - ], - "Passwords":["root","Adminreds#1","admin123","admin" - ] - }, - "0242AC":{ - "Usernames":["root","admin" - ], - "Passwords":["root","admin","default" - ] - }, - "3C5AB4":{ - "Usernames":["root","admin" - ], - "Passwords":["root","admin","default" - ] - }, - "9A0257":{ - "Usernames":["root","admin" - ], - "Passwords":["root","admin","default" - ] - } -} diff --git a/subset/security/test_password b/subset/security/test_password deleted file mode 100755 index 3a5a3c6c0d..0000000000 --- a/subset/security/test_password +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/bash -e - -source reporting.sh - -REPORT=reports/report.txt -TEST_DESC="Verify all default passwords are updated and new Google provided passwords are set." - -make_log_files() { - touch /tmp/http_report.txt - touch /tmp/https_report.txt - touch /tmp/telnet_report.txt - touch /tmp/ssh_report.txt -} - -run_password_test_all_protocols () { - java -jar security_passwords/build/libs/security_passwords-1.0-SNAPSHOT-all.jar $1 http 80 $2 nginx-site > /tmp/http_report.txt & - - java -jar security_passwords/build/libs/security_passwords-1.0-SNAPSHOT-all.jar $1 https 443 $2 nginx-site > /tmp/https_report.txt & - - java -jar security_passwords/build/libs/security_passwords-1.0-SNAPSHOT-all.jar $1 telnet 23 $2 nginx-site > /tmp/telnet_report.txt & - - java -jar security_passwords/build/libs/security_passwords-1.0-SNAPSHOT-all.jar $1 ssh 22 $2 nginx-site > /tmp/ssh_report.txt & - - wait -} - -if [ -n "$TARGET_IP" ]; then - run_password_test_all_protocols $TARGET_IP $TARGET_MAC - - make_log_files - - write_out_result $REPORT \ - "security.passwords.http" \ - "$TEST_DESC" \ - "$(cat /tmp/http_report.txt)" \ - "$(cat reports/http_result.txt)" - - write_out_result $REPORT \ - "security.passwords.https" \ - "$TEST_DESC" \ - "$(cat /tmp/https_report.txt)" \ - "$(cat reports/https_result.txt)" - - write_out_result $REPORT \ - "security.passwords.telnet" \ - "$TEST_DESC" \ - "$(cat /tmp/telnet_report.txt)" \ - "$(cat reports/telnet_result.txt)" - - write_out_result $REPORT \ - "security.passwords.ssh" \ - "$TEST_DESC" \ - "$(cat /tmp/ssh_report.txt)" \ - "$(cat reports/ssh_result.txt)" - - cp -r $REPORT /tmp/report.txt -else - echo Problem with target IP, password test cannot continue. | tee /tmp/report.txt -fi diff --git a/testing/test_aux.out b/testing/test_aux.out index 47d2650fd4..40961f6726 100644 --- a/testing/test_aux.out +++ b/testing/test_aux.out @@ -39,18 +39,18 @@ RESULT pass security.tls.v1_2 Certificate active for current date and public key RESULT pass security.tls.v1_2.x509 Certificate active for current date and public key length > 2048. RESULT pass security.tls.v1_3 Certificate active for current date and public key length > 2048. RESULT pass security.tls.v1_3.x509 Certificate active for current date and public key length > 2048. -RESULT skip security.passwords.http Port 80 is not open on target device. -RESULT skip security.passwords.https Port 443 is not open on target device. -RESULT skip security.passwords.telnet Port 23 is not open on target device. -RESULT skip security.passwords.ssh Port 22 is not open on target device. -RESULT fail security.passwords.http Default passwords have not been changed. -RESULT fail security.passwords.https Default passwords have not been changed. -RESULT fail security.passwords.telnet Default passwords have not been changed. -RESULT fail security.passwords.ssh Default passwords have not been changed. -RESULT pass security.passwords.http Default passwords have been changed. -RESULT pass security.passwords.https Default passwords have been changed. -RESULT pass security.passwords.telnet Default passwords have been changed. -RESULT pass security.passwords.ssh Default passwords have been changed. +RESULT skip security.passwords.http Port 80 not open on target device. +RESULT skip security.passwords.https Port 443 not open on target device. +RESULT skip security.passwords.ssh Port 22 not open on target device. +RESULT skip security.passwords.telnet Port 23 not open on target device. +RESULT fail security.passwords.http Was able to brute force using dictionary. +RESULT fail security.passwords.https Was able to brute force using dictionary. +RESULT fail security.passwords.ssh Was able to brute force using dictionary. +RESULT fail security.passwords.telnet Was able to brute force using dictionary. +RESULT pass security.passwords.http Was not able to brute force using dictionary. +RESULT pass security.passwords.https Was not able to brute force using dictionary. +RESULT pass security.passwords.ssh Was not able to brute force using dictionary. +RESULT pass security.passwords.telnet Was not able to brute force using dictionary. RESULT skip security.firmware Could not retrieve a firmware version with nmap. Check bacnet port. RESULT pass security.firmware version found: ?\xFF\xFF\x19,>u\x08\x00no RESULT pass connection.min_send ARP packets received. Data packets were sent at a frequency of less than 5 minutes @@ -126,6 +126,7 @@ port-01 module_config modules "enabled": true }, "password": { + "dictionary_dir": "resources/faux", "enabled": true }, "ssh": { @@ -183,6 +184,7 @@ port-02 module_config modules "enabled": false }, "password": { + "dictionary_dir": "resources/faux", "enabled": true }, "ssh": { diff --git a/testing/test_aux.sh b/testing/test_aux.sh index bee1720acc..cb710cf070 100755 --- a/testing/test_aux.sh +++ b/testing/test_aux.sh @@ -49,9 +49,14 @@ cp -r resources/test_site/device_types/rocket local/site/device_types/ mkdir -p local/site/device_types/rocket/aux/ cp subset/bacnet/bacnetTests/src/main/resources/pics.csv local/site/device_types/rocket/aux/ cp -r resources/test_site/mac_addrs local/site/ + +# Add extra configs to a copy of the baseline module config for the password test to select which dictionaries to use. +cat resources/setups/baseline/module_config.json | jq '.modules.password += {"dictionary_dir":"resources/faux"}' > local/module_config.json + cat < local/system.yaml --- include: config/system/all.conf +base_conf: local/module_config.json finish_hook: bin/dump_network test_config: resources/runtime_configs/long_wait site_path: inst/test_site From a9aaf3adedacf9d4768caa43352ca5194626d873 Mon Sep 17 00:00:00 2001 From: Trevor Date: Wed, 5 Aug 2020 17:25:14 -0700 Subject: [PATCH 073/212] Minor cleanup (#577) --- .github/workflows/tests.yml | 8 ++++++-- README.md | 2 +- daq/dhcp_monitor.py | 6 ++++-- .../scripts}/autorestart_dnsmasq | 0 .../scripts}/change_dhcp_range | 0 .../scripts}/change_dhcp_response_time | 0 .../scripts}/change_lease_time | 0 .../{networking_scripts => network/scripts}/new_ip | 0 .../scripts}/start_networking | 0 docker/modules/Dockerfile.networking | 2 +- 10 files changed, 12 insertions(+), 6 deletions(-) rename docker/include/{networking_scripts => network/scripts}/autorestart_dnsmasq (100%) rename docker/include/{networking_scripts => network/scripts}/change_dhcp_range (100%) rename docker/include/{networking_scripts => network/scripts}/change_dhcp_response_time (100%) rename docker/include/{networking_scripts => network/scripts}/change_lease_time (100%) rename docker/include/{networking_scripts => network/scripts}/new_ip (100%) rename docker/include/{networking_scripts => network/scripts}/start_networking (100%) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 457c8c6be0..e8711c3272 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,9 +1,13 @@ # This workflow will install Python dependencies, run tests and lint with a single version of Python # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions -name: DAQ push/pull tests +name: DAQ test suite -on: [push, pull_request] +on: + push: + pull_request: + schedule: + - cron: '0 */2 * * *' jobs: integration_tests: diff --git a/README.md b/README.md index d680013e8e..753bf6bdc4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![CI Tests](https://github.com/faucetsdn/daq/workflows/DAQ%20push%2Fpull%20tests/badge.svg?branch=master) +![CI Tests](https://github.com/faucetsdn/daq/workflows/DAQ%20test%20suite/badge.svg?branch=master) # DAQ: Device Automated Qualification for IoT Devices. diff --git a/daq/dhcp_monitor.py b/daq/dhcp_monitor.py index 6a5beceae0..4c312cb89b 100644 --- a/daq/dhcp_monitor.py +++ b/daq/dhcp_monitor.py @@ -57,10 +57,12 @@ def _dhcp_line(self): if match: if match.group(2): self.target_ip = match.group(2) - if match.group(4) == "ACK": - self._dhcp_success() if match.group(6): self.target_mac = match.group(6) + if match.group(4) == "ACK": + if not self.target_ip or not self.target_mac: + LOGGER.warning('dhcp ACK incomplete: %s', dhcp_line) + self._dhcp_success() def cleanup(self): """Cleanup any ongoing dhcp activity""" diff --git a/docker/include/networking_scripts/autorestart_dnsmasq b/docker/include/network/scripts/autorestart_dnsmasq similarity index 100% rename from docker/include/networking_scripts/autorestart_dnsmasq rename to docker/include/network/scripts/autorestart_dnsmasq diff --git a/docker/include/networking_scripts/change_dhcp_range b/docker/include/network/scripts/change_dhcp_range similarity index 100% rename from docker/include/networking_scripts/change_dhcp_range rename to docker/include/network/scripts/change_dhcp_range diff --git a/docker/include/networking_scripts/change_dhcp_response_time b/docker/include/network/scripts/change_dhcp_response_time similarity index 100% rename from docker/include/networking_scripts/change_dhcp_response_time rename to docker/include/network/scripts/change_dhcp_response_time diff --git a/docker/include/networking_scripts/change_lease_time b/docker/include/network/scripts/change_lease_time similarity index 100% rename from docker/include/networking_scripts/change_lease_time rename to docker/include/network/scripts/change_lease_time diff --git a/docker/include/networking_scripts/new_ip b/docker/include/network/scripts/new_ip similarity index 100% rename from docker/include/networking_scripts/new_ip rename to docker/include/network/scripts/new_ip diff --git a/docker/include/networking_scripts/start_networking b/docker/include/network/scripts/start_networking similarity index 100% rename from docker/include/networking_scripts/start_networking rename to docker/include/network/scripts/start_networking diff --git a/docker/modules/Dockerfile.networking b/docker/modules/Dockerfile.networking index db07f600fd..86ae77238b 100644 --- a/docker/modules/Dockerfile.networking +++ b/docker/modules/Dockerfile.networking @@ -7,7 +7,7 @@ FROM daqf/aardvark:latest RUN $AG update && $AG install dnsmasq ethtool iptables netcat ntp python curl -COPY docker/include/networking_scripts/* ./ +COPY docker/include/network/scripts/* ./ RUN mkdir -p /etc COPY docker/include/etc/ntp.conf /etc From 64179be14d165304f292c2f589a9b8347169bb8d Mon Sep 17 00:00:00 2001 From: Trevor Date: Wed, 5 Aug 2020 17:25:56 -0700 Subject: [PATCH 074/212] Add perodic tests (#575) From 8b811f26a390bd2b4570e19aef1552900b988020 Mon Sep 17 00:00:00 2001 From: henry54809 Date: Thu, 6 Aug 2020 07:07:07 -0700 Subject: [PATCH 075/212] Adding default dns for static ip faux devices (#576) --- docker/include/bin/start_faux | 6 +++++- docker/include/network/scripts/start_networking | 1 + testing/test_many.out | 1 + testing/test_many.sh | 8 +++++--- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/docker/include/bin/start_faux b/docker/include/bin/start_faux index d6afdf8972..5c310b8cac 100755 --- a/docker/include/bin/start_faux +++ b/docker/include/bin/start_faux @@ -87,7 +87,11 @@ if [ -n "${options[xdhcp]}" ]; then fi ip addr show $intf_name - (while true; do ping -c 1 10.20.0.1; sleep 5; done) & + if [ -n "${options[opendns]}" ]; then + dhcp_dns=8.8.8.8 + echo nameserver ${dhcp_dns#DNS=} > /etc/resolv.conf + route add default gw 10.20.255.254 $intf_name # fixed IP in start_networking + fi else echo Running dhclient... dhclient -v diff --git a/docker/include/network/scripts/start_networking b/docker/include/network/scripts/start_networking index a55e24b052..331585c2fe 100755 --- a/docker/include/network/scripts/start_networking +++ b/docker/include/network/scripts/start_networking @@ -40,6 +40,7 @@ if ! ip addr show dev $LOCAL_IF | fgrep -q 'inet '; then ip addr add 10.20.$subnet.1/16 dev $LOCAL_IF fi +ip addr add 10.20.255.254/16 dev $LOCAL_IF #For static ip devices' default gateway IP echo dhcp-host=*,ignore >> /etc/dnsmasq.conf # Start the NTP server diff --git a/testing/test_many.out b/testing/test_many.out index 29cc0367df..7e9ff645b2 100644 --- a/testing/test_many.out +++ b/testing/test_many.out @@ -4,6 +4,7 @@ DAQ stress test Enough results: 1 Enough DHCP timeouts: 1 Enough static ips: 1 +Found NTP and DNS traffic for static ip devices: 1 1 Enough ipaddr tests: 1 Enough alternate subnet ips: 1 Enough ipaddr timeouts: 1 diff --git a/testing/test_many.sh b/testing/test_many.sh index b3029e333e..bea177acb5 100755 --- a/testing/test_many.sh +++ b/testing/test_many.sh @@ -27,8 +27,8 @@ for iface in $(seq 1 $NUM_DEVICES); do intf_mac="9a02571e8f0$iface" mkdir -p local/site/mac_addrs/$intf_mac if [[ $iface -le $NUM_NO_DHCP_DEVICES ]]; then - ip="10.20.0.$((iface+5))" - xdhcp="xdhcp=$ip" + ip="10.20.255.$((iface+5))" + xdhcp="xdhcp=$ip opendns ntp_fail" if [[ $iface -gt $NUM_TIMEOUT_DEVICES ]]; then #Install site specific configs for xdhcp ips cat < local/site/mac_addrs/$intf_mac/module_config.json @@ -91,7 +91,8 @@ alternate_subnet_ip=$(fgrep "ip notification 192.168" inst/run-port-*/nodes/ipad cat inst/run-port-*/scans/ip_triggers.txt static_ips=$(fgrep nope inst/run-port-*/scans/ip_triggers.txt | wc -l) - +ntp_traffic=$(fgrep "RESULT fail base.startup.ntp" inst/run-port-*/nodes/ping*/tmp/result_lines.txt | wc -l) +dns_traffic=$(fgrep "RESULT fail base.startup.dns" inst/run-port-*/nodes/ping*/tmp/result_lines.txt | wc -l) more inst/run-port-*/nodes/ping*/activate.log | cat more inst/run-port-*/nodes/ipaddr*/activate.log | cat @@ -104,6 +105,7 @@ echo Enough results: $((results >= 5*RUN_LIMIT/10)) | tee -a $TEST_RESULTS # $timeouts should strictly equal $NUM_TIMEOUT_DEVICES when dhcp step is fixed. echo Enough DHCP timeouts: $((timeouts >= NUM_TIMEOUT_DEVICES)) | tee -a $TEST_RESULTS echo Enough static ips: $((static_ips >= (NUM_NO_DHCP_DEVICES - NUM_TIMEOUT_DEVICES))) | tee -a $TEST_RESULTS +echo Found NTP and DNS traffic for static ip devices: $((ntp_traffic > 0)) $((dns_traffic > 0)) | tee -a $TEST_RESULTS echo Enough ipaddr tests: $((ip_notifications >= (NUM_IPADDR_TEST_DEVICES - NUM_IPADDR_TEST_TIMEOUT_DEVICES) * 2 )) | tee -a $TEST_RESULTS echo Enough alternate subnet ips: $((alternate_subnet_ip >= (NUM_IPADDR_TEST_DEVICES - NUM_IPADDR_TEST_TIMEOUT_DEVICES) )) | tee -a $TEST_RESULTS From 75a3d0a8dda8f998f1a7329dd63bd4d8080ab0a6 Mon Sep 17 00:00:00 2001 From: Trevor Pering Date: Fri, 7 Aug 2020 12:15:32 -0700 Subject: [PATCH 076/212] Remove deprecated UDMI docs --- docs/pubsub.md | 127 ------------------------------------------------- 1 file changed, 127 deletions(-) delete mode 100644 docs/pubsub.md diff --git a/docs/pubsub.md b/docs/pubsub.md deleted file mode 100644 index 8333453577..0000000000 --- a/docs/pubsub.md +++ /dev/null @@ -1,127 +0,0 @@ -# PubSub Setup Documentation - -This document describes the [GCP PubSub in Cloud IoT](https://cloud.google.com/iot-core/) mechanism for -processing device messages. There are three major message types employed by the system: -* Config: Messages sent from cloud-to-device that _configure_ the device (idempotent). -* State: Messags sent from device-to-cloud reporting _state_ form the device (idempotent). -* Events: Messages sent from device-to-cloud for streaming _events_ (non-idempotent). - -The exact semantic meaning of theses is determined by the underlying schema used. E.g., the -[UDMI Schema](../schemas/udmi/README.md) specifies one set of conventions for managing IoT devices. - -## Validator Configuration - -Streaming validation validates a stream of messages pulled from a GCP PubSub topic. There are three values -in the `local/system.conf` file required to make it work: -* `gcp_cred`: The service account credentials, as per the general [DAQ Firebase setup](firebase.md). -* `gcp_topic`: The _PubSub_ (not MQTT) topic name. -* `schema_path`: Indicates which schema to validate against. - -You will need to add full Project Editor permissions for the service account. -E.g., to validate messages against the UDMI schema on the `projects/gcp-account/topics/target` topic, -there should be something like: - -
        -~/daq$ fgrep gcp_ local/system.conf
        -gcp_cred=local/gcp-account-de56aa4b1e47.json
        -gcp_topic=target
        -schema_path=schemas/udmi
        -
        - -## Message/Schema Mapping - -When using the -[GCP Cloud IoT Core MQTT Bridge](https://cloud.google.com/iot/docs/how-tos/mqtt-bridge#publishing_telemetry_events) -there are multiple ways the subschema used during validation is chosen. -* An `events` message is validated against the sub-schema indicated by the MQTT topic `subFolder`. E.g., the MQTT -topic `/devices/{device-id}/events/pointset` will be validated against `.../pointset.json`. -* [Device state messages](https://cloud.google.com/iot/docs/how-tos/config/getting-state#reporting_device_state) -are validated against the `.../state.json` schema. -* All messages have their attributes validated against the `.../attributes.json` schema. These attributes are -automatically defined by the MQTT Client ID and Topic, so are not explicitly included in any message payload. -* The `config` messages are artifically injected into the `target` PubSub topic by the configuration script -(below) so they can be easily checked by the validation engine. - -The simple `state_shunt` function in `daq/functions/state_shunt` will automatically send state update messages -to the `target` PubSub topic. Install this function to enable validation of state updates. (Also make sure to -configure the Cloud IoT project to send state message to the state topic!) - -## Pubber Reference Client - -The [Pubber Reference Client](pubber.md) is a complete reference client that can be used to test out streaming -validation in absence of a real known-working device. The basic setup and documentation listed on the Pubber -page are assumed to be "running in the background" for the other examples in this section. - -## Streaming Validation - -Running the `bin/validate` script will will parse the configuration file and automatically start -verifying PubSub messages against the indicated schema. Using the `pubber` client, the output -should look something like: -
        -~/daq$ bin/validate
        -Loading config from local/system.conf
        -
        -BUILD SUCCESSFUL in 3s
        -2 actionable tasks: 2 executed
        -Using credentials from /home/user/daq/local/gcp-account-de56aa4b1e47.json
        -Executing validator /home/user/daq/schemas/udmi pubsub:target...
        -Running schema . in /home/user/daq/schemas/udmi
        -Ignoring subfolders []
        -Results will be uploaded to https://console.cloud.google.com/firestore/data/registries/?project=gcp-account
        -Also found in such directories as /home/user/daq/schemas/udmi/out
        -Connecting to pubsub topic target
        -Entering pubsub message loop on projects/gcp-account/subscriptions/daq-validator
        -Success validating out/state_GAT-001.json
        -Success validating out/state_GAT-001.json
        -Success validating out/state_GAT-001.json
        -Success validating out/pointset_GAT-001.json
        -Success validating out/state_GAT-001.json
        -Success validating out/pointset_GAT-001.json
        -Success validating out/pointset_GAT-001.json
        -…
        -
        - -If there are no _state_ validation messages (but there are _pointset_ ones), then the `state_shunt` -function described above is not installed properly. - -## Injecting Configuration - -The `validator/bin/config` script can be used to inject a configuration message to a device: -
        -~/daq$ validator/bin/config GAT-001 schemas/udmi/config.tests/gateway.json
        -Configuring gcp-account:us-central1:sensor_hub:GAT-001 from schemas/udmi/config.tests/gateway.json
        -messageIds:
        -- '301010492284043'
        -Updated configuration for device [GAT-001].
        -
        - -If using the `pubber` client, there should be a corresponding flury of activity: -
        -…
        -[pool-1-thread-1] INFO daq.pubber.Pubber - Sending test message for sensor_hub/GAT-001
        -[pool-1-thread-1] INFO daq.pubber.Pubber - Sending test message for sensor_hub/GAT-001
        -[MQTT Call: projects/gcp-account/locations/us-central1/registries/sensor_hub/devices/GAT-001] INFO daq.pubber.Pubber - Received new config daq.udmi.Message$Config@3666b3a5
        -[MQTT Call: projects/gcp-account/locations/us-central1/registries/sensor_hub/devices/GAT-001] INFO daq.pubber.Pubber - Starting executor with send message delay 2000
        -[MQTT Call: projects/gcp-account/locations/us-central1/registries/sensor_hub/devices/GAT-001] INFO daq.pubber.Pubber - Sending state message for device GAT-001
        -[MQTT Call: projects/gcp-account/locations/us-central1/registries/sensor_hub/devices/GAT-001] INFO daq.pubber.Pubber - Sending state message for device GAT-001
        -[pool-1-thread-1] INFO daq.pubber.Pubber - Sending test message for sensor_hub/GAT-001
        -[pool-1-thread-1] INFO daq.pubber.Pubber - Sending test message for sensor_hub/GAT-001
        -…
        -
        - -And an associated bit of activity in the validation output: -
        -…
        -Success validating out/pointset_GAT-001.json
        -Success validating out/pointset_GAT-001.json
        -Success validating out/config_GAT-001.json
        -Success validating out/pointset_GAT-001.json
        -Success validating out/state_GAT-001.json
        -Success validating out/state_GAT-001.json
        -Success validating out/state_GAT-001.json
        -Success validating out/pointset_GAT-001.json
        -Success validating out/state_GAT-001.json
        -Success validating out/pointset_GAT-001.json
        -Success validating out/pointset_GAT-001.json
        -…
        -
        From 9947cd0c5f91bb2ec7a0b5c221765d08d4466a78 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2020 16:56:06 -0700 Subject: [PATCH 077/212] Update dependency gradle to v6.6 (#585) --- .../bacnet/bacnetFaux/gradle/wrapper/gradle-wrapper.properties | 2 +- .../network/NTPClient/gradle/wrapper/gradle-wrapper.properties | 2 +- mudacl/gradle/wrapper/gradle-wrapper.properties | 2 +- .../bacnet/bacnetTests/gradle/wrapper/gradle-wrapper.properties | 2 +- subset/network/mac_oui/gradle/wrapper/gradle-wrapper.properties | 2 +- .../security/tlstest/gradle/wrapper/gradle-wrapper.properties | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docker/include/bacnet/bacnetFaux/gradle/wrapper/gradle-wrapper.properties b/docker/include/bacnet/bacnetFaux/gradle/wrapper/gradle-wrapper.properties index bb8b2fc26b..6c9a224775 100644 --- a/docker/include/bacnet/bacnetFaux/gradle/wrapper/gradle-wrapper.properties +++ b/docker/include/bacnet/bacnetFaux/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/docker/include/network/NTPClient/gradle/wrapper/gradle-wrapper.properties b/docker/include/network/NTPClient/gradle/wrapper/gradle-wrapper.properties index 622ab64a3c..6c9a224775 100644 --- a/docker/include/network/NTPClient/gradle/wrapper/gradle-wrapper.properties +++ b/docker/include/network/NTPClient/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/mudacl/gradle/wrapper/gradle-wrapper.properties b/mudacl/gradle/wrapper/gradle-wrapper.properties index af94776b0b..e15393d384 100644 --- a/mudacl/gradle/wrapper/gradle-wrapper.properties +++ b/mudacl/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-all.zip diff --git a/subset/bacnet/bacnetTests/gradle/wrapper/gradle-wrapper.properties b/subset/bacnet/bacnetTests/gradle/wrapper/gradle-wrapper.properties index bb8b2fc26b..6c9a224775 100644 --- a/subset/bacnet/bacnetTests/gradle/wrapper/gradle-wrapper.properties +++ b/subset/bacnet/bacnetTests/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/subset/network/mac_oui/gradle/wrapper/gradle-wrapper.properties b/subset/network/mac_oui/gradle/wrapper/gradle-wrapper.properties index 8db0d0d953..fa55e31a18 100644 --- a/subset/network/mac_oui/gradle/wrapper/gradle-wrapper.properties +++ b/subset/network/mac_oui/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-bin.zip diff --git a/subset/security/tlstest/gradle/wrapper/gradle-wrapper.properties b/subset/security/tlstest/gradle/wrapper/gradle-wrapper.properties index bb8b2fc26b..6c9a224775 100644 --- a/subset/security/tlstest/gradle/wrapper/gradle-wrapper.properties +++ b/subset/security/tlstest/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 470d9e408e9c46c50fba9b8201570a5d4ddbe1cf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2020 16:56:30 -0700 Subject: [PATCH 078/212] Update dependency commons-net:commons-net to v3.7 (#578) --- subset/switches/pom.xml | 2 +- usi/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subset/switches/pom.xml b/subset/switches/pom.xml index 7c90249145..23fec86bf1 100644 --- a/subset/switches/pom.xml +++ b/subset/switches/pom.xml @@ -20,7 +20,7 @@ commons-net commons-net - 3.6 + 3.7 diff --git a/usi/pom.xml b/usi/pom.xml index 0a9138e922..7725680553 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -33,7 +33,7 @@ commons-net commons-net - 3.6 + 3.7 io.grpc From 248f47e9d937c0fad835937cc247230c0130e28b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2020 16:57:01 -0700 Subject: [PATCH 079/212] Update dependency firebase-functions to v3.9.0 (#569) --- firebase/functions/package-lock.json | 30 ++++++++++++++-------------- firebase/functions/package.json | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/firebase/functions/package-lock.json b/firebase/functions/package-lock.json index 0ed8a55711..05444c0d9b 100644 --- a/firebase/functions/package-lock.json +++ b/firebase/functions/package-lock.json @@ -704,9 +704,9 @@ } }, "@types/express-serve-static-core": { - "version": "4.17.8", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.8.tgz", - "integrity": "sha512-1SJZ+R3Q/7mLkOD9ewCBDYD2k0WyZQtWYqF/2VvoNN2/uhI49J9CDN4OAm+wGMA0DbArA4ef27xl4+JwMtGggw==", + "version": "4.17.9", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.9.tgz", + "integrity": "sha512-DG0BYg6yO+ePW+XoDENYz8zhNGC3jDDEpComMYn7WJc4mY1Us8Rw9ax2YhJXxpyk2SF47PQAoQ0YyVT1a0bEkA==", "requires": { "@types/node": "*", "@types/qs": "*", @@ -727,9 +727,9 @@ "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" }, "@types/mime": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.2.tgz", - "integrity": "sha512-4kPlzbljFcsttWEq6aBW0OZe6BDajAmyvr2xknBG92tejQnvdGtT9+kXSZ580DqpxY9qG2xeQVF9Dq0ymUTo5Q==" + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz", + "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==" }, "@types/node": { "version": "13.9.5", @@ -737,9 +737,9 @@ "integrity": "sha512-hkzMMD3xu6BrJpGVLeQ3htQQNAcOrJjX7WFmtK8zWQpz2UJf13LCFF2ALA7c9OVdvc2vQJeDdjfR35M0sBCxvw==" }, "@types/qs": { - "version": "6.9.3", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.3.tgz", - "integrity": "sha512-7s9EQWupR1fTc2pSMtXRQ9w9gLOcrJn+h7HOXw4evxyvVqMi4f+q7d2tnFe3ng3SNHjtK+0EzGMGFUQX4/AQRA==" + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.4.tgz", + "integrity": "sha512-+wYo+L6ZF6BMoEjtf8zB2esQsqdV6WsjRK/GP9WOgLPrq87PbNWgIxS76dS5uvl/QXtHGakZmwTznIfcPXcKlQ==" }, "@types/range-parser": { "version": "1.2.3", @@ -747,9 +747,9 @@ "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==" }, "@types/serve-static": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.4.tgz", - "integrity": "sha512-jTDt0o/YbpNwZbQmE/+2e+lfjJEJJR0I3OFaKQKPWkASkCoW3i6fsUnqudSMcNAfbtmADGu8f4MV4q+GqULmug==", + "version": "1.13.5", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.5.tgz", + "integrity": "sha512-6M64P58N+OXjU432WoLLBQxbA0LRGBCRm7aAGQJ+SMC1IMl0dgRVi9EFfoDcS2a7Xogygk/eGN94CfwU9UF7UQ==", "requires": { "@types/express-serve-static-core": "*", "@types/mime": "*" @@ -1177,9 +1177,9 @@ } }, "firebase-functions": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-3.8.0.tgz", - "integrity": "sha512-RFvoS7ZcXrk2sQ918czsjv94p4hnSoD0/e4cZ86XFpa1HbNZBI7ZuSgBCzRvlv6dJ1ArytAL13NpB1Bp2tJ6Yg==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-3.9.0.tgz", + "integrity": "sha512-PHwEvm/c0CNWFxfilmhyZBu5pZlQ2EJk/W4G2yKUm2yHGuh2ZZcga0s4Tj52vllX2eE+NkAsDsJpGdnjljA6+Q==", "requires": { "@types/express": "4.17.3", "cors": "^2.8.5", diff --git a/firebase/functions/package.json b/firebase/functions/package.json index d75ce0b03f..5eb365d0f8 100644 --- a/firebase/functions/package.json +++ b/firebase/functions/package.json @@ -15,7 +15,7 @@ "@google-cloud/pubsub": "2.3.0", "@google-cloud/iot": "1.8.0", "firebase-admin": "9.0.0", - "firebase-functions": "3.8.0", + "firebase-functions": "3.9.0", "extend": "3.0.2" }, "private": true From d281472be506c6ae600902838eb1ded0e0edf650 Mon Sep 17 00:00:00 2001 From: henry54809 Date: Mon, 10 Aug 2020 17:41:53 -0700 Subject: [PATCH 080/212] refactoring for vlan trigger (#582) --- cmd/exrun | 7 + cmd/faux | 1 + daq/docker_test.py | 57 +++-- daq/faucet_event_client.py | 5 +- daq/gateway.py | 36 +-- daq/host.py | 149 +++++------ daq/ipaddr_test.py | 9 +- daq/runner.py | 483 +++++++++++++++++++----------------- testing/test_aux.out | 31 +-- testing/test_aux.sh | 58 +++-- testing/test_base.out | 20 +- testing/test_base.sh | 18 +- testing/test_dhcp.out | 10 +- testing/test_dhcp.sh | 8 +- testing/test_many.sh | 19 +- testing/test_utils.sh | 6 +- testing/unit/test_runner.py | 8 +- 17 files changed, 482 insertions(+), 443 deletions(-) diff --git a/cmd/exrun b/cmd/exrun index 37cfc401fc..f690c50ee2 100755 --- a/cmd/exrun +++ b/cmd/exrun @@ -74,6 +74,13 @@ rm -rf $INSTDIR/faucet* $cleanup_file docker ps > /dev/null 2>&1 || service docker start +bridges=`ovs-vsctl list-br` +for bridge in $bridges; do + echo Cleaning bridge $bridge... + # bug in ovs + timeout 10 ovs-vsctl --if-exists del-br $bridge || true + ovs-vsctl --if-exists del-br $bridge +done ovsctl=/usr/share/openvswitch/scripts/ovs-ctl $ovsctl status || sudo $ovsctl start diff --git a/cmd/faux b/cmd/faux index 2ba40d83d3..dd4deb3eec 100755 --- a/cmd/faux +++ b/cmd/faux @@ -123,6 +123,7 @@ else sudo ip link del $intf 2>/dev/null || true echo Adding new interface to $pid... + sudo ip link add $intf type veth peer name faux-eth0 addr $intf_mac netns $pid sudo ip link set $intf up fi diff --git a/daq/docker_test.py b/daq/docker_test.py index c38b210b8d..fe17657a8e 100644 --- a/daq/docker_test.py +++ b/daq/docker_test.py @@ -3,6 +3,8 @@ import datetime import os import subprocess +import string +import random import logger from clib import docker_host @@ -18,13 +20,14 @@ class DockerTest: TAGGED_IMAGE_FORMAT = IMAGE_NAME_FORMAT + ':latest' CONTAINER_PREFIX = 'daq' - # pylint: disable=too-many-arguments - def __init__(self, host, target_port, tmpdir, test_name, module_config): - self.target_port = target_port + def __init__(self, host, tmpdir, test_name, module_config): + self.device = host.device self.tmpdir = tmpdir self.test_name = test_name self.runner = host.runner - self.host_name = '%s%02d' % (test_name, self.target_port) + # Host name can't be more than 15 characters + # because it is also used to create an interface in mininet. + self.host_name = '%s_%s' % (test_name[:6], self._get_random_string(3)) self.docker_log = None self.docker_host = None self.callback = None @@ -34,7 +37,7 @@ def __init__(self, host, target_port, tmpdir, test_name, module_config): def start(self, port, params, callback, finish_hook): """Start the docker test""" - LOGGER.debug('Target port %d starting docker test %s', self.target_port, self.test_name) + LOGGER.debug('%s starting docker test', self) self.start_time = datetime.datetime.now() self.callback = callback @@ -60,7 +63,7 @@ def opt_param(key): self._map_if_exists(vol_maps, params, 'type') image = self.IMAGE_NAME_FORMAT % self.test_name - LOGGER.debug("Target port %d running docker test %s", self.target_port, image) + LOGGER.debug("%s running docker test %s", self, image) cls = docker_host.make_docker_host(image, prefix=self.CONTAINER_PREFIX) # Work around an instability in the faucet/clib/docker library, b/152520627. setattr(cls, 'pullImage', self._check_image) @@ -73,20 +76,20 @@ def opt_param(key): raise wrappers.DaqException(e) try: - LOGGER.debug("Target port %d activating docker test %s", self.target_port, image) + LOGGER.debug("%s activating docker test %s", self, image) pipe = host.activate(log_name=None) # Docker tests don't use DHCP, so manually set up DNS. host.cmd('echo nameserver $GATEWAY_IP > /etc/resolv.conf') self.docker_log = host.open_log() if self._should_raise_test_exception('initialize'): - LOGGER.error('Target port %d inducing initialization failure', self.target_port) + LOGGER.error('%s inducing initialization failure', self) raise Exception('induced initialization failure') self.runner.monitor_stream(self.host_name, pipe.stdout, copy_to=self.docker_log, hangup=self._docker_complete, error=self._docker_error) self.pipe = pipe if self._should_raise_test_exception('callback'): - LOGGER.error('Target port %d will induce callback failure', self.target_port) + LOGGER.error('%s will induce callback failure', self) # Closing this now will cause error when attempting to write output. self.docker_log.close() except Exception as e: @@ -97,7 +100,7 @@ def opt_param(key): self.runner.monitor_forget(self.pipe.stdout) self.pipe = None raise e - LOGGER.info("Target port %d test %s running", self.target_port, self.test_name) + LOGGER.info("%s running", self) def _check_image(self): lines = subprocess.check_output(["docker", "images", "--format", @@ -108,7 +111,7 @@ def _check_image(self): def terminate(self): """Forcibly terminate this container""" - LOGGER.info("Target port %d test %s terminating", self.target_port, self.test_name) + LOGGER.info("%s terminating", self) return self._docker_finalize() def _map_if_exists(self, vol_maps, params, kind): @@ -116,18 +119,18 @@ def _map_if_exists(self, vol_maps, params, kind): if base and os.path.exists(base): abs_base = os.path.abspath(base) vol_maps += ['%s:/config/%s' % (abs_base, kind)] - LOGGER.info('Target port %d mapping %s to /config/%s', self.target_port, abs_base, kind) + LOGGER.info('%s mapping %s to /config/%s', self, abs_base, kind) def _docker_error(self, exception): - LOGGER.error('Target port %d docker error: %s', self.target_port, str(exception)) + LOGGER.error('%s docker error: %s', self, str(exception)) if self._docker_finalize() is None: - LOGGER.warning('Target port %d docker already terminated.', self.target_port) + LOGGER.warning('%s docker already terminated.', self) else: self.callback(exception=exception) def _docker_finalize(self): - assert self.docker_host, 'docker host %s already finalized' % self.target_port - LOGGER.info('Target port %d docker finalize', self.target_port) + assert self.docker_host, 'docker host %s already finalized' % self + LOGGER.info('%s docker finalize', self) if self._finish_hook: self._finish_hook() self.runner.remove_host(self.docker_host) @@ -139,12 +142,12 @@ def _docker_finalize(self): self.docker_log.close() self.docker_log = None if self._should_raise_test_exception('finalize'): - LOGGER.error('Target port %d inducing finalize failure', self.target_port) + LOGGER.error('%s inducing finalize failure', self) raise Exception('induced finalize failure') return return_code def _should_raise_test_exception(self, trigger_value): - key = '%s_%02d' % (self.test_name, self.target_port) + key = "%s_%s" % (self.test_name, self.device.mac.replace(':', '')) return self.runner.config.get('fail_module', {}).get(key) == trigger_value def _docker_complete(self): @@ -158,15 +161,21 @@ def _docker_complete(self): exception = e LOGGER.exception(e) delay = (datetime.datetime.now() - self.start_time).total_seconds() - LOGGER.debug("Target port %d docker complete, return=%d (%s)", - self.target_port, return_code, exception) + LOGGER.debug("%s docker complete, return=%d (%s)", + self, return_code, exception) if return_code: - LOGGER.info("Target port %d test %s failed %ss: %s %s", - self.target_port, self.test_name, delay, return_code, exception) + LOGGER.info("%s failed %ss: %s %s", + self, delay, return_code, exception) else: - LOGGER.info("Target port %d test %s passed %ss", - self.target_port, self.test_name, delay) + LOGGER.info("%s passed %ss", + self, delay) self.callback(return_code=return_code, exception=exception) + def _get_random_string(self, length): + return ''.join(random.choice(string.ascii_letters) for _ in range(length)) + + def __repr__(self): + return "Target device %s test %s" % (self.device, self.test_name) + def ip_listener(self, target_ip): """Do nothing b/c docker tests don't care about ip notifications""" diff --git a/daq/faucet_event_client.py b/daq/faucet_event_client.py index a97c8c9bb5..b2254b1cf9 100644 --- a/daq/faucet_event_client.py +++ b/daq/faucet_event_client.py @@ -184,11 +184,12 @@ def as_port_state(self, event): def as_port_learn(self, event): """Convert to port learning info, if applicable""" if not event or 'L2_LEARN' not in event: - return (None, None, None) + return [None] * 4 dpid = event['dp_id'] port_no = int(event['L2_LEARN']['port_no']) eth_src = event['L2_LEARN']['eth_src'] - return (dpid, port_no, eth_src) + vid = event['L2_LEARN']['vid'] + return (dpid, port_no, eth_src, vid) def close(self): """Close the faucet event socket""" diff --git a/daq/gateway.py b/daq/gateway.py index 4ee9bc2fd1..60b6abe193 100644 --- a/daq/gateway.py +++ b/daq/gateway.py @@ -182,9 +182,8 @@ def _is_target_expected(self, target): if not target: return False target_mac = target['mac'] - for target_port in self.targets: - if self.targets[target_port]['mac'] == target_mac: - return True + if target_mac in self.targets: + return True LOGGER.warning('No target match found for %s in %s', target_mac, self.name) return False @@ -192,7 +191,7 @@ def _dhcp_callback(self, state, target, exception=None): if exception: LOGGER.error('Gateway DHCP exception %s', exception) if self._is_target_expected(target) or exception: - self.runner.ip_notify(state, target, self.port_set, exception=exception) + self.runner.ip_notify(state, target, self, exception=exception) def _setup_tmpdir(self, base_name): tmpdir = os.path.join('inst', base_name) @@ -201,26 +200,26 @@ def _setup_tmpdir(self, base_name): os.makedirs(tmpdir) return tmpdir - def attach_target(self, target_port, target): + def attach_target(self, device): """Attach the given target to this gateway; return number of attached targets.""" - assert target_port not in self.targets, 'target already attached to gw' - LOGGER.info('Attaching target %d to gateway group %s', target_port, self.name) - self.targets[target_port] = target + assert device.mac not in self.targets, 'target %s already attached to gw' % device + LOGGER.info('Attaching target %s to gateway group %s', device, self.name) + self.targets[device.mac] = device return len(self.targets) - def detach_target(self, target_port): + def detach_target(self, device): """Detach the given target from this gateway; return number of remaining targets.""" - assert target_port in self.targets, 'target not attached to gw' - LOGGER.info('Detach target %d from gateway group %s: %s', - target_port, self.name, list(self.targets.keys())) - del self.targets[target_port] + assert device.mac in self.targets, 'target %s not attached to gw' % device + LOGGER.info('Detach target %s from gateway group %s: %s', + device, self.name, list(self.targets.keys())) + del self.targets[device.mac] return len(self.targets) - def target_ready(self, target_mac): + def target_ready(self, device): """Mark a target ready, and return set of ready targets""" - if not target_mac in self.ready: - LOGGER.info('Ready target %s from gateway group %s', target_mac, self.name) - self.ready.add(target_mac) + if device not in self.ready: + LOGGER.info('Ready target %s from gateway group %s', device, self.name) + self.ready.add(device) return self.ready def get_targets(self): @@ -253,3 +252,6 @@ def terminate(self): def _ping_test(self, src, dst, src_addr=None): return self.runner.ping_test(src, dst, src_addr=src_addr) + + def __repr__(self): + return 'Gateway group %s set %d' % (self.name, self.port_set) diff --git a/daq/host.py b/daq/host.py index 16562b929a..d1c68b5bad 100644 --- a/daq/host.py +++ b/daq/host.py @@ -80,20 +80,21 @@ class ConnectedHost: _TIMEOUT_EXCEPTION = TimeoutError('Timeout expired') # pylint: disable=too-many-statements - def __init__(self, runner, gateway, target, config): + def __init__(self, runner, device, config): self.configurator = configurator.Configurator() self.runner = runner self._gcp = runner.gcp - self.gateway = gateway + self.gateway = device.gateway self.config = config self.switch_setup = self.config.get('switch_setup', {}) - self.target_port = target['port'] - self.target_mac = target['mac'] - self.fake_target = target['fake'] + self.device = device + self.target_mac = device.mac + self.target_port = device.port.port_no + self.fake_target = self.gateway.fake_target self.devdir = self._init_devdir() self.run_id = self.make_runid() self.scan_base = os.path.abspath(os.path.join(self.devdir, 'scans')) - self.logger = logger.get_logger('host%s' % self.target_port) + self.logger = logger.get_logger('host') self._port_base = self._get_port_base() self._device_base = self._get_device_base() self.state = None @@ -121,7 +122,7 @@ def __init__(self, runner, gateway, target, config): assert self._loaded_config, 'config was not loaded' self._write_module_config(self._loaded_config, self._device_aux_path()) self.remaining_tests = self._get_enabled_tests() - self.logger.info('Host %s running with enabled tests %s', self.target_port, + self.logger.info('Host %s running with enabled tests %s', self.target_mac, self.remaining_tests) self._report = ReportGenerator(config, self._INST_DIR, self.target_mac, self._loaded_config) @@ -139,20 +140,20 @@ def make_runid(): return '%06x' % int(time.time()) def _init_devdir(self): - devdir = os.path.join(self._INST_DIR, 'run-port-%02d' % self.target_port) + devdir = os.path.join(self._INST_DIR, 'run-%s' % self.target_mac.replace(':', '')) shutil.rmtree(devdir, ignore_errors=True) os.makedirs(devdir) return devdir def _get_port_base(self): test_config = self.config.get('test_config') - if not test_config: - return None - conf_base = os.path.abspath(os.path.join(test_config, 'port-%02d' % self.target_port)) - if not os.path.isdir(conf_base): - self.logger.warning('Test config directory not found: %s', conf_base) - return None - return conf_base + if test_config and self.target_port: + conf_base = os.path.abspath(os.path.join(test_config, 'port-%02d' % self.target_port)) + if not os.path.isdir(conf_base): + self.logger.warning('Test config directory not found: %s', conf_base) + return None + return conf_base + return None def _make_config_bundle(self, config=None): return { @@ -224,7 +225,7 @@ def _type_path(self): device_type = dev_config.get('device_type') if not device_type: return None - self.logger.info('Configuring device %s as type %s', self.target_mac, device_type) + self.logger.info('Configuring device %s as type %s', self.device, device_type) site_path = self.config.get('site_path') type_path = os.path.abspath(os.path.join(site_path, 'device_types', device_type)) return type_path @@ -257,14 +258,15 @@ def _upload_file(self, path): def initialize(self): """Fully initialize a new host set""" - self.logger.info('Target port %d initializing...', self.target_port) + self.logger.info('Target device %s initializing...', self) # There is a race condition here with ovs assigning ports, so wait a bit. time.sleep(2) shutil.rmtree(self.devdir, ignore_errors=True) os.makedirs(self.scan_base) self._initialize_config() network = self.runner.network - self._mirror_intf_name = network.create_mirror_interface(self.target_port) + if self.target_port: + self._mirror_intf_name = network.create_mirror_interface(self.target_port) self._topology_hook() if self.config['test_list']: self._start_run() @@ -289,13 +291,13 @@ def _state_transition(self, target, expected=None): message = 'state was %s expected %s' % (self.state, expected) assert self.state == expected, message assert self.state != _STATE.TERM, 'host already terminated' - self.logger.debug('Target port %d state: %s -> %s', self.target_port, self.state, target) + self.logger.debug('Target device %s state: %s -> %s', self, self.state, target) self.state = target def _build_switch_info(self) -> usi.SwitchInfo: switch_config = self._get_switch_config() model_str = switch_config['model'] - if model_str == 'FAUX_SWITCH': + if model_str == 'FAUX_SWITCH' or not self.target_port: return None if model_str: switch_model = usi.SwitchModel.Value(model_str) @@ -346,28 +348,28 @@ def connect_port(self, connect): return True def _prepare(self): - self.logger.info('Target port %d waiting for ip as %s', self.target_port, self.target_mac) + self.logger.info('Target device %s waiting for ip', self) self._state_transition(_STATE.WAITING, _STATE.INIT) self.record_result('sanity', state=MODE.DONE) self.record_result('acquire', state=MODE.EXEC) static_ip = self._get_static_ip() if static_ip: - self.logger.info('Target port %d using static ip', self.target_port) + self.logger.info('Target device %s using static ip', self) time.sleep(self._STARTUP_MIN_TIME_SEC) self.runner.ip_notify(MODE.NOPE, { 'mac': self.target_mac, 'ip': static_ip, 'delta': -1 - }, self.gateway.port_set) + }, self.gateway) else: dhcp_mode = self._get_dhcp_mode() # enables dhcp response for this device wait_time = self.runner.config.get("long_dhcp_response_sec") \ if dhcp_mode == 'long_response' else 0 - self.logger.info('Target port %d using %s DHCP mode, wait %s', - self.target_port, dhcp_mode, wait_time) + self.logger.info('Target device %s using %s DHCP mode, wait %s', + self, dhcp_mode, wait_time) self.gateway.change_dhcp_response_time(self.target_mac, wait_time) - _ = [listener(self) for listener in self._dhcp_listeners] + _ = [listener(self.device) for listener in self._dhcp_listeners] def _aux_module_timeout_handler(self): # clean up tcp monitor that could be open @@ -408,12 +410,13 @@ def _finalize_report(self): def terminate(self, reason, trigger=True): """Terminate this host""" - self.logger.info('Target port %d terminate, running %s, trigger %s: %s', self.target_port, + self.logger.info('Target device %s terminate, running %s, trigger %s: %s', self, self._host_name(), trigger, reason) self._state_transition(_STATE.TERM) self._release_config() self._monitor_cleanup() - self.runner.network.delete_mirror_interface(self.target_port) + if self.target_port: + self.runner.network.delete_mirror_interface(self.target_port) self._finalize_report() if self.test_host: try: @@ -421,12 +424,12 @@ def terminate(self, reason, trigger=True): self.test_host = None self.timeout_handler = None except Exception as e: - self.logger.error('Target port %d terminating test: %s', self.target_port, e) + self.logger.error('Target device %s terminating test: %s', self, self.test_name) self.logger.exception(e) if trigger: - self.runner.target_set_complete(self.target_port, - 'Target port %d termination: %s' % ( - self.target_port, self.test_host)) + self.runner.target_set_complete(self.device, + 'Target device %s termination: %s' % ( + self, self.test_host)) def idle_handler(self): """Trigger events from idle state""" @@ -461,10 +464,10 @@ def trigger_ready(self): def trigger(self, state=MODE.DONE, target_ip=None, exception=None, delta_sec=-1): """Handle device trigger""" if not self.target_ip and not self.trigger_ready(): - self.logger.warn('Target port %d ignoring premature trigger', self.target_port) + self.logger.warn('Target device %s ignoring premature trigger', self) return False if self.target_ip: - self.logger.debug('Target port %d already triggered', self.target_port) + self.logger.debug('Target device %s already triggered', self) assert self.target_ip == target_ip, "target_ip mismatch" return True self.target_ip = target_ip @@ -472,9 +475,9 @@ def trigger(self, state=MODE.DONE, target_ip=None, exception=None, delta_sec=-1) self.record_result('acquire', ip=target_ip, state=state, exception=exception) if exception: self._state_transition(_STATE.ERROR) - self.runner.target_set_error(self.target_port, exception) + self.runner.target_set_error(self.device, exception) else: - self.logger.info('Target port %d triggered as %s', self.target_port, target_ip) + self.logger.info('Target device %s triggered as %s', self, target_ip) self._state_transition(_STATE.BASE, _STATE.WAITING) return True @@ -487,15 +490,16 @@ def _ping_test(self, src, dst, src_addr=None): def _startup_scan(self): self._startup_file = os.path.join(self.scan_base, 'startup.pcap') self._startup_time = datetime.now() - self.logger.info('Target port %d startup pcap capture', self.target_port) + self.logger.info('Target device %s startup pcap capture', self) self._monitor_scan(self._startup_file) def _monitor_scan(self, output_file, timeout=None): assert not self._monitor_ref, 'tcp_monitor already active' network = self.runner.network tcp_filter = '' - self.logger.info('Target port %d pcap intf %s for %ss output in %s', - self.target_port, self._mirror_intf_name, timeout, output_file) + self.logger.info('Target device %s pcap intf %s for %s seconds output in %s', + self, self._mirror_intf_name, timeout if timeout else 'infinite', + output_file) helper = tcpdump_helper.TcpdumpHelper(network.pri, tcp_filter, packets=None, intf_name=self._mirror_intf_name, timeout=timeout, pcap_out=output_file, @@ -511,10 +515,10 @@ def _base_start(self): success = self._base_tests() self._monitor_cleanup() if not success: - self.logger.warning('Target port %d base tests failed', self.target_port) + self.logger.warning('Target device %s base tests failed', self) self._state_transition(_STATE.ERROR) return - self.logger.info('Target port %d done with base.', self.target_port) + self.logger.info('Target device %s done with base.', self) self._background_scan() except Exception as e: self._monitor_cleanup() @@ -522,7 +526,7 @@ def _base_start(self): def _monitor_cleanup(self, forget=True): if self._monitor_ref: - self.logger.info('Target port %d network pcap complete', self.target_port) + self.logger.info('Target device %s network pcap complete', self) active = self._monitor_ref.stream() and not self._monitor_ref.stream().closed assert active == forget, 'forget and active mismatch' self._upload_file(self._startup_file) @@ -532,22 +536,22 @@ def _monitor_cleanup(self, forget=True): self._monitor_ref = None def _monitor_error(self, exception, forget=False): - self.logger.error('Target port %d monitor error: %s', self.target_port, exception) + self.logger.error('Target device %s monitor error: %s', self, exception) self._monitor_cleanup(forget=forget) self.record_result(self.test_name, exception=exception) self._state_transition(_STATE.ERROR) - self.runner.target_set_error(self.target_port, exception) + self.runner.target_set_error(self.device, exception) def _background_scan(self): self._state_transition(_STATE.MONITOR, _STATE.BASE) if not self._monitor_scan_sec: - self.logger.info('Target port %d skipping background pcap', self.target_port) + self.logger.info('Target device %s skipping background pcap', self) self._monitor_continue() return self.record_result('monitor', time=self._monitor_scan_sec, state=MODE.EXEC) monitor_file = os.path.join(self.scan_base, 'monitor.pcap') - self.logger.info('Target port %d background pcap for %ds', - self.target_port, self._monitor_scan_sec) + self.logger.info('Target device %s background pcap for %ds', + self, self._monitor_scan_sec) self._monitor_scan(monitor_file, timeout=self._monitor_scan_sec) def _monitor_timeout(self, timeout): @@ -558,7 +562,7 @@ def _monitor_timeout(self, timeout): self._monitor_complete() def _monitor_complete(self): - self.logger.info('Target port %d pcap complete', self.target_port) + self.logger.info('Target device %s pcap complete', self) self._monitor_cleanup(forget=False) self.record_result('monitor', state=MODE.DONE) self._monitor_continue() @@ -571,7 +575,7 @@ def _monitor_continue(self): def _base_tests(self): self.record_result('base', state=MODE.EXEC) if not self._ping_test(self.gateway.host, self.target_ip): - self.logger.debug('Target port %d warmup ping failed', self.target_port) + self.logger.debug('Target device %s warmup ping failed', self) try: success1 = self._ping_test(self.gateway.host, self.target_ip), 'simple ping failed' success2 = self._ping_test(self.gateway.host, self.target_ip, @@ -589,18 +593,18 @@ def _run_next_test(self): assert not self.test_name, 'test_name defined: %s' % self.test_name try: if self.remaining_tests: - self.logger.debug('Target port %d executing tests %s', - self.target_port, self.remaining_tests) + self.logger.debug('Target device %s executing tests %s', + self, self.remaining_tests) self._run_test(self.remaining_tests.pop(0)) else: - self.logger.info('Target port %d no more tests remaining', self.target_port) + self.logger.info('Target device %s no more tests remaining', self) self.timeout_handler = self._aux_module_timeout_handler self._state_transition(_STATE.DONE, _STATE.NEXT) self.record_result('finish', state=MODE.FINE) except Exception as e: - self.logger.error('Target port %d start error: %s', self.target_port, e) + self.logger.error('Target device %s start error: %s', self, e) self._state_transition(_STATE.ERROR) - self.runner.target_set_error(self.target_port, e) + self.runner.target_set_error(self.device, e) def _inst_config_path(self): return os.path.abspath(os.path.join(self._INST_DIR, self._CONFIG_DIR)) @@ -613,16 +617,16 @@ def _device_aux_path(self): def _new_test(self, test_name): clazz = ipaddr_test.IpAddrTest if test_name == 'ipaddr' else docker_test.DockerTest - return clazz(self, self.target_port, self.devdir, test_name, self._loaded_config) + return clazz(self, self.devdir, test_name, self._loaded_config) def _run_test(self, test_name): self.timeout_handler = self._main_module_timeout_handler self.test_host = self._new_test(test_name) - self.logger.info('Target port %d start %s', self.target_port, self._host_name()) + self.logger.info('Target device %s start %s', self, self._host_name()) try: - self.test_port = self.runner.allocate_test_port(self.target_port) + self.test_port = self.gateway.allocate_test_port() except Exception as e: self.test_host = None raise e @@ -633,7 +637,7 @@ def _run_test(self, test_name): self.test_host.start(self.test_port, params, self._module_callback, self._finish_hook) except Exception as e: self.test_host = None - self.runner.release_test_port(self.target_port, self.test_port) + self.gateway.release_test_port(self.test_port) self.test_port = None self._monitor_cleanup() raise e @@ -674,7 +678,7 @@ def _get_module_params(self): 'local_ip': ext_loip, 'target_ip': self.target_ip, 'target_mac': self.target_mac, - 'target_port': str(self.target_port), + 'target_port': str(self.target_port) if self.target_port else None, 'gateway_ip': self.gateway.host.IP(), 'gateway_mac': self.gateway.host.MAC(), 'inst_base': self._inst_config_path(), @@ -727,7 +731,7 @@ def _module_callback(self, return_code=None, exception=None): self.test_name, host_name, return_code, exception) failed = return_code or exception state = MODE.MERR if failed else MODE.DONE - self.runner.release_test_port(self.target_port, self.test_port) + self.gateway.release_test_port(self.test_port) assert self.test_host, '_module_callback with no test_host defined' self._end_test(state=state, return_code=return_code, exception=exception) @@ -753,8 +757,8 @@ def record_result(self, name, **kwargs): """Record a named result for this test""" current = gcp.get_timestamp() if name != self.test_name: - self.logger.debug('Target port %d report %s start %s', - self.target_port, name, current) + self.logger.debug('Target device %s report %s start %s', + self, name, current) self.test_name = name self.test_start = current if name: @@ -790,12 +794,12 @@ def _exception_message(self, exception): return str(exception) def _control_updated(self, control_config): - self.logger.info('Updated control config: %s %s', self.target_mac, control_config) + self.logger.info('Updated control config: %s %s', self, control_config) paused = control_config.get('paused') if not paused and self.is_ready(): self._start_run() elif paused and not self.is_ready(): - self.logger.warning('Inconsistent control state for update of %s', self.target_mac) + self.logger.warning('Inconsistent control state for update of %s', self) def reload_config(self): """Trigger a config reload due to an external config change.""" @@ -804,12 +808,12 @@ def reload_config(self): if device_ready: self._loaded_config = new_config config_bundle = self._make_config_bundle(new_config) - self.logger.info('Device config reloaded: %s %s', device_ready, self.target_mac) + self.logger.info('Device config reloaded: %s %s', device_ready, self) self._record_result(None, run_info=device_ready, config=config_bundle) return new_config def _dev_config_updated(self, dev_config): - self.logger.info('Device config update: %s %s', self.target_mac, dev_config) + self.logger.info('Device config update: %s %s', self, dev_config) self._write_module_config(dev_config, self._device_base) self.reload_config() @@ -817,11 +821,16 @@ def _initialize_config(self): dev_config = self._load_config({}, self._device_base) self._gcp.register_config(self._DEVICE_PATH % self.target_mac, dev_config, self._dev_config_updated) - self._gcp.register_config(self._CONTROL_PATH % self.target_port, - self._make_control_bundle(), - self._control_updated, immediate=True) + if self.target_port: + self._gcp.register_config(self._CONTROL_PATH % self.target_port, + self._make_control_bundle(), + self._control_updated, immediate=True) self._record_result(None, config=self._make_config_bundle()) def _release_config(self): self._gcp.release_config(self._DEVICE_PATH % self.target_mac) - self._gcp.release_config(self._CONTROL_PATH % self.target_port) + if self.target_port: + self._gcp.release_config(self._CONTROL_PATH % self.target_port) + + def __repr__(self): + return str(self.device) + (" on port %d" % self.target_port if self.target_port else "") diff --git a/daq/ipaddr_test.py b/daq/ipaddr_test.py index a7473925ce..0ce72b7e65 100644 --- a/daq/ipaddr_test.py +++ b/daq/ipaddr_test.py @@ -12,15 +12,14 @@ class IpAddrTest: """Module for inline ipaddr tests""" - # pylint: disable=too-many-arguments - def __init__(self, host, target_port, tmpdir, test_name, module_config): + def __init__(self, host, tmpdir, test_name, module_config): self.host = host - self.target_port = target_port + self.device = host.device self.tmpdir = tmpdir self.test_config = module_config.get('modules').get('ipaddr') self.test_dhcp_ranges = copy.copy(self.test_config.get('dhcp_ranges', [])) self.test_name = test_name - self.host_name = '%s%02d' % (test_name, self.target_port) + self.host_name = '%s_%s' % (test_name, self.device.mac) self.log_path = os.path.join(self.tmpdir, 'nodes', self.host_name, 'activate.log') self.log_file = None self.callback = None @@ -35,7 +34,7 @@ def __init__(self, host, target_port, tmpdir, test_name, module_config): def start(self, port, params, callback, finish_hook): """Start the ip-addr tests""" self.callback = callback - LOGGER.debug('Target port %d starting ipaddr test %s', self.target_port, self.test_name) + LOGGER.debug('Target device %s starting ipaddr test %s', self.device, self.test_name) self.log_file = open(self.log_path, 'w') self._next_test() diff --git a/daq/runner.py b/daq/runner.py index 5895045271..8e416d554d 100644 --- a/daq/runner.py +++ b/daq/runner.py @@ -25,18 +25,87 @@ class PortInfo: """Simple container for device port info""" active = False - flapping_start = 0 - mac = None - host = None - gateway = None - + flapping_start = None + port_no = None + + +class IpInfo: + """Simple container for device ip info""" + ip_addr = None + state = None + delta_sec = None + + +class Device: + """Simple container for device info""" + def __init__(self): + self.mac = None + self.host = None + self.gateway = None + self.group = None + self.port = PortInfo() + self.dhcp_ready = False + self.ip_info = IpInfo() + + def __repr__(self): + return self.mac.replace(":", "") + + +class Devices: + """Container for all devices""" + def __init__(self): + self._devices = {} + + def new_device(self, mac): + """Adding a new device""" + assert mac not in self._devices, "Device with mac: %s is already added." % mac + device = Device() + device.mac = mac + self._devices[mac] = device + return device + + def remove(self, device): + """Removing a device""" + assert self.contains(device), "Device %s not found." % device + del self._devices[device.mac] + + def get(self, device_mac): + """Get a device using its mac address""" + return self._devices.get(device_mac) + + def get_by_port_info(self, port): + """Get a device using its port info object""" + for device in self._devices.values(): + if device.port == port: + return device + return None + + def get_by_gateway(self, gateway): + """Get devices under specified gateway""" + return [device for device in self._devices.values() if device.gateway == gateway] + + def get_by_group(self, group_name): + """Get devices under a group name""" + return [device for device in self._devices.values() if device.group == group_name] + + def get_all_devices(self): + """Get all devices""" + return list(self._devices.values()) + + def get_triggered_devices(self): + """Get devices with hosts""" + return [device for device in self._devices.values() if device.host] + + def contains(self, device): + """Returns true if the device is expected""" + return self._devices.get(device.mac) == device class DAQRunner: """Main runner class controlling DAQ. Primarily mediates between faucet events, connected hosts (to test), and gcp for logging. This class owns the main event loop and shards out work to subclasses.""" - MAX_GATEWAYS = 10 + MAX_GATEWAYS = 9 _DEFAULT_RETENTION_DAYS = 30 _MODULE_CONFIG = 'module_config.json' _RUNNER_CONFIG_PATH = 'runner/setup' @@ -45,13 +114,11 @@ class owns the main event loop and shards out work to subclasses.""" def __init__(self, config): self.configurator = configurator.Configurator() + self.gateway_sets = set(range(1, self.MAX_GATEWAYS+1)) self.config = config - self._port_info = {} self._result_sets = {} - self._mac_port_map = {} - self._device_groups = {} - self._gateway_sets = {} - self._target_mac_ip = {} + self._devices = Devices() + self._ports = {} self._callback_queue = [] self._callback_lock = threading.Lock() self.gcp = gcp.GcpManager(self.config, self._queue_callback) @@ -65,7 +132,6 @@ def __init__(self, config): self._linger_exit = 0 self.faucet_events = None self.single_shot = config.get('single_shot', False) - self.event_trigger = config.get('event_trigger', False) self.fail_mode = config.get('fail_mode', False) self.run_tests = True self.stream_monitor = None @@ -75,8 +141,6 @@ def __init__(self, config): self._default_port_flap_timeout = int(config.get('port_flap_timeout_sec', 0)) self.result_log = self._open_result_log() self._system_active = False - self._dhcp_ready = set() - self._ip_info = {} logging_client = self.gcp.get_logging_client() self._daq_run_id = uuid.uuid4() if logging_client: @@ -93,12 +157,6 @@ def __init__(self, config): LOGGER.info('LSB release %s' % self._lsb_release) LOGGER.info('system uname %s' % self._sys_uname) - def _flush_faucet_events(self): - LOGGER.info('Flushing faucet event queue...') - if self.faucet_events: - while self.faucet_events.next_event(): - pass - def _open_result_log(self): return open(self._RESULT_LOG_FILE, 'w') @@ -182,9 +240,9 @@ def _handle_faucet_events(self): LOGGER.debug('port_state: %s %s', dpid, port) self._handle_port_state(dpid, port, active) return - (dpid, port, target_mac) = self.faucet_events.as_port_learn(event) - if dpid and port: - self._handle_port_learn(dpid, port, target_mac) + (dpid, port, target_mac, vid) = self.faucet_events.as_port_learn(event) + if dpid and port and vid: + self._handle_port_learn(dpid, port, vid, target_mac) return (dpid, restart_type) = self.faucet_events.as_config_change(event) if dpid is not None: @@ -203,41 +261,47 @@ def _handle_port_state(self, dpid, port, active): LOGGER.debug('Unknown port %s on dpid %s is active %s', port, dpid, active) return - if port not in self._port_info: - self._port_info[port] = PortInfo() + if port not in self._ports: + self._ports[port] = PortInfo() + self._ports[port].port_no = port - if active != self._port_info[port].active: + if active != self._ports[port].active: LOGGER.info('Port %s dpid %s is now %s', port, dpid, "active" if active else "inactive") if active: self._activate_port(port) else: - port_info = self._port_info[port] - if port_info.host and not port_info.flapping_start: + device = self._devices.get_by_port_info(self._ports[port]) + port_info = self._ports[port] + if device and device.host and not port_info.flapping_start: port_info.flapping_start = time.time() if port_info.active: - if port_info.mac and not port_info.flapping_start: - self._direct_port_traffic(port_info.mac, port, None) + if device and not port_info.flapping_start: + self._direct_port_traffic(device.mac, port, None) self._deactivate_port(port) self._send_heartbeat() def _activate_port(self, port): - port_info = self._port_info[port] + port_info = self._ports[port] port_info.flapping_start = 0 port_info.active = True def _deactivate_port(self, port): - port_info = self._port_info[port] + port_info = self._ports[port] port_info.active = False def _direct_port_traffic(self, mac, port, target): self.network.direct_port_traffic(mac, port, target) - def _handle_port_learn(self, dpid, port, target_mac): + def _handle_port_learn(self, dpid, port, vid, target_mac): if self.network.is_device_port(dpid, port): LOGGER.info('Port %s dpid %s learned %s', port, dpid, target_mac) - self._mac_port_map[target_mac] = port - self._port_info[port].mac = target_mac - self._target_set_trigger(port) + if port not in self._ports: + self._ports[port] = PortInfo() + self._ports[port].port_no = port + if not self._devices.get(target_mac): + device = self._devices.new_device(target_mac) + device.port = self._ports[port] + self._target_set_trigger(self._devices.get(target_mac)) else: LOGGER.debug('Port %s dpid %s learned %s (ignored)', port, dpid, target_mac) @@ -259,21 +323,19 @@ def _handle_system_idle(self): # Some synthetic faucet events don't come in on the socket, so process them here. self._handle_faucet_events() all_idle = True - for target_port, target_host in self._get_port_hosts(): + for device in self._devices.get_triggered_devices(): try: - if target_host.is_running(): + if device.host.is_running(): all_idle = False - target_host.idle_handler() + device.host.idle_handler() else: - self.target_set_complete(target_port, 'target set not active') + self.target_set_complete(device, 'target set not active') except Exception as e: - self.target_set_error(target_host.target_port, e) - if not self.event_trigger: - for target_port, port_info in self._port_info.items(): - if port_info.active and port_info.mac: - self._target_set_trigger(target_port) - all_idle = False - if not self._get_running_ports() and not self.run_tests: + self.target_set_error(device, e) + for device in self._devices.get_all_devices(): + self._target_set_trigger(device) + all_idle = False + if not self._devices.get_triggered_devices() and not self.run_tests: if self.faucet_events and not self._linger_exit: self.shutdown() if self._linger_exit == 1: @@ -281,20 +343,19 @@ def _handle_system_idle(self): LOGGER.warning('Result linger on exit.') all_idle = False if all_idle: - LOGGER.debug('No active device ports, waiting for trigger event...') + LOGGER.debug('No active device, waiting for trigger event...') def _reap_stale_ports(self): - for port, port_info in copy.copy(self._port_info).items(): - if not port_info.flapping_start or not port_info.host: + for device in self._devices.get_triggered_devices(): + if not device.port.flapping_start: continue - host = port_info.host - timeout_sec = host.get_port_flap_timeout(host.test_name) + timeout_sec = device.host.get_port_flap_timeout(device.host.test_name) if timeout_sec is None: timeout_sec = self._default_port_flap_timeout - if (port_info.flapping_start + timeout_sec) <= time.time(): + if (device.port.flapping_start + timeout_sec) <= time.time(): exception = DaqException('port not active for %ds' % timeout_sec) - self.target_set_error(port, exception) - port_info.flapping_start = 0 + self.target_set_error(device, exception) + device.port.flapping_start = 0 def shutdown(self): """Shutdown this runner by closing all active components""" @@ -308,16 +369,16 @@ def shutdown(self): def _loop_hook(self): self._handle_queued_events() - states = {p: h.state for p, h in self._get_port_hosts()} + states = {device.mac: device.host.state for device in self._devices.get_triggered_devices()} LOGGER.debug('Active target sets/state: %s', states) def _terminate(self): - for target_port in self._get_running_ports(): - self.target_set_error(target_port, DaqException('terminated')) + for device in self._devices.get_triggered_devices(): + self.target_set_error(device, DaqException('terminated')) def _module_heartbeat(self): # Should probably be converted to a separate thread to timeout any blocking fn calls - _ = [host.heartbeat() for _, host in self._get_port_hosts()] + _ = [device.host.heartbeat() for device in self._devices.get_triggered_devices()] def main_loop(self): """Run main loop to execute tests""" @@ -329,8 +390,6 @@ def main_loop(self): self.stream_monitor = monitor self.monitor_stream('faucet', self.faucet_events.sock, self._handle_faucet_events, priority=10) - if self.event_trigger: - self._flush_faucet_events() LOGGER.info('Entering main event loop.') LOGGER.info('See docs/troubleshooting.md if this blocks for more than a few minutes.') while self.stream_monitor.event_loop(): @@ -351,64 +410,62 @@ def main_loop(self): self._terminate() - def _target_set_trigger(self, target_port): - target_active = target_port in self._port_info and self._port_info[target_port].active - assert target_active, 'Target port %d not active' % target_port - - target_mac = self._port_info[target_port].mac - assert target_mac, 'Target port %d triggered but not learned' % target_port + def _target_set_trigger(self, device): + assert self._devices.contains(device), 'Target device %s is not expected' % device.mac + port_trigger = device.port.port_no is not None + if port_trigger: + assert device.port.active, 'Target port %d is not active' % device.port.port_no if not self._system_active: - LOGGER.warning('Target port %d ignored, system not active', target_port) + LOGGER.warning('Target device %s ignored, system is not active', device.mac) return False - if self._port_info[target_port].host: - LOGGER.debug('Target port %d already triggered', target_port) + if device.host: + LOGGER.debug('Target device %s already triggered', device.mac) return False if not self.run_tests: - LOGGER.debug('Target port %d trigger suppressed', target_port) + LOGGER.debug('Target device %s trigger suppressed', device.mac) return False try: - group_name = self.network.device_group_for(target_mac) - gateway = self._activate_device_group(group_name, target_port) + group_name = self.network.device_group_for(device.mac) + device.group = group_name + gateway = self._activate_device_group(device) if gateway.activated: - LOGGER.debug('Target port %d trigger ignored b/c activated gateway', target_port) + LOGGER.debug('Target device %s trigger ignored b/c activated gateway', device.mac) return False except Exception as e: - LOGGER.error('Target port %d target trigger error %s', target_port, str(e)) + LOGGER.error('Target device %s target trigger error %s', device.mac, str(e)) if self.fail_mode: LOGGER.warning('Suppressing further tests due to failure.') self.run_tests = False return False - target = { - 'port': target_port, - 'group': group_name, - 'fake': gateway.fake_target, - 'port_set': gateway.port_set, - 'mac': target_mac - } - # Stops all DHCP response initially # Selectively enables dhcp response at ipaddr stage based on dhcp mode - gateway.stop_dhcp_response(target_mac) - gateway.attach_target(target_port, target) - + gateway.stop_dhcp_response(device.mac) + gateway.attach_target(device) + device.gateway = gateway try: self.run_count += 1 - new_host = connected_host.ConnectedHost(self, gateway, target, self.config) - self._port_info[target_port].host = new_host - self._port_info[target_port].gateway = gateway - LOGGER.info('Target port %d registered %s', target_port, target_mac) + new_host = connected_host.ConnectedHost(self, device, self.config) + device.host = new_host new_host.register_dhcp_ready_listener(self._dhcp_ready_listener) new_host.initialize() - self._direct_port_traffic(target_mac, target_port, target) + if port_trigger: + target = { + 'port': device.port.port_no, + 'group': group_name, + 'fake': gateway.fake_target, + 'port_set': gateway.port_set, + 'mac': device.mac + } + self._direct_port_traffic(device.mac, device.port.port_no, target) return True except Exception as e: - self.target_set_error(target_port, e) + self.target_set_error(device, e) def _get_test_list(self, test_file, test_list): no_test = self.config.get('no_test', False) @@ -438,127 +495,101 @@ def _get_test_list(self, test_file, test_list): line = file.readline() return test_list - def allocate_test_port(self, target_port): - """Get the test port for the given target_port""" - gateway = self._port_info[target_port].gateway - return gateway.allocate_test_port() - - def release_test_port(self, target_port, test_port): - """Release the given test port""" - gateway = self._port_info[target_port].gateway - return gateway.release_test_port(test_port) - - def _activate_device_group(self, group_name, target_port): - if group_name in self._device_groups: - existing = self._device_groups[group_name] - LOGGER.debug('Gateway for existing device group %s is %s', group_name, existing.name) + def _activate_device_group(self, device): + group_name = device.group + group_devices = self._devices.get_by_group(group_name) + existing_gateways = {device.gateway for device in group_devices if device.gateway} + if existing_gateways: + existing = existing_gateways.pop() + LOGGER.info('Gateway for existing device group %s is %s', group_name, existing) return existing - set_num = self._find_gateway_set(target_port) + + set_num = self._find_gateway_set(device) LOGGER.info('Gateway for device group %s not found, initializing base %d...', - group_name, set_num) + device.group, set_num) gateway = gateway_manager.Gateway(self, group_name, set_num, self.network) - self._gateway_sets[set_num] = group_name - self._device_groups[group_name] = gateway try: gateway.initialize() except Exception: LOGGER.error('Cleaning up from failed gateway initialization') - LOGGER.debug('Clearing target %s gateway group %s for %s', - target_port, set_num, group_name) - del self._gateway_sets[set_num] - del self._device_groups[group_name] + LOGGER.debug('Clearing %s gateway group %s for %s', + device, set_num, group_name) + self.gateway_sets.add(set_num) raise return gateway - def ip_notify(self, state, target, gateway_set, exception=None): + def ip_notify(self, state, target, gateway, exception=None): """Handle a DHCP / Static IP notification""" if exception: assert not target, 'unexpected exception with target' - LOGGER.error('IP exception for gw%02d: %s', gateway_set, exception) + LOGGER.error('IP exception for %s: %s', gateway, exception) LOGGER.exception(exception) - self._terminate_gateway_set(gateway_set) + self._terminate_gateway_set(gateway) return target_mac, target_ip, delta_sec = target['mac'], target['ip'], target['delta'] - LOGGER.info('IP notify %s is %s on gw%02d (%s/%d)', target_mac, - target_ip, gateway_set, state, delta_sec) + LOGGER.info('IP notify %s is %s on %s (%s/%d)', target_mac, + target_ip, gateway, state, delta_sec) if not target_mac: LOGGER.warning('IP target mac missing') return - self._target_mac_ip[target_mac] = target_ip - host = self._get_host_from_mac(target_mac) - if host: - self._ip_info[host] = (state, target, gateway_set) - host.ip_notify(target_ip, state, delta_sec) - self._check_and_activate_gateway(host) - - def _get_host_from_mac(self, mac): - if mac not in self._mac_port_map: - return None - return self._port_info[self._mac_port_map[mac]].host - - def _get_port_hosts(self): - return list({p: i.host for p, i in self._port_info.items() if i.host}.items()) - - def _get_running_ports(self): - return [p for p, i in self._port_info.items() if i.host] + device = self._devices.get(target_mac) + device.ip_info.ip_addr = target_ip + device.ip_info.state = state + device.ip_info.delta_sec = delta_sec + if device and device.host: + device.host.ip_notify(target_ip, state, delta_sec) + self._check_and_activate_gateway(device) def _get_active_ports(self): - return [p for p, i in self._port_info.items() if i.active] + return [p for p in self._ports.values() if p.active] - def _check_and_activate_gateway(self, host): + def _check_and_activate_gateway(self, device): # Host ready to be activated and DHCP happened / Static IP - if host not in self._ip_info or host not in self._dhcp_ready: + ip_info = device.ip_info + if not ip_info.ip_addr or not device.dhcp_ready: return - state, target, gateway_set = self._ip_info[host] - target_mac, target_ip, delta_sec = target['mac'], target['ip'], target['delta'] - (gateway, ready_devices) = self._should_activate_target(target_mac, target_ip, gateway_set) + (gateway, ready_devices) = self._should_activate_target(device) if not ready_devices: return - if ready_devices is True: - self._get_host_from_mac(target_mac).trigger(state, target_ip=target_ip, - delta_sec=delta_sec) + device.host.trigger(ip_info.state, target_ip=ip_info.ip_addr, + delta_sec=ip_info.delta_sec) else: - self._activate_gateway(state, gateway, ready_devices, delta_sec) + self._activate_gateway(ip_info.state, gateway, ready_devices, ip_info.delta_sec) - def _dhcp_ready_listener(self, host): - self._dhcp_ready.add(host) - self._check_and_activate_gateway(host) + def _dhcp_ready_listener(self, device): + device.dhcp_ready = True + self._check_and_activate_gateway(device) def _activate_gateway(self, state, gateway, ready_devices, delta_sec): gateway.activate() if len(ready_devices) > 1: state = 'group' delta_sec = -1 - for ready_mac in ready_devices: - LOGGER.info('IP activating target %s', ready_mac) - ready_host = self._get_host_from_mac(ready_mac) - ready_ip = self._target_mac_ip[ready_mac] - triggered = ready_host.trigger(state, target_ip=ready_ip, delta_sec=delta_sec) - assert triggered, 'host %s not triggered' % ready_mac - - def _should_activate_target(self, target_mac, target_ip, gateway_set): - target_host = self._get_host_from_mac(target_mac) - if not target_host: - LOGGER.warning('DHCP targets missing %s', target_mac) + for device in ready_devices: + LOGGER.info('IP activating target %s', device) + target_ip, delta_sec = device.ip_info.ip_addr, device.ip_info.delta_sec + triggered = device.host.trigger(state, target_ip=target_ip, delta_sec=delta_sec) + assert triggered, 'Device %s not triggered' % device + + def _should_activate_target(self, device): + if not device.host: + LOGGER.warning('DHCP targets missing %s', device) return False, False - - group_name = self._gateway_sets[gateway_set] - gateway = self._device_groups[group_name] - + gateway, group_name = device.gateway, device.group if gateway.activated: LOGGER.info('DHCP activation group %s already activated', group_name) return gateway, True - if not target_host.notify_activate(): - LOGGER.info('DHCP device %s ignoring spurious notify', target_mac) + if not device.host.notify_activate(): + LOGGER.info('DHCP device %s ignoring spurious notify', device) return gateway, False - ready_devices = gateway.target_ready(target_mac) + ready_devices = gateway.target_ready(device) group_size = self.network.device_group_size(group_name) remaining = group_size - len(ready_devices) @@ -566,30 +597,27 @@ def _should_activate_target(self, target_mac, target_ip, gateway_set): LOGGER.info('DHCP waiting for %d additional members of group %s', remaining, group_name) return gateway, False - hosts = map(self._get_host_from_mac, ready_devices) - ready_trigger = all(map(lambda host: host.trigger_ready(), hosts)) + ready_trigger = all(map(lambda host: device.host.trigger_ready(), ready_devices)) if not ready_trigger: LOGGER.info('DHCP device group %s not ready to trigger', group_name) return gateway, False return gateway, ready_devices - def _terminate_gateway_set(self, gateway_set): - assert gateway_set in self._gateway_sets, 'Gateway set %s not found' - group_name = self._gateway_sets[gateway_set] - gateway = self._device_groups[group_name] - ports = [target['port'] for target in gateway.get_targets()] - LOGGER.info('Terminating gateway group %s set %s, ports %s', group_name, gateway_set, ports) - for target_port in ports: - self.target_set_error(target_port, DaqException('terminated')) - - def _find_gateway_set(self, target_port): - if target_port not in self._gateway_sets: - return target_port - for entry in range(1, self.MAX_GATEWAYS): - if entry not in self._gateway_sets: - return entry - raise Exception('Could not allocate open gateway set') + def _terminate_gateway_set(self, gateway): + gateway_devices = self._devices.get_by_gateway(gateway) + assert gateway_devices, '%s not found' % gateway + LOGGER.info('Terminating %s', gateway) + for device in gateway_devices: + self.target_set_error(device, DaqException('terminated')) + + def _find_gateway_set(self, device): + if not self.gateway_sets: + raise Exception('Could not allocate open gateway set') + if device.port.port_no in self.gateway_sets: + self.gateway_sets.remove(device.port.port_no) + return device.port.port_no + return self.gateway_sets.pop() @staticmethod def ping_test(src, dst, src_addr=None): @@ -608,36 +636,34 @@ def ping_test(src, dst, src_addr=None): LOGGER.info('Test ping failure: %s', e) return False - def target_set_error(self, target_port, exception): - """Handle an error in the target port set""" - running = bool(target_port in self._port_info and self._port_info[target_port].host) - LOGGER.error('Target port %d running %s exception: %s', target_port, running, exception) + def target_set_error(self, device, exception): + """Handle an error in the target set""" + running = bool(device.host) + LOGGER.error('Target device %s running %s exception: %s', device, running, exception) LOGGER.exception(exception) if running: - target_host = self._port_info[target_port].host - target_host.record_result(target_host.test_name, exception=exception) - self.target_set_complete(target_port, str(exception)) + device.host.record_result(device.host.test_name, exception=exception) + self.target_set_complete(device, str(exception)) else: stack = ''.join( traceback.format_exception(etype=type(exception), value=exception, tb=exception.__traceback__)) - self._target_set_finalize(target_port, + self._target_set_finalize(device, {'exception': {'exception': str(exception), 'traceback': stack}}, str(exception)) - self._detach_gateway(target_port) + self._detach_gateway(device) - def target_set_complete(self, target_port, reason): + def target_set_complete(self, device, reason): """Handle completion of a target_set""" - target_host = self._port_info[target_port].host - self._target_set_finalize(target_port, target_host.results, reason) - self._target_set_cancel(target_port) + self._target_set_finalize(device, device.host.results, reason) + self._target_set_cancel(device) - def _target_set_finalize(self, target_port, result_set, reason): - results = self._combine_result_set(target_port, result_set) - LOGGER.info('Target port %d finalize: %s (%s)', target_port, results, reason) + def _target_set_finalize(self, device, result_set, reason): + results = self._combine_result_set(device, result_set) + LOGGER.info('Target device %s finalize: %s (%s)', device, results, reason) if self.result_log: - self.result_log.write('%02d: %s\n' % (target_port, results)) + self.result_log.write('%s: %s\n' % (device, results)) self.result_log.flush() suppress_tests = self.fail_mode or self.result_linger @@ -646,49 +672,48 @@ def _target_set_finalize(self, target_port, result_set, reason): self.run_tests = False if self.result_linger: self._linger_exit = 1 - self._result_sets[target_port] = result_set + self._result_sets[device] = result_set - def _target_set_cancel(self, target_port): - target_host = self._port_info[target_port].host + def _target_set_cancel(self, device): + target_host = device.host if target_host: - self._port_info[target_port].host = None - target_mac = self._port_info[target_port].mac - del self._mac_port_map[target_mac] - target_gateway = self._port_info[target_port].gateway - LOGGER.info('Target port %d cancel %s (#%d/%s).', - target_port, target_mac, self.run_count, self.run_limit) - results = self._combine_result_set(target_port, self._result_sets.get(target_port)) + device.host = None + target_gateway = device.gateway + target_port = device.port.port_no + LOGGER.info('Target device %s cancel (#%d/%s).', device.mac, self.run_count, + self.run_limit) + + results = self._combine_result_set(device, self._result_sets.get(device)) this_result_linger = results and self.result_linger target_gateway_linger = target_gateway and target_gateway.result_linger if target_gateway_linger or this_result_linger: - LOGGER.warning('Target port %d result_linger: %s', target_port, results) - self._activate_port(target_port) + LOGGER.warning('Target device %s result_linger: %s', device.mac, results) + if target_port: + self._activate_port(target_port) target_gateway.result_linger = True else: - self._direct_port_traffic(target_mac, target_port, None) + if target_port: + self._direct_port_traffic(device.mac, target_port, None) target_host.terminate('_target_set_cancel', trigger=False) if target_gateway: - self._detach_gateway(target_port) + self._detach_gateway(device) if self.run_limit and self.run_count >= self.run_limit and self.run_tests: LOGGER.warning('Suppressing future tests because run limit reached.') self.run_tests = False if self.single_shot and self.run_tests: LOGGER.warning('Suppressing future tests because test done in single shot.') self.run_tests = False - LOGGER.info('Remaining target sets: %s', self._get_running_ports()) + self._devices.remove(device) + LOGGER.info('Remaining target sets: %s', self._devices.get_triggered_devices()) - def _detach_gateway(self, target_port): - target_gateway = self._port_info[target_port].gateway + def _detach_gateway(self, device): + target_gateway = device.gateway if not target_gateway: return - self._port_info[target_port].gateway = None - target_mac = self._port_info[target_port].mac - if not target_gateway.detach_target(target_port): - LOGGER.info('Retiring target gateway %s, %s, %s, %s', - target_port, target_mac, target_gateway.name, target_gateway.port_set) - group_name = self.network.device_group_for(target_mac) - del self._device_groups[group_name] - del self._gateway_sets[target_gateway.port_set] + device.gateway = None + if not target_gateway.detach_target(device): + LOGGER.info('Retiring %s. Last device: %s', target_gateway, device) + self.gateway_sets.add(target_gateway.port_set) target_gateway.terminate() def monitor_stream(self, *args, **kwargs): @@ -720,7 +745,7 @@ def _combine_result_set(self, set_key, result_sets): exp_msg = result.get('exception') status = exp_msg if exp_msg else code if name != 'fail' else not code if status != 0: - results.append('%02d:%s:%s' % (set_key, name, status)) + results.append('%s:%s:%s' % (set_key, name, status)) return results def finalize(self): @@ -742,7 +767,7 @@ def _base_config_changed(self, new_config): self._MODULE_CONFIG) self._base_config = self._load_base_config(register=False) self._publish_runner_config(self._base_config) - _ = [host.reload_config() for _, host in self._get_port_hosts()] + _ = [device.host.reload_config() for device in self._devices.get_triggered_devices()] def _load_base_config(self, register=True): base = self.configurator.load_and_merge({}, self.config.get('base_conf')) diff --git a/testing/test_aux.out b/testing/test_aux.out index 40961f6726..d29d4f2093 100644 --- a/testing/test_aux.out +++ b/testing/test_aux.out @@ -69,9 +69,9 @@ RESULT skip connection.network.ntp_support No NTP packets received. RESULT skip connection.network.ntp_update Not enough NTP packets received. RESULT pass connection.mac_oui Manufacturer: Google found for address 3c:5a:b4:1e:8f:0a dhcp requests 1 1 1 1 -01: [] -02: ['02:ping:TimeoutError'] -03: [] +3c5ab41e8f0a: [] +3c5ab41e8f0b: ['3c5ab41e8f0b:ping:TimeoutError'] +9a02571e8f01: [] arp.txt dp_port_acls.yaml dp_sec_port_1_acl.yaml @@ -216,26 +216,9 @@ Host: X.X.X.X () Status: Up Host: X.X.X.X () Ports: 47808/closed/udp//bacnet/// Ignored State: closed (3) Redacted docs diff No report diff -01: ['01:ping:Exception'] -02: ['02:hold:Exception'] -03: ['03:hold:DaqException', '03:ping:ValueError'] -inst/gw01/nodes/gw01/activate.log -inst/gw02/nodes/gw02/activate.log -inst/gw03/nodes/gw03/activate.log -inst/run-port-01/nodes/fail01/activate.log -inst/run-port-01/nodes/nmap01/activate.log -inst/run-port-01/nodes/pass01/activate.log -inst/run-port-01/nodes/ping01/activate.log -inst/run-port-02/nodes/fail02/activate.log -inst/run-port-02/nodes/hold02/activate.log -inst/run-port-02/nodes/nmap02/activate.log -inst/run-port-02/nodes/pass02/activate.log -inst/run-port-02/nodes/ping02/activate.log -inst/run-port-03/nodes/fail03/activate.log -inst/run-port-03/nodes/hold03/activate.log -inst/run-port-03/nodes/nmap03/activate.log -inst/run-port-03/nodes/pass03/activate.log -inst/run-port-03/nodes/ping03/activate.log +9a02571e8f01: ['9a02571e8f01:ping:Exception'] +9a02571e8f02: ['9a02571e8f02:hold:Exception'] +9a02571e8f03: ['9a02571e8f03:hold:DaqException', '9a02571e8f03:ping:ValueError'] Enough port disconnects: 1 -01: ['01:hold:DaqException'] +9a02571e8f00: ['9a02571e8f00:hold:DaqException'] Done with tests diff --git a/testing/test_aux.sh b/testing/test_aux.sh index cb710cf070..fe5acb5e0a 100755 --- a/testing/test_aux.sh +++ b/testing/test_aux.sh @@ -36,7 +36,9 @@ EOF function capture_test_results { module_name=$1 - fgrep -h RESULT inst/run-port-*/nodes/$module_name*/tmp/report.txt | tee -a $TEST_RESULTS + for mac in 9a02571e8f01 3c5ab41e8f0b 3c5ab41e8f0a; do + fgrep -h RESULT inst/run-$mac/nodes/$module_name*/tmp/report.txt | tee -a $TEST_RESULTS + done } # Setup an instance test site @@ -105,45 +107,46 @@ echo %%%%%%%%%%%%%%%%%%%%%%%%% Starting aux test run cmd/run -s # Capture RESULT lines from ping activation logs (not generated report). -fgrep -h RESULT inst/run-port*/nodes/ping*/activate.log \ +for mac in 9a02571e8f01 3c5ab41e8f0b 3c5ab41e8f0a; do + fgrep -h RESULT inst/run-$mac/nodes/ping*/activate.log \ | sed -e 's/\s*\(%%.*\)*$//' | tee -a $TEST_RESULTS - +done # Add the RESULT lines from all aux test report files. capture_test_results bacext capture_test_results macoui capture_test_results tls -capture_test_results password -capture_test_results discover -capture_test_results network +capture_test_results passwo # test host names are truncated to 6 characters +capture_test_results discov +capture_test_results networ capture_test_results ntp # Capture peripheral logs -more inst/run-port-*/scans/ip_triggers.txt | cat -dhcp_done=$(fgrep done inst/run-port-01/scans/ip_triggers.txt | wc -l) -dhcp_long=$(fgrep long inst/run-port-01/scans/ip_triggers.txt | wc -l) +more inst/run-*/scans/ip_triggers.txt | cat +dhcp_done=$(fgrep done inst/run-9a02571e8f01/scans/ip_triggers.txt | wc -l) +dhcp_long=$(fgrep long inst/run-9a02571e8f01/scans/ip_triggers.txt | wc -l) echo dhcp requests $((dhcp_done > 1)) $((dhcp_done < 3)) \ $((dhcp_long >= 1)) $((dhcp_long < 4)) | tee -a $TEST_RESULTS sort inst/result.log | tee -a $TEST_RESULTS # Show partial logs from each test head -20 inst/gw*/nodes/gw*/activate.log -head -20 inst/run-port-*/nodes/*/activate.log -haed -20 inst/run-port-*/nodes/*/tmp/report.txt -ls inst/run-port-01/finish/fail01/ | tee -a $TEST_RESULTS +head -20 inst/run-*/nodes/*/activate.log +head -20 inst/run-*/nodes/*/tmp/report.txt +ls inst/run-9a02571e8f01/finish/fail*/ | tee -a $TEST_RESULTS # Add the port-01 and port-02 module config into the file echo port-01 module_config modules | tee -a $TEST_RESULTS -jq .modules inst/run-port-01/nodes/ping01/tmp/module_config.json | tee -a $TEST_RESULTS +jq .modules inst/run-9a02571e8f01/nodes/ping*/tmp/module_config.json | tee -a $TEST_RESULTS echo port-02 module_config modules | tee -a $TEST_RESULTS -jq .modules inst/run-port-02/nodes/ping02/tmp/module_config.json | tee -a $TEST_RESULTS +jq .modules inst/run-3c5ab41e8f0b/nodes/ping*/tmp/module_config.json | tee -a $TEST_RESULTS # Add a lovely snake and a lizard into this file for testing device/type mappings. -cat inst/run-port-03/nodes/ping03/tmp/snake.txt | tee -a $TEST_RESULTS -cat inst/run-port-03/nodes/ping03/tmp/lizard.txt | tee -a $TEST_RESULTS +cat inst/run-3c5ab41e8f0a/nodes/ping*/tmp/snake.txt | tee -a $TEST_RESULTS +cat inst/run-3c5ab41e8f0a/nodes/ping*/tmp/lizard.txt | tee -a $TEST_RESULTS # Add the results for cloud tests into a different file, since cloud tests may not run if # our test environment isn't set up correctly. See bin/test_daq for more insight. -fgrep -h RESULT inst/run-port-*/nodes/udmi*/tmp/report.txt | tee -a $GCP_RESULTS +fgrep -h RESULT inst/run-*/nodes/udmi*/tmp/report.txt | tee -a $GCP_RESULTS for num in 1 2 3; do echo docker logs daq-faux-$num @@ -175,9 +178,9 @@ cat < local/system.yaml --- include: config/system/multi.conf fail_module: - ping_01: finalize - hold_02: initialize - ping_03: callback + ping_9a02571e8f01: finalize + hold_9a02571e8f02: initialize + ping_9a02571e8f03: callback EOF function kill_gateway { @@ -188,20 +191,20 @@ function kill_gateway { } # Check that killing the dhcp monitor aborts the run. -MARKER=inst/run-port-03/nodes/hold03/activate.log +MARKER=inst/run-9a02571e8f03/nodes/hold*/activate.log monitor_marker $MARKER "kill_gateway gw03" echo %%%%%%%%%%%%%%%%%%%%%%%%% Starting hold test run +rm -r inst/run-* cmd/run -k -s finish_hook=bin/dump_network cat inst/result.log | sort | tee -a $TEST_RESULTS -find inst/ -name activate.log | sort | tee -a $TEST_RESULTS -head inst/run-port-*/nodes/nmap*/activate.log -head inst/run-port-*/finish/nmap*/* - -tcpdump -en -r inst/run-port-01/scans/test_nmap.pcap icmp or arp +head inst/run-*/nodes/nmap*/activate.log +head inst/run-*/finish/nmap*/* +tcpdump -en -r inst/run-9a02571e8f01/scans/test_nmap.pcap icmp or arp +echo %%%%%%%%%%%%%%%%%%%%%%%%% Running port toggle test # Check port toggling does not cause a shutdown cat < local/system.yaml --- @@ -210,7 +213,8 @@ port_flap_timeout_sec: 10 port_debounce_sec: 0 EOF monitor_log "Port 1 dpid 2 is now active" "sudo ifconfig faux down;sleep 5; sudo ifconfig faux up" -monitor_log "Target port 1 test hold running" "sudo ifconfig faux down" +monitor_log "Target device 9a02571e8f00 test hold running" "sudo ifconfig faux down" +rm -r inst/run-* cmd/run -s -k disconnections=$(cat inst/cmdrun.log | grep "Port 1 dpid 2 is now inactive" | wc -l) echo Enough port disconnects: $((disconnections >= 2)) | tee -a $TEST_RESULTS diff --git a/testing/test_base.out b/testing/test_base.out index 7ad42c6cce..15bcb7af64 100644 --- a/testing/test_base.out +++ b/testing/test_base.out @@ -2,7 +2,7 @@ Running testing/test_base.sh Base Tests %%%%%%%%%%%%%%%%%%%%%% Base tests DAQ result code 1 -01: ['01:hold:DaqException'] +9a02571e8f00: ['9a02571e8f00:hold:DaqException'] # Device 9a02571e8f00, XXX to XXX Sample device description. @@ -124,18 +124,18 @@ terminated %%%%%%%%%%%%%%%%%%%%%% Telnet fail DAQ result code 1 -01: ['01:hold:DaqException'] +9a02571e8f00: ['9a02571e8f00:hold:DaqException'] |fail|security.ports.nmap|Other|Other|Some disallowed ports are open: 23| security.ports.nmap RESULT fail security.ports.nmap Some disallowed ports are open: 23 %%%%%%%%%%%%%%%%%%%%%% Default MUD DAQ result code 0 -01: [] +9a02571e8f00: [] |pass|security.ports.nmap|Other|Other|Only allowed ports found open.| security.ports.nmap RESULT pass security.ports.nmap Only allowed ports found open. %%%%%%%%%%%%%%%%%%%%%% External switch tests -02: [] +9a02571e8f00: [] dp_id: 1 dp_id: 4886718345 Switch test with target 192.0.2.138:2 @@ -146,22 +146,22 @@ switch ping 2 %%%%%%%%%%%%%%%%%%%%%% Alt switch tests XXX faucet.valve INFO DPID 1 (0x1) pri L2 learned on Port 1 9a:02:57:1e:8f:00 (L2 type 0x0800, L2 dst ff:ff:ff:ff:ff:ff, L3 src X.X.X.X, L3 dst 255.255.255.255) Port 1 VLAN 1002 (1 hosts total) %%%%%%%%%%%%%%%%%%%%%% Mud profile tests -result open 01: [] 02: [] 03: [] +result open 9a02571e8f01: [] 9a02571e8f02: [] 9a02571e8f03: [] device open 1 1 1 cntrlr open 1 1 1 -result base 01: [] 02: [] 03: [] +result base 9a02571e8f01: [] 9a02571e8f02: [] 9a02571e8f03: [] device base 1 1 0 cntrlr base 1 1 0 -result todev 01: ['01:ping:1'] 02: ['02:ping:1'] 03: [] +result todev 9a02571e8f01: ['9a02571e8f01:ping:1'] 9a02571e8f02: ['9a02571e8f02:ping:1'] 9a02571e8f03: [] device todev 0 0 0 cntrlr todev 0 0 0 -result frdev 01: [] 02: ['02:ping:1'] 03: [] +result frdev 9a02571e8f01: [] 9a02571e8f02: ['9a02571e8f02:ping:1'] 9a02571e8f03: [] device frdev 1 0 0 cntrlr frdev 1 0 0 -result none 01: ['01:ping:1'] 02: ['02:ping:1'] 03: [] +result none 9a02571e8f01: ['9a02571e8f01:ping:1'] 9a02571e8f02: ['9a02571e8f02:ping:1'] 9a02571e8f03: [] device none 0 0 0 cntrlr none 0 0 0 -result star 01: [] 02: [] 03: [] +result star 9a02571e8f01: [] 9a02571e8f02: [] 9a02571e8f03: [] device star 1 1 1 cntrlr star 1 1 0 %%%%%%%%%%%%%%%%%%%%%% Done with tests diff --git a/testing/test_base.sh b/testing/test_base.sh index cf4bf4aed7..e16bf2470b 100755 --- a/testing/test_base.sh +++ b/testing/test_base.sh @@ -15,7 +15,7 @@ bin/build_proto check || exit 1 echo %%%%%%%%%%%%%%%%%%%%%% Base tests | tee -a $TEST_RESULTS rm -f local/system.yaml local/system.conf # Check that bringing down the trunk interface terminates DAQ. -MARKER=inst/run-port-01/nodes/hold01/activate.log +MARKER=inst/run-9a02571e8f00/nodes/hold*/activate.log monitor_marker $MARKER "sudo ip link set pri-eth1 down" cmd/run -b -k -s site_path=inst/tmp_site echo DAQ result code $? | tee -a $TEST_RESULTS @@ -30,7 +30,7 @@ docker rmi daqf/test_hold:latest # Check case of missing image cmd/run -s -k interfaces.faux.opts=telnet echo DAQ result code $? | tee -a $TEST_RESULTS cat inst/result.log | tee -a $TEST_RESULTS -cat inst/run-port-01/nodes/nmap01/activate.log +cat inst/run-9a02571e8f00/nodes/nmap01/activate.log fgrep 'security.ports.nmap' inst/reports/report_9a02571e8f00_*.md | tee -a $TEST_RESULTS DAQ_TARGETS=test_hold cmd/build @@ -40,16 +40,16 @@ cmd/run -s interfaces.faux.opts=telnet device_specs=resources/device_specs/simpl echo DAQ result code $? | tee -a $TEST_RESULTS cat inst/result.log | tee -a $TEST_RESULTS fgrep 'security.ports.nmap' inst/reports/report_9a02571e8f00_*.md | tee -a $TEST_RESULTS -cat inst/run-port-01/nodes/nmap01/activate.log +cat inst/run-9a02571e8f00/nodes/nmap01/activate.log echo %%%%%%%%%%%%%%%%%%%%%% External switch tests | tee -a $TEST_RESULTS cp config/system/ext.yaml local/system.yaml cmd/run -s cat inst/result.log | tee -a $TEST_RESULTS fgrep dp_id inst/faucet.yaml | tee -a $TEST_RESULTS -fgrep -i switch inst/run-port-02/nodes/ping02/activate.log | tee -a $TEST_RESULTS -cat -vet inst/run-port-02/nodes/ping02/activate.log -count=$(fgrep icmp_seq=5 inst/run-port-02/nodes/ping02/activate.log | wc -l) +fgrep -i switch inst/run-9a02571e8f00/nodes/ping*/activate.log | tee -a $TEST_RESULTS +cat -vet inst/run-9a02571e8f00/nodes/ping*/activate.log +count=$(fgrep icmp_seq=5 inst/run-9a02571e8f00/nodes/ping*/activate.log | wc -l) echo switch ping $count | tee -a $TEST_RESULTS echo %%%%%%%%%%%%%%%%%%%%%% Alt switch tests | tee -a $TEST_RESULTS @@ -61,11 +61,11 @@ echo %%%%%%%%%%%%%%%%%%%%%% Mud profile tests | tee -a $TEST_RESULTS rm -f local/system.yaml cp config/system/muddy.conf local/system.conf -device_traffic="tcpdump -en -r inst/run-port-01/scans/monitor.pcap port 47808" +device_traffic="tcpdump -en -r inst/run-9a02571e8f01/scans/monitor.pcap port 47808" device_bcast="$device_traffic and ether broadcast" device_ucast="$device_traffic and ether dst 9a:02:57:1e:8f:02" device_xcast="$device_traffic and ether dst 9a:02:57:1e:8f:03" -cntrlr_traffic="tcpdump -en -r inst/run-port-02/scans/monitor.pcap port 47808" +cntrlr_traffic="tcpdump -en -r inst/run-9a02571e8f02/scans/monitor.pcap port 47808" cntrlr_bcast="$cntrlr_traffic and ether broadcast" cntrlr_ucast="$cntrlr_traffic and ether dst 9a:02:57:1e:8f:01" cntrlr_xcast="$cntrlr_traffic and ether dst 9a:02:57:1e:8f:03" @@ -83,7 +83,7 @@ function test_mud { ucast=$($cntrlr_ucast | wc -l) xcast=$($cntrlr_xcast | wc -l) echo cntrlr $type $(($bcast > 2)) $(($ucast > 2)) $(($xcast > 0)) | tee -a $TEST_RESULTS - more inst/run-port-*/nodes/*/activate.log | cat + more inst/run-*/nodes/*/activate.log | cat } test_mud open diff --git a/testing/test_dhcp.out b/testing/test_dhcp.out index 31148ca8b6..06ba950d71 100644 --- a/testing/test_dhcp.out +++ b/testing/test_dhcp.out @@ -1,10 +1,10 @@ Running testing/test_dhcp.sh DHCP Tests -01: [] -02: ['02:acquire:TimeoutError'] -03: [] -04: [] -05: [] +9a02571e8f01: [] +9a02571e8f02: ['9a02571e8f02:acquire:TimeoutError'] +9a02571e8f03: [] +9a02571e8f04: [] +9a02571e8f05: [] Device 1 ip triggers: 1 0 Device 2 ip triggers: 0 0 Device 3 long ip triggers: 1 diff --git a/testing/test_dhcp.sh b/testing/test_dhcp.sh index 44a7272be5..30f15ec103 100755 --- a/testing/test_dhcp.sh +++ b/testing/test_dhcp.sh @@ -69,7 +69,7 @@ cat inst/result.log | sort | tee -a $TEST_RESULTS for iface in $(seq 1 5); do intf_mac=9a:02:57:1e:8f:0$iface - ip_file=inst/run-port-0$iface/scans/ip_triggers.txt + ip_file=inst/run-9a02571e8f0$iface/scans/ip_triggers.txt cat $ip_file ip_triggers=$(fgrep done $ip_file | wc -l) long_triggers=$(fgrep long $ip_file | wc -l) @@ -80,9 +80,9 @@ for iface in $(seq 1 5); do echo "Device $iface num of ips: $num_ips" | tee -a $TEST_RESULTS elif [ $iface == 4 ]; then echo "Device $iface ip triggers: $(((ip_triggers + long_triggers) >= 4))" | tee -a $TEST_RESULTS - subnet_ip=$(fgrep "ip notification 192.168" inst/run-port-*/nodes/ipaddr*/activate.log | wc -l) - subnet2_ip=$(fgrep "ip notification 10.255.255" inst/run-port-*/nodes/ipaddr*/activate.log | wc -l) - subnet3_ip=$(fgrep "ip notification 172.16.0" inst/run-port-*/nodes/ipaddr*/activate.log | wc -l) + subnet_ip=$(fgrep "ip notification 192.168" inst/run-*/nodes/ipaddr*/activate.log | wc -l) + subnet2_ip=$(fgrep "ip notification 10.255.255" inst/run-*/nodes/ipaddr*/activate.log | wc -l) + subnet3_ip=$(fgrep "ip notification 172.16.0" inst/run-*/nodes/ipaddr*/activate.log | wc -l) echo "Device $iface subnet 1 ip: $subnet_ip subnet 2 ip: $subnet2_ip subnet 3 ip: $subnet3_ip" | tee -a $TEST_RESULTS elif [ $iface == 3 ]; then echo "Device $iface long ip triggers: $((long_triggers > 0))" | tee -a $TEST_RESULTS diff --git a/testing/test_many.sh b/testing/test_many.sh index bea177acb5..60537a9561 100755 --- a/testing/test_many.sh +++ b/testing/test_many.sh @@ -86,15 +86,16 @@ cat inst/result.log results=$(fgrep [] inst/result.log | wc -l) timeouts=$(fgrep "ipaddr:TimeoutError" inst/result.log | wc -l) ipaddr_timeouts=$(fgrep "ipaddr:TimeoutError" inst/result.log | wc -l) -ip_notifications=$(fgrep "ip notification" inst/run-port-*/nodes/ipaddr*/activate.log | wc -l) -alternate_subnet_ip=$(fgrep "ip notification 192.168" inst/run-port-*/nodes/ipaddr*/activate.log | wc -l) - -cat inst/run-port-*/scans/ip_triggers.txt -static_ips=$(fgrep nope inst/run-port-*/scans/ip_triggers.txt | wc -l) -ntp_traffic=$(fgrep "RESULT fail base.startup.ntp" inst/run-port-*/nodes/ping*/tmp/result_lines.txt | wc -l) -dns_traffic=$(fgrep "RESULT fail base.startup.dns" inst/run-port-*/nodes/ping*/tmp/result_lines.txt | wc -l) -more inst/run-port-*/nodes/ping*/activate.log | cat -more inst/run-port-*/nodes/ipaddr*/activate.log | cat +ip_notifications=$(fgrep "ip notification" inst/run-*/nodes/ipaddr*/activate.log | wc -l) +alternate_subnet_ip=$(fgrep "ip notification 192.168" inst/run-*/nodes/ipaddr*/activate.log | wc -l) + +cat inst/run-*/scans/ip_triggers.txt +static_ips=$(fgrep nope inst/run-*/scans/ip_triggers.txt | wc -l) +ntp_traffic=$(fgrep "RESULT fail base.startup.ntp" inst/run-*/nodes/ping*/tmp/result_lines.txt | wc -l) +dns_traffic=$(fgrep "RESULT fail base.startup.dns" inst/run-*/nodes/ping*/tmp/result_lines.txt | wc -l) + +more inst/run-*/nodes/ping*/activate.log | cat +more inst/run-*/nodes/ipaddr*/activate.log | cat echo Found $results clean runs, $timeouts timeouts, and $static_ips static_ips. echo ipaddr had $ip_notifications notifications and $ipaddr_timeouts timeouts. diff --git a/testing/test_utils.sh b/testing/test_utils.sh index 26d0e1331d..9d06feea09 100644 --- a/testing/test_utils.sh +++ b/testing/test_utils.sh @@ -120,9 +120,9 @@ function run_test { test -d $conf_dir || (mkdir -p $conf_dir; echo sleep 30 >> $cmd_file) done cmd/run -s - cat inst/run-port-*/nodes/ping*${socket_file} | tee -a $TEST_RESULTS - cat inst/run-port-*/nodes/ping*${bacnet_file} | tee -a $TEST_RESULTS - more inst/run-port-*/nodes/ping*/activate.log | cat + cat inst/run-*/nodes/ping*${socket_file} | tee -a $TEST_RESULTS + cat inst/run-*/nodes/ping*${bacnet_file} | tee -a $TEST_RESULTS + more inst/run-*/nodes/ping*/activate.log | cat more inst/gw0*/nodes/gw0*/activate.log | cat more inst/gw0*/dhcp_monitor.txt | cat } diff --git a/testing/unit/test_runner.py b/testing/unit/test_runner.py index bdc0f813a1..eb729be9be 100644 --- a/testing/unit/test_runner.py +++ b/testing/unit/test_runner.py @@ -43,16 +43,14 @@ def setUp(self): def test_reap_stale_ports(self): """Test port flap timeout config override""" self.runner.target_set_error = MagicMock() - self.runner._port_info = {1: PortInfo()} + device = self.runner._devices.new_device("0000000000") self.runner._reap_stale_ports() self.runner.target_set_error.assert_not_called() ConnectedHost.__init__ = MagicMock(return_value=None) host = ConnectedHost() host.test_name = "test_test" - port_info = PortInfo() - port_info.flapping_start = time.time() - 1 - port_info.host = host - self.runner._port_info = {1: port_info} + device.port.flapping_start = time.time() - 1 + device.host = host host.get_port_flap_timeout = MagicMock(return_value=10000) self.runner._reap_stale_ports() From 8f385a0dcf1cd0d8f0a96528cb429a9603057628 Mon Sep 17 00:00:00 2001 From: henry54809 Date: Tue, 11 Aug 2020 13:05:04 -0700 Subject: [PATCH 081/212] fix gcp combine report test (#587) --- bin/python/combine_reports_from_date_range.py | 2 +- daq/runner.py | 2 +- testing/test_many.sh | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/bin/python/combine_reports_from_date_range.py b/bin/python/combine_reports_from_date_range.py index 9b304c7e76..ea3de4d17a 100644 --- a/bin/python/combine_reports_from_date_range.py +++ b/bin/python/combine_reports_from_date_range.py @@ -63,7 +63,7 @@ def _get_local_reports(device, reports_dir, start, end, count): json_files = [f for f in os.listdir(reports_dir) if report_re.match(f)] json_files.sort(reverse=True) # Match gcp behavior if count and len(json_files) > count: - json_files = json_files[len(json_files) - count:] + json_files = json_files[:count] for json_file in json_files: timestamp = report_re.search(json_file).group(1) start_str = _iso_to_fname(start) diff --git a/daq/runner.py b/daq/runner.py index 8e416d554d..0f6fc94097 100644 --- a/daq/runner.py +++ b/daq/runner.py @@ -544,7 +544,7 @@ def ip_notify(self, state, target, gateway, exception=None): self._check_and_activate_gateway(device) def _get_active_ports(self): - return [p for p in self._ports.values() if p.active] + return [p.port_no for p in self._ports.values() if p.active] def _check_and_activate_gateway(self, device): # Host ready to be activated and DHCP happened / Static IP diff --git a/testing/test_many.sh b/testing/test_many.sh index 60537a9561..9cab9672fe 100755 --- a/testing/test_many.sh +++ b/testing/test_many.sh @@ -125,7 +125,11 @@ echo Redacted soak diff | tee -a $TEST_RESULTS if [ -f "$gcp_cred" ]; then mv inst/reports/combo_*.md out/report_local.md - echo Pulling reports from gcp... + echo Pulling reports from gcp... from $start_time to $end_time + echo \n******Local reports****** + ls -l inst/reports/report_9a02571e8f05*.md + echo *************************\n + bin/combine_reports device=9a:02:57:1e:8f:05 from_time=$start_time to_time=$end_time \ count=2 from_gcp=true echo GCP results diff | tee -a $GCP_RESULTS From 784dc6a16a1e6d4b22023f7eb40ae37b644f8750 Mon Sep 17 00:00:00 2001 From: henry54809 Date: Wed, 12 Aug 2020 10:56:30 -0700 Subject: [PATCH 082/212] Feature/vlan trigger (#588) --- config/faucet/faucet_alt-switch.yaml | 4 +- config/system/alt.yaml | 3 ++ config/system/default.yaml | 2 + daq/runner.py | 14 ++++++- firebase/public/protos.hash | 2 +- firebase/public/protos.html | 34 ++++++++++++++++ libs/proto/system_config_pb2.py | 59 ++++++++++++++++++++++------ proto/system_config.proto | 8 ++++ testing/test_base.out | 3 +- testing/test_base.sh | 5 ++- 10 files changed, 115 insertions(+), 19 deletions(-) diff --git a/config/faucet/faucet_alt-switch.yaml b/config/faucet/faucet_alt-switch.yaml index 876cf786fd..059233aa4b 100644 --- a/config/faucet/faucet_alt-switch.yaml +++ b/config/faucet/faucet_alt-switch.yaml @@ -3,9 +3,9 @@ dps: dp_id: 2 interfaces: 1: - native_vlan: 1001 - 2: native_vlan: 1002 + 2: + native_vlan: 1001 3: native_vlan: 1003 4: diff --git a/config/system/alt.yaml b/config/system/alt.yaml index e429326c7f..ab1f6945f2 100644 --- a/config/system/alt.yaml +++ b/config/system/alt.yaml @@ -18,3 +18,6 @@ interfaces: faux: opts: port: 2 + +# use vlan trigger +run_trigger_type: VLAN diff --git a/config/system/default.yaml b/config/system/default.yaml index 538ae0090f..3b3746f6f4 100644 --- a/config/system/default.yaml +++ b/config/system/default.yaml @@ -41,6 +41,8 @@ finish_hook: bin/dump_network # topology hook: executed when device topology changes topology_hook: bin/dump_network +run_trigger_type: PORT + # usi url for DAQ to connect to usi_setup: url: localhost:5000 diff --git a/daq/runner.py b/daq/runner.py index 0f6fc94097..388721cce6 100644 --- a/daq/runner.py +++ b/daq/runner.py @@ -133,6 +133,7 @@ def __init__(self, config): self.faucet_events = None self.single_shot = config.get('single_shot', False) self.fail_mode = config.get('fail_mode', False) + self.run_trigger_type = config.get('run_trigger_type', 'PORT') self.run_tests = True self.stream_monitor = None self.exception = None @@ -242,7 +243,10 @@ def _handle_faucet_events(self): return (dpid, port, target_mac, vid) = self.faucet_events.as_port_learn(event) if dpid and port and vid: - self._handle_port_learn(dpid, port, vid, target_mac) + if self.run_trigger_type == "PORT": + self._handle_port_learn(dpid, port, vid, target_mac) + elif self.run_trigger_type == "VLAN" and self.network.is_system_port(dpid, port): + self._handle_device_learn(vid, target_mac) return (dpid, restart_type) = self.faucet_events.as_config_change(event) if dpid is not None: @@ -305,6 +309,14 @@ def _handle_port_learn(self, dpid, port, vid, target_mac): else: LOGGER.debug('Port %s dpid %s learned %s (ignored)', port, dpid, target_mac) + def _handle_device_learn(self, vid, target_mac): + LOGGER.info('%s learned on vid %s', target_mac, vid) + if not self._devices.get(target_mac): + device = self._devices.new_device(target_mac) + else: + device = self._devices.get(target_mac) + self._target_set_trigger(device) + def _queue_callback(self, callback): with self._callback_lock: LOGGER.debug('Register callback') diff --git a/firebase/public/protos.hash b/firebase/public/protos.hash index 5d00da6704..1a7397bfdf 100644 --- a/firebase/public/protos.hash +++ b/firebase/public/protos.hash @@ -1 +1 @@ -1f6e7f1a7517da9544eab551d16b7bd650c2d4ae proto/system_config.proto +5e1ffaa617230e5ae366e281660ff3d38056d6e6 proto/system_config.proto diff --git a/firebase/public/protos.html b/firebase/public/protos.html index b0929b316a..637d0b9911 100644 --- a/firebase/public/protos.html +++ b/firebase/public/protos.html @@ -203,6 +203,10 @@

        Table of Contents

        +
      • + ERunTriggerType +
      • +
      @@ -489,6 +493,13 @@

      DaqConfig

      USI url

      + + run_trigger_type + RunTriggerType + +

      Configures events that trigger a DAQ run

      + + @@ -730,6 +741,29 @@

      USISetup

      +

      RunTriggerType

      +

      + + + + + + + + + + + + + + + + + + + +
      NameNumberDescription
      PORT0

      VLAN1

      + diff --git a/libs/proto/system_config_pb2.py b/libs/proto/system_config_pb2.py index 89ee2bc00b..716bb36fe3 100644 --- a/libs/proto/system_config_pb2.py +++ b/libs/proto/system_config_pb2.py @@ -3,6 +3,7 @@ import sys _b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf.internal import enum_type_wrapper from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection @@ -19,9 +20,34 @@ package='', syntax='proto3', serialized_options=None, - serialized_pb=_b('\n\x1d\x64\x61q/proto/system_config.proto\"\x9d\x08\n\tDaqConfig\x12\x18\n\x10site_description\x18\x01 \x01(\t\x12\x18\n\x10monitor_scan_sec\x18\x02 \x01(\x05\x12\x1b\n\x13\x64\x65\x66\x61ult_timeout_sec\x18\x03 \x01(\x05\x12\x12\n\nsettle_sec\x18& \x01(\x05\x12\x11\n\tbase_conf\x18\x04 \x01(\t\x12\x11\n\tsite_path\x18\x05 \x01(\t\x12\x1f\n\x17initial_dhcp_lease_time\x18\x06 \x01(\t\x12\x17\n\x0f\x64hcp_lease_time\x18\x07 \x01(\t\x12\x19\n\x11\x64hcp_response_sec\x18\' \x01(\x05\x12\x1e\n\x16long_dhcp_response_sec\x18\x08 \x01(\x05\x12\"\n\x0cswitch_setup\x18\t \x01(\x0b\x32\x0c.SwitchSetup\x12\x12\n\nhost_tests\x18\x10 \x01(\t\x12\x13\n\x0b\x62uild_tests\x18$ \x01(\x08\x12\x11\n\trun_limit\x18\x11 \x01(\x05\x12\x11\n\tfail_mode\x18\x12 \x01(\x08\x12\x13\n\x0bsingle_shot\x18\" \x01(\x08\x12\x15\n\rresult_linger\x18\x13 \x01(\x08\x12\x0f\n\x07no_test\x18\x14 \x01(\x08\x12\x11\n\tkeep_hold\x18( \x01(\x08\x12\x14\n\x0c\x64\x61q_loglevel\x18\x15 \x01(\t\x12\x18\n\x10mininet_loglevel\x18\x16 \x01(\t\x12\x13\n\x0b\x66inish_hook\x18# \x01(\t\x12\x10\n\x08gcp_cred\x18\x17 \x01(\t\x12\x11\n\tgcp_topic\x18\x18 \x01(\t\x12\x13\n\x0bschema_path\x18\x19 \x01(\t\x12\x11\n\tmud_files\x18\x1a \x01(\t\x12\x14\n\x0c\x64\x65vice_specs\x18\x1b \x01(\t\x12\x13\n\x0btest_config\x18\x1c \x01(\t\x12\x19\n\x11port_debounce_sec\x18\x1d \x01(\x05\x12\x15\n\rtopology_hook\x18\x1e \x01(\t\x12\x17\n\x0f\x64\x65vice_template\x18\x1f \x01(\t\x12\x14\n\x0csite_reports\x18 \x01(\t\x12\x1f\n\x17run_data_retention_days\x18! \x01(\x02\x12.\n\ninterfaces\x18% \x03(\x0b\x32\x1a.DaqConfig.InterfacesEntry\x12/\n\x0b\x66\x61il_module\x18/ \x03(\x0b\x32\x1a.DaqConfig.FailModuleEntry\x12\x1d\n\x15port_flap_timeout_sec\x18\x30 \x01(\x05\x12\x1c\n\tusi_setup\x18\x31 \x01(\x0b\x32\t.USISetup\x1a=\n\x0fInterfacesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x19\n\x05value\x18\x02 \x01(\x0b\x32\n.Interface:\x02\x38\x01\x1a\x31\n\x0f\x46\x61ilModuleEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"0\n\x08USISetup\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x17\n\x0frpc_timeout_sec\x18\x02 \x01(\x05\"\xf4\x01\n\x0bSwitchSetup\x12\x11\n\tctrl_intf\x18\t \x01(\t\x12\x0f\n\x07ip_addr\x18\x0b \x01(\t\x12\x13\n\x0buplink_port\x18\r \x01(\x05\x12\x0f\n\x07lo_port\x18\x0e \x01(\x05\x12\x10\n\x08\x61lt_port\x18\x10 \x01(\x05\x12\x0f\n\x07lo_addr\x18\x12 \x01(\t\x12\x11\n\tmods_addr\x18\x14 \x01(\t\x12\x0f\n\x07of_dpid\x18) \x01(\t\x12\x11\n\tdata_intf\x18* \x01(\t\x12\x0e\n\x06\x65xt_br\x18+ \x01(\t\x12\r\n\x05model\x18, \x01(\t\x12\x10\n\x08username\x18- \x01(\t\x12\x10\n\x08password\x18. \x01(\t\"\'\n\tInterface\x12\x0c\n\x04opts\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05\x62\x06proto3') + serialized_pb=_b('\n\x1d\x64\x61q/proto/system_config.proto\"\xc8\x08\n\tDaqConfig\x12\x18\n\x10site_description\x18\x01 \x01(\t\x12\x18\n\x10monitor_scan_sec\x18\x02 \x01(\x05\x12\x1b\n\x13\x64\x65\x66\x61ult_timeout_sec\x18\x03 \x01(\x05\x12\x12\n\nsettle_sec\x18& \x01(\x05\x12\x11\n\tbase_conf\x18\x04 \x01(\t\x12\x11\n\tsite_path\x18\x05 \x01(\t\x12\x1f\n\x17initial_dhcp_lease_time\x18\x06 \x01(\t\x12\x17\n\x0f\x64hcp_lease_time\x18\x07 \x01(\t\x12\x19\n\x11\x64hcp_response_sec\x18\' \x01(\x05\x12\x1e\n\x16long_dhcp_response_sec\x18\x08 \x01(\x05\x12\"\n\x0cswitch_setup\x18\t \x01(\x0b\x32\x0c.SwitchSetup\x12\x12\n\nhost_tests\x18\x10 \x01(\t\x12\x13\n\x0b\x62uild_tests\x18$ \x01(\x08\x12\x11\n\trun_limit\x18\x11 \x01(\x05\x12\x11\n\tfail_mode\x18\x12 \x01(\x08\x12\x13\n\x0bsingle_shot\x18\" \x01(\x08\x12\x15\n\rresult_linger\x18\x13 \x01(\x08\x12\x0f\n\x07no_test\x18\x14 \x01(\x08\x12\x11\n\tkeep_hold\x18( \x01(\x08\x12\x14\n\x0c\x64\x61q_loglevel\x18\x15 \x01(\t\x12\x18\n\x10mininet_loglevel\x18\x16 \x01(\t\x12\x13\n\x0b\x66inish_hook\x18# \x01(\t\x12\x10\n\x08gcp_cred\x18\x17 \x01(\t\x12\x11\n\tgcp_topic\x18\x18 \x01(\t\x12\x13\n\x0bschema_path\x18\x19 \x01(\t\x12\x11\n\tmud_files\x18\x1a \x01(\t\x12\x14\n\x0c\x64\x65vice_specs\x18\x1b \x01(\t\x12\x13\n\x0btest_config\x18\x1c \x01(\t\x12\x19\n\x11port_debounce_sec\x18\x1d \x01(\x05\x12\x15\n\rtopology_hook\x18\x1e \x01(\t\x12\x17\n\x0f\x64\x65vice_template\x18\x1f \x01(\t\x12\x14\n\x0csite_reports\x18 \x01(\t\x12\x1f\n\x17run_data_retention_days\x18! \x01(\x02\x12.\n\ninterfaces\x18% \x03(\x0b\x32\x1a.DaqConfig.InterfacesEntry\x12/\n\x0b\x66\x61il_module\x18/ \x03(\x0b\x32\x1a.DaqConfig.FailModuleEntry\x12\x1d\n\x15port_flap_timeout_sec\x18\x30 \x01(\x05\x12\x1c\n\tusi_setup\x18\x31 \x01(\x0b\x32\t.USISetup\x12)\n\x10run_trigger_type\x18\x32 \x01(\x0e\x32\x0f.RunTriggerType\x1a=\n\x0fInterfacesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x19\n\x05value\x18\x02 \x01(\x0b\x32\n.Interface:\x02\x38\x01\x1a\x31\n\x0f\x46\x61ilModuleEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"0\n\x08USISetup\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x17\n\x0frpc_timeout_sec\x18\x02 \x01(\x05\"\xf4\x01\n\x0bSwitchSetup\x12\x11\n\tctrl_intf\x18\t \x01(\t\x12\x0f\n\x07ip_addr\x18\x0b \x01(\t\x12\x13\n\x0buplink_port\x18\r \x01(\x05\x12\x0f\n\x07lo_port\x18\x0e \x01(\x05\x12\x10\n\x08\x61lt_port\x18\x10 \x01(\x05\x12\x0f\n\x07lo_addr\x18\x12 \x01(\t\x12\x11\n\tmods_addr\x18\x14 \x01(\t\x12\x0f\n\x07of_dpid\x18) \x01(\t\x12\x11\n\tdata_intf\x18* \x01(\t\x12\x0e\n\x06\x65xt_br\x18+ \x01(\t\x12\r\n\x05model\x18, \x01(\t\x12\x10\n\x08username\x18- \x01(\t\x12\x10\n\x08password\x18. \x01(\t\"\'\n\tInterface\x12\x0c\n\x04opts\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05*$\n\x0eRunTriggerType\x12\x08\n\x04PORT\x10\x00\x12\x08\n\x04VLAN\x10\x01\x62\x06proto3') ) +_RUNTRIGGERTYPE = _descriptor.EnumDescriptor( + name='RunTriggerType', + full_name='RunTriggerType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='PORT', index=0, number=0, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='VLAN', index=1, number=1, + serialized_options=None, + type=None), + ], + containing_type=None, + serialized_options=None, + serialized_start=1470, + serialized_end=1506, +) +_sym_db.RegisterEnumDescriptor(_RUNTRIGGERTYPE) + +RunTriggerType = enum_type_wrapper.EnumTypeWrapper(_RUNTRIGGERTYPE) +PORT = 0 +VLAN = 1 @@ -58,8 +84,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=975, - serialized_end=1036, + serialized_start=1018, + serialized_end=1079, ) _DAQCONFIG_FAILMODULEENTRY = _descriptor.Descriptor( @@ -95,8 +121,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1038, - serialized_end=1087, + serialized_start=1081, + serialized_end=1130, ) _DAQCONFIG = _descriptor.Descriptor( @@ -365,6 +391,13 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='run_trigger_type', full_name='DaqConfig.run_trigger_type', index=37, + number=50, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], @@ -378,7 +411,7 @@ oneofs=[ ], serialized_start=34, - serialized_end=1087, + serialized_end=1130, ) @@ -415,8 +448,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1089, - serialized_end=1137, + serialized_start=1132, + serialized_end=1180, ) @@ -530,8 +563,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1140, - serialized_end=1384, + serialized_start=1183, + serialized_end=1427, ) @@ -568,8 +601,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1386, - serialized_end=1425, + serialized_start=1429, + serialized_end=1468, ) _DAQCONFIG_INTERFACESENTRY.fields_by_name['value'].message_type = _INTERFACE @@ -579,10 +612,12 @@ _DAQCONFIG.fields_by_name['interfaces'].message_type = _DAQCONFIG_INTERFACESENTRY _DAQCONFIG.fields_by_name['fail_module'].message_type = _DAQCONFIG_FAILMODULEENTRY _DAQCONFIG.fields_by_name['usi_setup'].message_type = _USISETUP +_DAQCONFIG.fields_by_name['run_trigger_type'].enum_type = _RUNTRIGGERTYPE DESCRIPTOR.message_types_by_name['DaqConfig'] = _DAQCONFIG DESCRIPTOR.message_types_by_name['USISetup'] = _USISETUP DESCRIPTOR.message_types_by_name['SwitchSetup'] = _SWITCHSETUP DESCRIPTOR.message_types_by_name['Interface'] = _INTERFACE +DESCRIPTOR.enum_types_by_name['RunTriggerType'] = _RUNTRIGGERTYPE _sym_db.RegisterFileDescriptor(DESCRIPTOR) DaqConfig = _reflection.GeneratedProtocolMessageType('DaqConfig', (_message.Message,), dict( diff --git a/proto/system_config.proto b/proto/system_config.proto index 5c334e728b..9b3c60c54c 100644 --- a/proto/system_config.proto +++ b/proto/system_config.proto @@ -117,6 +117,14 @@ message DaqConfig { // USI url USISetup usi_setup = 49; + + // Configures events that trigger a DAQ run + RunTriggerType run_trigger_type = 50; +} + +enum RunTriggerType { + PORT = 0; + VLAN = 1; } /** diff --git a/testing/test_base.out b/testing/test_base.out index 15bcb7af64..c0d73a57fe 100644 --- a/testing/test_base.out +++ b/testing/test_base.out @@ -144,7 +144,8 @@ Switch test with target 192.0.2.138:2 Monolog processing base.switch.ping... switch ping 2 %%%%%%%%%%%%%%%%%%%%%% Alt switch tests -XXX faucet.valve INFO DPID 1 (0x1) pri L2 learned on Port 1 9a:02:57:1e:8f:00 (L2 type 0x0800, L2 dst ff:ff:ff:ff:ff:ff, L3 src X.X.X.X, L3 dst 255.255.255.255) Port 1 VLAN 1002 (1 hosts total) +XXX runner INFO 9a:02:57:1e:8f:00 learned on vid 1001 +9a02571e8f00: ['9a02571e8f00:ping:1'] %%%%%%%%%%%%%%%%%%%%%% Mud profile tests result open 9a02571e8f01: [] 9a02571e8f02: [] 9a02571e8f03: [] device open 1 1 1 diff --git a/testing/test_base.sh b/testing/test_base.sh index e16bf2470b..79f45c5886 100755 --- a/testing/test_base.sh +++ b/testing/test_base.sh @@ -55,8 +55,9 @@ echo switch ping $count | tee -a $TEST_RESULTS echo %%%%%%%%%%%%%%%%%%%%%% Alt switch tests | tee -a $TEST_RESULTS cp config/system/alt.yaml local/system.yaml # TODO: Replace this with proper test once VLAN-triggers are added. -timeout 120s cmd/run -s -fgrep 'Port 1 9a:02:57:1e:8f:00' inst/faucet.log | redact | tee -a $TEST_RESULTS +timeout 1200s cmd/run -s +fgrep '9a:02:57:1e:8f:00 learned on vid 1001' inst/cmdrun.log | head -1 | redact | tee -a $TEST_RESULTS +cat inst/result.log | tee -a $TEST_RESULTS # ping test should fail since there are no dhcp packets captured echo %%%%%%%%%%%%%%%%%%%%%% Mud profile tests | tee -a $TEST_RESULTS rm -f local/system.yaml cp config/system/muddy.conf local/system.conf From e4fccdf4de991e44d694f117c5a27575cb4e992e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Aug 2020 13:14:44 -0700 Subject: [PATCH 083/212] Update dependency firebase-admin to v9.1.0 (#594) --- firebase/functions/package-lock.json | 264 +++++++++++++++------------ firebase/functions/package.json | 2 +- 2 files changed, 145 insertions(+), 121 deletions(-) diff --git a/firebase/functions/package-lock.json b/firebase/functions/package-lock.json index 05444c0d9b..af650e00d5 100644 --- a/firebase/functions/package-lock.json +++ b/firebase/functions/package-lock.json @@ -14,32 +14,32 @@ "integrity": "sha512-88h74TMQ6wXChPA6h9Q3E1Jg6TkTHep2+k63OWg3s0ozyGVMeY+TTOti7PFPzq5RhszQPQOoCi59es4MaRvgCw==" }, "@firebase/component": { - "version": "0.1.16", - "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.1.16.tgz", - "integrity": "sha512-FvffvFN0LWgv1H/FIyruTECOL69Dhy+JfwoTq+mV39V8Mz9lNpo41etonL5AOr7KmXxYJVbNwkx0L9Ei88i7JA==", + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.1.17.tgz", + "integrity": "sha512-/tN5iLcFp9rdpTfCJPfQ/o2ziGHlDxOzNx6XD2FoHlu4pG/PPGu+59iRfQXIowBGhxcTGD/l7oJhZEY/PVg0KQ==", "requires": { - "@firebase/util": "0.2.50", + "@firebase/util": "0.3.0", "tslib": "^1.11.1" } }, "@firebase/database": { - "version": "0.6.7", - "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.6.7.tgz", - "integrity": "sha512-vm0ch2zNSoHfXWnDG6WVjf0p/BdXOMBL1lAfkGu3DYH/Rkl4p97x57w0WNOURNfL4GY2LIqScSYKCidV7jqTog==", + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.6.10.tgz", + "integrity": "sha512-Hc8zIPAroIbAoRe6xFCI5oFHubcHKoDsbYE3J5G1/BhT6DnEUSoLgx8kJ2npybVSCVyb8BvsD6swh17DGEz+0g==", "requires": { "@firebase/auth-interop-types": "0.1.5", - "@firebase/component": "0.1.16", - "@firebase/database-types": "0.5.1", + "@firebase/component": "0.1.17", + "@firebase/database-types": "0.5.2", "@firebase/logger": "0.2.6", - "@firebase/util": "0.2.50", + "@firebase/util": "0.3.0", "faye-websocket": "0.11.3", "tslib": "^1.11.1" } }, "@firebase/database-types": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.5.1.tgz", - "integrity": "sha512-onQxom1ZBYBJ648w/VNRzUewovEDAH7lvnrrpCd69ukkyrMk6rGEO/PQ9BcNEbhlNtukpsqRS0oNOFlHs0FaSA==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-0.5.2.tgz", + "integrity": "sha512-ap2WQOS3LKmGuVFKUghFft7RxXTyZTDr0Xd8y2aqmWsbJVjgozi0huL/EUMgTjGFrATAjcf2A7aNs8AKKZ2a8g==", "requires": { "@firebase/app-types": "0.6.1" } @@ -50,9 +50,9 @@ "integrity": "sha512-KIxcUvW/cRGWlzK9Vd2KB864HlUnCfdTH0taHE0sXW5Xl7+W68suaeau1oKNEqmc3l45azkd4NzXTCWZRZdXrw==" }, "@firebase/util": { - "version": "0.2.50", - "resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.2.50.tgz", - "integrity": "sha512-vFE6+Jfc25u0ViSpFxxq0q5s+XmuJ/y7CL3ud79RQe+WLFFg+j0eH1t23k0yNSG9vZNM7h3uHRIXbV97sYLAyw==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.3.0.tgz", + "integrity": "sha512-GTwC+FSLeCPc44/TXCDReNQ5FPRIS5cb8Gr1XcD1TgiNBOvmyx61Om2YLwHp2GnN++6m6xmwmXARm06HOukATA==", "requires": { "tslib": "^1.11.1" } @@ -74,6 +74,12 @@ "teeny-request": "^7.0.0" }, "dependencies": { + "bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==", + "optional": true + }, "duplexify": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.1.tgz", @@ -87,9 +93,9 @@ } }, "gaxios": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.0.4.tgz", - "integrity": "sha512-97NmFuMETFQh6gqPUxkqjxRMjmY8aRKRMphIkgO/b90AbCt5wAVuXsp8oWjIXlLN2pIK/fsXD8edcM7ULkFMLg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.1.0.tgz", + "integrity": "sha512-DDTn3KXVJJigtz+g0J3vhcfbDbKtAroSTxauWsdnP57sM5KZ3d2c/3D9RKFJ86s43hfw6WULg6TXYw/AYiBlpA==", "optional": true, "requires": { "abort-controller": "^3.0.0", @@ -100,19 +106,19 @@ } }, "gcp-metadata": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.1.0.tgz", - "integrity": "sha512-r57SV28+olVsflPlKyVig3Muo/VDlcsObMtvDGOEtEJXj+DDE8bEl0coIkXh//hbkSDTvo+f5lbihZOndYXQQQ==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.1.4.tgz", + "integrity": "sha512-5J/GIH0yWt/56R3dNaNWPGQ/zXsZOddYECfJaqxFWgrZ9HC2Kvc5vl9upOgUUHKzURjAVf2N+f6tEJiojqXUuA==", "optional": true, "requires": { "gaxios": "^3.0.0", - "json-bigint": "^0.3.0" + "json-bigint": "^1.0.0" } }, "google-auth-library": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.0.5.tgz", - "integrity": "sha512-Wj31lfTm2yR4g3WfOOB1Am1tt478Xq9OvzTPQJi17tn/I9R5IcsxjANBsE93nYmxYxtwDedhOdIb8l3vSPG49Q==", + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.0.6.tgz", + "integrity": "sha512-fWYdRdg55HSJoRq9k568jJA1lrhg9i2xgfhVIMJbskUmbDpJGHsbv9l41DGhCDXM21F9Kn4kUwdysgxSYBYJUw==", "optional": true, "requires": { "arrify": "^2.0.0", @@ -136,9 +142,9 @@ } }, "gtoken": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.2.tgz", - "integrity": "sha512-lull70rHCTvRTmAt+R/6W5bTtx4MjHku7AwJwK5fGqhOmygcZud0nrZcX+QUNfBJwCzqy7S5i1Bc4NYnr5PMMA==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.3.tgz", + "integrity": "sha512-Nyd1wZCMRc2dj/mAD0LlfQLcAO06uKdpKJXvK85SGrF5+5+Bpfil9u/2aw35ltvEHjvl0h5FMKN5knEU+9JrOg==", "optional": true, "requires": { "gaxios": "^3.0.0", @@ -147,6 +153,15 @@ "mime": "^2.2.0" } }, + "json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "optional": true, + "requires": { + "bignumber.js": "^9.0.0" + } + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -176,9 +191,9 @@ } }, "@google-cloud/firestore": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-4.1.1.tgz", - "integrity": "sha512-HFy2OEOrYJ7jYUir90Kg7+AWM6fsFoWYiHiryoseHfkL9//AnXm2sn0CiaOhsTsxphc69G8LBBvUj6ws0QDa7g==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-4.2.0.tgz", + "integrity": "sha512-YCiKaTYCbXSoEvZ8cTmpgg4ebAvmFUOu3hj/aX+lHiOK7LsoFVi4jgNknogSqIiv04bxAysTBodpgn8XoZ4l5g==", "optional": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -187,18 +202,24 @@ }, "dependencies": { "@grpc/grpc-js": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.1.2.tgz", - "integrity": "sha512-k2u86Bkm/3xrjUaSWeIyzXScBt/cC8uE7BznR0cpueQi11R33W6qfJdMrkrsmSHirp5likR55JSXUrcWG6ybHA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.1.3.tgz", + "integrity": "sha512-HtOsk2YUofBcm1GkPqGzb6pwHhv+74eC2CUO229USIDKRtg30ycbZmqC+HdNtY3nHqoc9IgcRlntFgopyQoYCA==", "optional": true, "requires": { "semver": "^6.2.0" } }, + "bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==", + "optional": true + }, "gaxios": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.0.4.tgz", - "integrity": "sha512-97NmFuMETFQh6gqPUxkqjxRMjmY8aRKRMphIkgO/b90AbCt5wAVuXsp8oWjIXlLN2pIK/fsXD8edcM7ULkFMLg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.1.0.tgz", + "integrity": "sha512-DDTn3KXVJJigtz+g0J3vhcfbDbKtAroSTxauWsdnP57sM5KZ3d2c/3D9RKFJ86s43hfw6WULg6TXYw/AYiBlpA==", "optional": true, "requires": { "abort-controller": "^3.0.0", @@ -209,19 +230,19 @@ } }, "gcp-metadata": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.1.0.tgz", - "integrity": "sha512-r57SV28+olVsflPlKyVig3Muo/VDlcsObMtvDGOEtEJXj+DDE8bEl0coIkXh//hbkSDTvo+f5lbihZOndYXQQQ==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.1.4.tgz", + "integrity": "sha512-5J/GIH0yWt/56R3dNaNWPGQ/zXsZOddYECfJaqxFWgrZ9HC2Kvc5vl9upOgUUHKzURjAVf2N+f6tEJiojqXUuA==", "optional": true, "requires": { "gaxios": "^3.0.0", - "json-bigint": "^0.3.0" + "json-bigint": "^1.0.0" } }, "google-auth-library": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.0.5.tgz", - "integrity": "sha512-Wj31lfTm2yR4g3WfOOB1Am1tt478Xq9OvzTPQJi17tn/I9R5IcsxjANBsE93nYmxYxtwDedhOdIb8l3vSPG49Q==", + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.0.6.tgz", + "integrity": "sha512-fWYdRdg55HSJoRq9k568jJA1lrhg9i2xgfhVIMJbskUmbDpJGHsbv9l41DGhCDXM21F9Kn4kUwdysgxSYBYJUw==", "optional": true, "requires": { "arrify": "^2.0.0", @@ -236,9 +257,9 @@ } }, "google-gax": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-2.6.3.tgz", - "integrity": "sha512-hqY6H53Qmaku8rE8dGAM89RSUc1nc4JYG81whrVJRmDQZ2jhJK8AwCd3pJQ3V48rgp9xiWBzBQsyeaxnb3Eikw==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-2.7.0.tgz", + "integrity": "sha512-0dBATy8mMVlfOBrT85Q+NzBpZ4OJZUMrPI9wJULpiIDq2w1zlN30Duor+fQUcMEjanYEc72G58M4iUVve0jfXw==", "optional": true, "requires": { "@grpc/grpc-js": "~1.1.1", @@ -267,9 +288,9 @@ } }, "gtoken": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.2.tgz", - "integrity": "sha512-lull70rHCTvRTmAt+R/6W5bTtx4MjHku7AwJwK5fGqhOmygcZud0nrZcX+QUNfBJwCzqy7S5i1Bc4NYnr5PMMA==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.3.tgz", + "integrity": "sha512-Nyd1wZCMRc2dj/mAD0LlfQLcAO06uKdpKJXvK85SGrF5+5+Bpfil9u/2aw35ltvEHjvl0h5FMKN5knEU+9JrOg==", "optional": true, "requires": { "gaxios": "^3.0.0", @@ -278,6 +299,15 @@ "mime": "^2.2.0" } }, + "json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "optional": true, + "requires": { + "bignumber.js": "^9.0.0" + } + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -288,9 +318,9 @@ } }, "protobufjs": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.10.0.tgz", - "integrity": "sha512-Hdz1+CXkrlmGDKkP6DczxysdnUyUuhM1mjeaydnBxOcjxQPbJldLZ8eGE1gX0UTsgv+0QkFfn6dioo5yt9XORw==", + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.10.1.tgz", + "integrity": "sha512-pb8kTchL+1Ceg4lFd5XUpK8PdWacbvV5SK2ULH2ebrYtl4GjJmS24m6CKME67jzV53tbJxHlnNOSqQHbTsR9JQ==", "optional": true, "requires": { "@protobufjs/aspromise": "^1.1.2", @@ -325,9 +355,9 @@ } }, "@google-cloud/paginator": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-3.0.2.tgz", - "integrity": "sha512-kXK+Dbz4pNvv8bKU80Aw5HsIdgOe0WuMTd8/fI6tkANUxzvJOVJQQRsWVqcHSWK2RXHPTA9WBniUCwY6gAJDXw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-3.0.4.tgz", + "integrity": "sha512-fKI+jYQdV1F9jtG6tSRro3ilNSeBWVmTzxc8Z0kiPRXcj8eshh9fiF8TtxfDefyUKgTdWgHpzGBwLbZ/OGikJg==", "optional": true, "requires": { "arrify": "^2.0.0", @@ -346,9 +376,9 @@ "optional": true }, "@google-cloud/promisify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-2.0.1.tgz", - "integrity": "sha512-82EQzwrNauw1fkbUSr3f+50Bcq7g4h0XvLOk8C5e9ABkXYHei7ZPi9tiMMD7Vh3SfcdH97d1ibJ3KBWp2o1J+w==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-2.0.2.tgz", + "integrity": "sha512-EvuabjzzZ9E2+OaYf+7P9OAiiwbTxKYL0oGLnREQd+Su2NTQBpomkdlkBowFvyWsaV0d1sSGxrKpSNcrhPqbxg==", "optional": true }, "@google-cloud/pubsub": { @@ -527,39 +557,37 @@ } }, "@google-cloud/storage": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-5.1.2.tgz", - "integrity": "sha512-j2blsBVv6Tt5Z7ff6kOSIg5zVQPdlcTQh/4zMb9h7xMj4ekwndQA60le8c1KEa+Y6SR3EM6ER2AvKYK53P7vdQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-5.2.0.tgz", + "integrity": "sha512-zxHXZajtVA0Qx9IOnDUDb76mtKn5M20LKV/phmnVos7foozG9YZ6yYod90pRC/GgP3eOgxNYdt6KQcapssPsFw==", "optional": true, "requires": { - "@google-cloud/common": "^3.0.0", + "@google-cloud/common": "^3.3.0", "@google-cloud/paginator": "^3.0.0", "@google-cloud/promisify": "^2.0.0", "arrify": "^2.0.0", "compressible": "^2.0.12", "concat-stream": "^2.0.0", - "date-and-time": "^0.13.0", + "date-and-time": "^0.14.0", "duplexify": "^3.5.0", "extend": "^3.0.2", "gaxios": "^3.0.0", - "gcs-resumable-upload": "^3.0.0", + "gcs-resumable-upload": "^3.1.0", "hash-stream-validation": "^0.2.2", "mime": "^2.2.0", "mime-types": "^2.0.8", "onetime": "^5.1.0", "p-limit": "^3.0.1", "pumpify": "^2.0.0", - "readable-stream": "^3.4.0", "snakeize": "^0.1.0", "stream-events": "^1.0.1", - "through2": "^4.0.0", "xdg-basedir": "^4.0.0" }, "dependencies": { "gaxios": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.0.4.tgz", - "integrity": "sha512-97NmFuMETFQh6gqPUxkqjxRMjmY8aRKRMphIkgO/b90AbCt5wAVuXsp8oWjIXlLN2pIK/fsXD8edcM7ULkFMLg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.1.0.tgz", + "integrity": "sha512-DDTn3KXVJJigtz+g0J3vhcfbDbKtAroSTxauWsdnP57sM5KZ3d2c/3D9RKFJ86s43hfw6WULg6TXYw/AYiBlpA==", "optional": true, "requires": { "abort-controller": "^3.0.0", @@ -568,26 +596,6 @@ "is-stream": "^2.0.0", "node-fetch": "^2.3.0" } - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "optional": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "through2": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", - "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", - "optional": true, - "requires": { - "readable-stream": "3" - } } } }, @@ -947,9 +955,9 @@ "optional": true }, "date-and-time": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-0.13.1.tgz", - "integrity": "sha512-/Uge9DJAT+s+oAcDxtBhyR8+sKjUnZbYmyhbmWjTHNtX7B7oWD8YyYdeXcBRbwSj6hVvj+IQegJam7m7czhbFw==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-0.14.0.tgz", + "integrity": "sha512-0wY8b90XjQkRxv3XGT8k1ffyDQOf4+T+2hiWp7rwYgoEn8OyYDsHZdnVrPlzxbwjLUY66mVBXr59eKOwpSV7lw==", "optional": true }, "debug": { @@ -1156,11 +1164,12 @@ } }, "firebase-admin": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-9.0.0.tgz", - "integrity": "sha512-LP4xD+JxfEZ+e1kBIKT2kbDa9UFChwgL4488NexvTjhynNcJsKCGmawl2FMvZ2UPwXKgWBpLXJ07cYp6gk5lcw==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-9.1.0.tgz", + "integrity": "sha512-tGGREJpoRM/mbV/5bs/q9SQRZkVhxMMq1HIJEzSEh3mtz5hC9VtaCkuLt6chuAsqHMBoc1pvnrGTOC5nOme9VQ==", "requires": { - "@firebase/database": "^0.6.0", + "@firebase/database": "^0.6.10", + "@firebase/database-types": "^0.5.2", "@google-cloud/firestore": "^4.0.0", "@google-cloud/storage": "^5.0.0", "@types/node": "^10.10.0", @@ -1170,9 +1179,9 @@ }, "dependencies": { "@types/node": { - "version": "10.17.27", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.27.tgz", - "integrity": "sha512-J0oqm9ZfAXaPdwNXMMgAhylw5fhmXkToJd06vuDUSAgEDZ/n/69/69UmyBZbc+zT34UnShuDSBqvim3SPnozJg==" + "version": "10.17.28", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.28.tgz", + "integrity": "sha512-dzjES1Egb4c1a89C7lKwQh8pwjYmlOAG9dW1pBgxEk57tMrLnssOfEthz8kdkNaBd7lIqQx7APm5+mZ619IiCQ==" } } }, @@ -1239,10 +1248,16 @@ "stream-events": "^1.0.4" }, "dependencies": { + "bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==", + "optional": true + }, "gaxios": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.0.4.tgz", - "integrity": "sha512-97NmFuMETFQh6gqPUxkqjxRMjmY8aRKRMphIkgO/b90AbCt5wAVuXsp8oWjIXlLN2pIK/fsXD8edcM7ULkFMLg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.1.0.tgz", + "integrity": "sha512-DDTn3KXVJJigtz+g0J3vhcfbDbKtAroSTxauWsdnP57sM5KZ3d2c/3D9RKFJ86s43hfw6WULg6TXYw/AYiBlpA==", "optional": true, "requires": { "abort-controller": "^3.0.0", @@ -1253,19 +1268,19 @@ } }, "gcp-metadata": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.1.0.tgz", - "integrity": "sha512-r57SV28+olVsflPlKyVig3Muo/VDlcsObMtvDGOEtEJXj+DDE8bEl0coIkXh//hbkSDTvo+f5lbihZOndYXQQQ==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.1.4.tgz", + "integrity": "sha512-5J/GIH0yWt/56R3dNaNWPGQ/zXsZOddYECfJaqxFWgrZ9HC2Kvc5vl9upOgUUHKzURjAVf2N+f6tEJiojqXUuA==", "optional": true, "requires": { "gaxios": "^3.0.0", - "json-bigint": "^0.3.0" + "json-bigint": "^1.0.0" } }, "google-auth-library": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.0.5.tgz", - "integrity": "sha512-Wj31lfTm2yR4g3WfOOB1Am1tt478Xq9OvzTPQJi17tn/I9R5IcsxjANBsE93nYmxYxtwDedhOdIb8l3vSPG49Q==", + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.0.6.tgz", + "integrity": "sha512-fWYdRdg55HSJoRq9k568jJA1lrhg9i2xgfhVIMJbskUmbDpJGHsbv9l41DGhCDXM21F9Kn4kUwdysgxSYBYJUw==", "optional": true, "requires": { "arrify": "^2.0.0", @@ -1289,9 +1304,9 @@ } }, "gtoken": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.2.tgz", - "integrity": "sha512-lull70rHCTvRTmAt+R/6W5bTtx4MjHku7AwJwK5fGqhOmygcZud0nrZcX+QUNfBJwCzqy7S5i1Bc4NYnr5PMMA==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.3.tgz", + "integrity": "sha512-Nyd1wZCMRc2dj/mAD0LlfQLcAO06uKdpKJXvK85SGrF5+5+Bpfil9u/2aw35ltvEHjvl0h5FMKN5knEU+9JrOg==", "optional": true, "requires": { "gaxios": "^3.0.0", @@ -1300,6 +1315,15 @@ "mime": "^2.2.0" } }, + "json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "optional": true, + "requires": { + "bignumber.js": "^9.0.0" + } + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -1729,9 +1753,9 @@ } }, "onetime": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", - "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "optional": true, "requires": { "mimic-fn": "^2.1.0" @@ -2120,9 +2144,9 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.2.0.tgz", - "integrity": "sha512-CYpGiFTUrmI6OBMkAdjSDM0k5h8SkkiTP4WAjQgDgNB1S3Ou9VBEvr6q0Kv2H1mMk7IWfxYGpMH5sd5AvcIV2Q==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.0.tgz", + "integrity": "sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ==", "optional": true }, "vary": { diff --git a/firebase/functions/package.json b/firebase/functions/package.json index 5eb365d0f8..46aabc7580 100644 --- a/firebase/functions/package.json +++ b/firebase/functions/package.json @@ -14,7 +14,7 @@ "dependencies": { "@google-cloud/pubsub": "2.3.0", "@google-cloud/iot": "1.8.0", - "firebase-admin": "9.0.0", + "firebase-admin": "9.1.0", "firebase-functions": "3.9.0", "extend": "3.0.2" }, From ba1324db9648b5c0945ab081f9cf425b8d5fb208 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Aug 2020 13:15:03 -0700 Subject: [PATCH 084/212] Update dependency io.grpc:grpc-protobuf to v1.31.1 (#592) --- usi/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usi/pom.xml b/usi/pom.xml index 7725680553..73fc30d26f 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -43,7 +43,7 @@ io.grpc grpc-protobuf - 1.31.0 + 1.31.1 io.grpc From 678cb21af6032b72acf184d95e636b91f4158dd1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Aug 2020 13:15:25 -0700 Subject: [PATCH 085/212] Update dependency io.grpc:grpc-netty-shaded to v1.31.1 (#591) --- usi/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usi/pom.xml b/usi/pom.xml index 73fc30d26f..a034a91001 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -38,7 +38,7 @@ io.grpc grpc-netty-shaded - 1.31.0 + 1.31.1 io.grpc From f0a8f06377d48b596f227a616d914bb58d1f1868 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Aug 2020 14:46:11 -0700 Subject: [PATCH 086/212] Update dependency io.grpc:grpc-bom to v1.31.1 (#590) --- usi/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usi/pom.xml b/usi/pom.xml index a034a91001..e5187df332 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -16,7 +16,7 @@ io.grpc grpc-bom - 1.31.0 + 1.31.1 pom import From 1ed4cb9a9c8fb4c0d1c35daabe3796598eed0ea7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Aug 2020 14:48:30 -0700 Subject: [PATCH 087/212] Update dependency org.apache.maven.plugins:maven-resources-plugin to v3.2.0 (#586) --- subset/switches/pom.xml | 2 +- usi/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subset/switches/pom.xml b/subset/switches/pom.xml index 23fec86bf1..18d7f9a8d6 100644 --- a/subset/switches/pom.xml +++ b/subset/switches/pom.xml @@ -47,7 +47,7 @@ maven-resources-plugin - 3.1.0 + 3.2.0 maven-compiler-plugin diff --git a/usi/pom.xml b/usi/pom.xml index e5187df332..dbe98f1cff 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -114,7 +114,7 @@ maven-resources-plugin - 3.1.0 + 3.2.0 maven-surefire-plugin From 040f96fd2e0b5f0d5c585d92e69489a158a2c2dd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 13 Aug 2020 16:03:53 -0700 Subject: [PATCH 088/212] Update dependency io.grpc:grpc-stub to v1.31.1 (#593) --- usi/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usi/pom.xml b/usi/pom.xml index dbe98f1cff..0b3ff43238 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -48,7 +48,7 @@ io.grpc grpc-stub - 1.31.0 + 1.31.1 org.apache.tomcat From e718927d97321632a01e346ea1e887088dc277a1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 14 Aug 2020 08:39:41 -0700 Subject: [PATCH 089/212] Update dependency firebase-functions to v3.9.1 (#589) --- firebase/functions/package-lock.json | 12 ++++++------ firebase/functions/package.json | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/firebase/functions/package-lock.json b/firebase/functions/package-lock.json index af650e00d5..1b50041c1f 100644 --- a/firebase/functions/package-lock.json +++ b/firebase/functions/package-lock.json @@ -1186,9 +1186,9 @@ } }, "firebase-functions": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-3.9.0.tgz", - "integrity": "sha512-PHwEvm/c0CNWFxfilmhyZBu5pZlQ2EJk/W4G2yKUm2yHGuh2ZZcga0s4Tj52vllX2eE+NkAsDsJpGdnjljA6+Q==", + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-3.9.1.tgz", + "integrity": "sha512-LnQQ5EJp8RaSvNZSOz/Ulp9ZQbKUXme/8sa5bLAmcKMc1o/cLu6IMB4GmWJXoi/4O5IFqSrWI9vNqb14LpfSIQ==", "requires": { "@types/express": "4.17.3", "cors": "^2.8.5", @@ -1591,9 +1591,9 @@ } }, "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", - "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" }, "lodash.at": { "version": "4.6.0", diff --git a/firebase/functions/package.json b/firebase/functions/package.json index 46aabc7580..4719ed425c 100644 --- a/firebase/functions/package.json +++ b/firebase/functions/package.json @@ -15,7 +15,7 @@ "@google-cloud/pubsub": "2.3.0", "@google-cloud/iot": "1.8.0", "firebase-admin": "9.1.0", - "firebase-functions": "3.9.0", + "firebase-functions": "3.9.1", "extend": "3.0.2" }, "private": true From c83ed7989e97339e489bfe1a4ce6ab5ce4a99619 Mon Sep 17 00:00:00 2001 From: Trevor Date: Fri, 14 Aug 2020 13:21:11 -0700 Subject: [PATCH 090/212] Update registrar tool for latest UDMI version (#596) --- etc/UDMI_VERSION | 2 +- testing/test_aux.gcp | 13 ++++++++----- testing/test_aux.sh | 2 +- testing/test_many.sh | 12 +++++++----- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/etc/UDMI_VERSION b/etc/UDMI_VERSION index 3eefcb9dd5..9084fa2f71 100644 --- a/etc/UDMI_VERSION +++ b/etc/UDMI_VERSION @@ -1 +1 @@ -1.0.0 +1.1.0 diff --git a/testing/test_aux.gcp b/testing/test_aux.gcp index 05847273db..9c5cc28467 100644 --- a/testing/test_aux.gcp +++ b/testing/test_aux.gcp @@ -5,18 +5,21 @@ Running testing/test_aux.sh "AHU-22" : "True", "GAT-123" : "True", "SNS-4" : "True" + }, + "Version" : { + "main" : "1.1.0" } } inst/test_site/devices/AHU-1/metadata_norm.json: "hash": "175e704a" inst/test_site/devices/AHU-22/metadata_norm.json: "hash": "bf0ba5fa" inst/test_site/devices/GAT-123/metadata_norm.json: "hash": "cbcf045e" inst/test_site/devices/SNS-4/metadata_norm.json: "hash": "879557b4" -RESULT skip cloud.udmi.state No device id -RESULT skip cloud.udmi.pointset No device id -RESULT skip cloud.udmi.system No device id RESULT pass cloud.udmi.state Payload successfully validated -RESULT pass cloud.udmi.pointset Payload successfully validated +RESULT fail cloud.udmi.pointset "Unrecognized field \"extraField\" (class com.google.daq.mqtt.registrar.UdmiSchema$PointsetMessage), not marked as ignorable (3 known properties: \"version\", \"points\", \"timestamp\"])\n at [Source: UNKNOWN; line: -1, column: -1] (through reference chain: com.google.daq.mqtt.registrar.UdmiSchema$PointsetMessage[\"extraField\"])" RESULT pass cloud.udmi.system Payload successfully validated RESULT pass cloud.udmi.state Payload successfully validated -RESULT fail cloud.udmi.pointset "Unrecognized field \"extraField\" (class com.google.daq.mqtt.registrar.UdmiSchema$PointsetMessage), not marked as ignorable (3 known properties: \"version\", \"points\", \"timestamp\"])\n at [Source: UNKNOWN; line: -1, column: -1] (through reference chain: com.google.daq.mqtt.registrar.UdmiSchema$PointsetMessage[\"extraField\"])" +RESULT pass cloud.udmi.pointset Payload successfully validated RESULT pass cloud.udmi.system Payload successfully validated +RESULT skip cloud.udmi.state No device id +RESULT skip cloud.udmi.pointset No device id +RESULT skip cloud.udmi.system No device id diff --git a/testing/test_aux.sh b/testing/test_aux.sh index fe5acb5e0a..e19d5a1334 100755 --- a/testing/test_aux.sh +++ b/testing/test_aux.sh @@ -87,7 +87,7 @@ if [ -f "$gcp_cred" ]; then make_pubber AHU-1 daq-faux-2 null null make_pubber SNS-4 daq-faux-3 1234 \"GAT-123\" - GOOGLE_APPLICATION_CREDENTIALS=$gcp_cred udmi/bin/registrar $project_id inst/test_site + GOOGLE_APPLICATION_CREDENTIALS=$gcp_cred udmi/bin/registrar inst/test_site $project_id cat inst/test_site/registration_summary.json | tee -a $GCP_RESULTS echo | tee -a $GCP_RESULTS fgrep hash inst/test_site/devices/*/metadata_norm.json | tee -a $GCP_RESULTS diff --git a/testing/test_many.sh b/testing/test_many.sh index 9cab9672fe..86c86fc299 100755 --- a/testing/test_many.sh +++ b/testing/test_many.sh @@ -125,13 +125,15 @@ echo Redacted soak diff | tee -a $TEST_RESULTS if [ -f "$gcp_cred" ]; then mv inst/reports/combo_*.md out/report_local.md - echo Pulling reports from gcp... from $start_time to $end_time - echo \n******Local reports****** + echo '******Local reports******' ls -l inst/reports/report_9a02571e8f05*.md - echo *************************\n + echo '*************************' - bin/combine_reports device=9a:02:57:1e:8f:05 from_time=$start_time to_time=$end_time \ - count=2 from_gcp=true + echo Pulling reports from gcp... from $start_time to $end_time + cmd="bin/combine_reports device=9a:02:57:1e:8f:05 from_time=$start_time to_time=$end_time" + cmd="$cmd count=2 from_gcp=true" + echo $cmd + $cmd echo GCP results diff | tee -a $GCP_RESULTS diff inst/reports/combo_*.md out/report_local.md | tee -a $GCP_RESULTS fi From 749e33fced634b36e156c0879791d07e8a1478a4 Mon Sep 17 00:00:00 2001 From: Francesco Anselmo Date: Fri, 14 Aug 2020 21:51:22 +0100 Subject: [PATCH 091/212] security.nmap.http test (#563) * test that checks open ports exposing http servers --- docker/include/bin/start_faux | 7 ++ docs/device_report.md | 30 ++++++-- docs/soak_report.md | 5 +- subset/pentests/readme.md | 8 +++ subset/pentests/test_nmap | 126 +++++++++++++++++++++++++--------- testing/test_aux.out | 6 +- testing/test_base.out | 43 +++++++----- testing/test_base.sh | 2 +- testing/test_modules.out | 12 +++- testing/test_modules.sh | 1 + testing/test_preamble.sh | 3 + 11 files changed, 177 insertions(+), 66 deletions(-) diff --git a/docker/include/bin/start_faux b/docker/include/bin/start_faux index 5c310b8cac..f0e5ff782c 100755 --- a/docker/include/bin/start_faux +++ b/docker/include/bin/start_faux @@ -68,6 +68,13 @@ elif [ -n "${options[passwordfail]}" ]; then service ssh start fi +# security.nmap.http faux device setup +if [ -n "${options[ohttp]}" ]; then + cp /root/nginx/nginxpass.conf /etc/nginx/nginx.conf + sed -i 's/listen 80;/listen 12345; listen 54321;/' /etc/nginx/nginx.conf + service nginx start +fi + # To capture all the data in/out of the faux device for debugging, uncomment # the following lines. The pcap file will end up in inst/faux/{hostname}.pcap # on the DAQ controller. diff --git a/docs/device_report.md b/docs/device_report.md index b9da9c2a8a..9ba625a067 100644 --- a/docs/device_report.md +++ b/docs/device_report.md @@ -48,15 +48,15 @@ Overall device result FAIL |Category|Result| |---|---| -|Security|PASS| +|Security|1/2| |Other|1/2| |Connectivity|n/a| |Expectation|pass|fail|skip|info|gone| |---|---|---|---|---|---| |Required|1|0|0|0|0| -|Recommended|2|0|0|0|0| -|Other|4|2|22|1|2| +|Recommended|1|0|0|0|1| +|Other|6|2|22|1|2| |Result|Test|Category|Expectation|Notes| |---|---|---|---|---| @@ -81,11 +81,13 @@ Overall device result FAIL |fail|protocol.bacnet.pic|Other|Other|PICS file defined however a BACnet device was not found.| |skip|protocol.bacnet.version|Other|Other|Bacnet device not found.| |skip|security.firmware|Other|Other|Could not retrieve a firmware version with nmap. Check bacnet port.| +|pass|security.nmap.http|Other|Other|No running http servers have been found.| +|pass|security.nmap.ports|Other|Other|Only allowed ports found open.| |skip|security.passwords.http|Other|Other|Port 80 not open on target device.| |skip|security.passwords.https|Other|Other|Port 443 not open on target device.| |skip|security.passwords.ssh|Other|Other|Port 22 not open on target device.| |skip|security.passwords.telnet|Other|Other|Port 23 not open on target device.| -|pass|security.ports.nmap|Security|Recommended|Only allowed ports found open.| +|gone|security.ports.nmap|Security|Recommended|| |skip|security.tls.v1|Other|Other|IOException unable to connect to server| |skip|security.tls.v1.x509|Other|Other|IOException unable to connect to server| |skip|security.tls.v1_2|Other|Other|IOException unable to connect to server| @@ -154,18 +156,32 @@ RESULT pass base.target.ping target reached ``` -------------------- -security.ports.nmap +security.nmap.ports -------------------- Automatic TCP/UDP port scan using nmap -------------------- # Nmap 7.60 scan initiated XXX as: nmap -v -n -T5 -sT -sU --host-timeout=4m --open -pU:47808,T:23,443,80, -oG /tmp/nmap.log X.X.X.X # Ports scanned: TCP(3;23,80,443) UDP(1;47808) SCTP(0;) PROTOCOLS(0;) Host: X.X.X.X () Status: Up -Host: X.X.X.X () Ports: 47808/closed/udp//bacnet/// Ignored State: closed (3) +Host: X.X.X.X () Ports: 47808/closed/udp//bacnet/// # Nmap done at XXX -- 1 IP address (1 host up) scanned in XXX No invalid ports found. -------------------- -RESULT pass security.ports.nmap Only allowed ports found open. +RESULT pass security.nmap.ports Only allowed ports found open. + +-------------------- +security.nmap.http +-------------------- +Check that the device does not have open ports exposing an unencrypted web interface using HTTP +-------------------- +# Nmap 7.60 scan initiated XXX as: nmap -v -n -T5 -A --script http-methods --host-timeout=4m --open -p- -oG /tmp/http.log X.X.X.X +# Ports scanned: TCP(65535;1-65535) UDP(0;) SCTP(0;) PROTOCOLS(0;) +Host: X.X.X.X () Status: Up +Host: X.X.X.X () Ports: 10000/open/tcp//snet-sensor-mgmt?/// +# Nmap done at XXX -- 1 IP address (1 host up) scanned in XXX +No running http servers have been found. +-------------------- +RESULT pass security.nmap.http No running http servers have been found. ``` diff --git a/docs/soak_report.md b/docs/soak_report.md index 7e99b37e7b..748bfeb93c 100644 --- a/docs/soak_report.md +++ b/docs/soak_report.md @@ -9,11 +9,12 @@ Source: local |base.startup.dhcp|2|0| |base.switch.ping|0|2| |base.target.ping|2|0| -|security.ports.nmap|2|0| +|security.nmap.ports|2|0| +|security.nmap.http|2|0| |categories|pass|skip| |---|---|---| -|Other|6|2| +|Other|8|2| |missing tests|count| |---|---| diff --git a/subset/pentests/readme.md b/subset/pentests/readme.md index 83b4c8ae32..845555fe11 100644 --- a/subset/pentests/readme.md +++ b/subset/pentests/readme.md @@ -33,12 +33,20 @@ Tests included in this module: ## test_nmap The nmap module uses the nmap tool to check open ports and validates them in relation to the policy that is set in the module_config.json file or files. +It also checks that there isn't any HTTP server running on any open port Tests included in this module: - security.nmap.ports +- security.nmap.http ### Conditions for security.nmap.ports - pass -> all the ports configured in module_config.json agree with the allow/deny policy - fail -> one or more of the ports configured in module_config.json do not agree with the allow/deny policy + +### Conditions for security.nmap.http + +- pass -> there is no HTTP server running on any of the open ports +- fail -> one or more of the ports is running an HTTP server + diff --git a/subset/pentests/test_nmap b/subset/pentests/test_nmap index 5fec9ac7ac..06159d0b21 100755 --- a/subset/pentests/test_nmap +++ b/subset/pentests/test_nmap @@ -2,18 +2,31 @@ source reporting.sh CONFIG=/config/device/module_config.json - REPORT=/tmp/report.txt -LOG=/tmp/nmap.log -OPENPORTSLIST_LOG=/tmp/nmap.ports.log -REDACTED_LOG=/tmp/nmap.report.log -TEST_NAME="security.ports.nmap" -TEST_DESCRIPTION="Automatic TCP/UDP port scan using nmap" -SUMMARY="" +# security.nmap.ports test variables +REPORT_NMAP=/tmp/report_nmap.txt +LOG_NMAP=/tmp/nmap.log +OPENPORTSLIST_LOG_NMAP=/tmp/nmap.ports.log +REDACTED_LOG_NMAP=/tmp/nmap.report.log +TEST_NAME_NMAP="security.nmap.ports" +TEST_DESCRIPTION_NMAP="Automatic TCP/UDP port scan using nmap" +SUMMARY_NMAP="" + +# security.nmap.http test variables +REPORT_HTTP=/tmp/report_http.txt +LOG_HTTP=/tmp/http.log +OPENPORTSLIST_LOG_HTTP=/tmp/http.ports.log +REDACTED_LOG_HTTP=/tmp/http.report.log +TEST_NAME_HTTP="security.nmap.http" +TEST_DESCRIPTION_HTTP="Check that the device does not have open ports exposing an unencrypted web interface using HTTP" +SUMMARY_HTTP="" -rm -f $LOG $REDACTED_LOG $OPENPORTSLIST_LOG $REPORT +# remove temporary files +rm -f $LOG_NMAP $REDACTED_LOG_NMAP $OPENPORTSLIST_LOG_NMAP $REPORT_NMAP +rm -f $LOG_HTTP $REDACTED_LOG_HTTP $OPENPORTSLIST_LOG_HTTP $REPORT_HTTP +# configure and run the security.nmap.ports test if [ -f $CONFIG ]; then echo Extracting servers config from $CONFIG else @@ -31,7 +44,7 @@ nc -nzv $TARGET_IP -w 5 23 || true sleep 1 option="-sT" -portslist=-p1-1024 +portslist=-p1-65535 if [ -f $CONFIG ]; then # get list of ports to be scanned from module_config.json ports="U:" @@ -50,21 +63,20 @@ if [ -f $CONFIG ]; then if [ $portslist != "U:T:" ]; then portslist="-p$portslist" else - portslist=-p1-1024 + portslist=-p1-65535 fi fi echo -e "\nTesting target $TARGET_IP to check open ports $portslist" -nmap -v -n -T5 $option --host-timeout=4m --open $portslist -oG $LOG $TARGET_IP > /dev/null -cat $LOG +nmap -v -n -T5 $option --host-timeout=4m --open $portslist -oG $LOG_NMAP $TARGET_IP > /dev/null +cat $LOG_NMAP -touch $REDACTED_LOG -cat $LOG | tee -a $REDACTED_LOG -touch $REPORT -touch $OPENPORTSLIST_LOG +touch $REDACTED_LOG_NMAP +cat $LOG_NMAP | tee -a $REDACTED_LOG_NMAP +touch $REPORT_NMAP +touch $OPENPORTSLIST_LOG_NMAP rm -f .fail -openportslist=" - " -grep -oh '[0-9]*/open[^[:space:]]*' $LOG | while IFS=/ read -ra parts; do +grep -oh '[0-9]*/open[^[:space:]]*' $LOG_NMAP | while IFS=/ read -ra parts; do state=${parts[1]} if [ "$state" == open ]; then if [ -f $CONFIG ]; then @@ -73,14 +85,14 @@ grep -oh '[0-9]*/open[^[:space:]]*' $LOG | while IFS=/ read -ra parts; do allowed=$(jq ".servers.$proto.ports.\"$port\".allowed" $CONFIG) if [ "$allowed" != true ]; then touch .fail - echo Failing ${parts[*]} | sed 's/,$//' | tee -a $REDACTED_LOG - echo ${parts[0]}"," | tee -a $OPENPORTSLIST_LOG + echo Failing ${parts[*]} | sed 's/,$//' | tee -a $REDACTED_LOG_NMAP + echo -n ${parts[0]}"," | tee -a $OPENPORTSLIST_LOG_NMAP else - echo Allowing ${parts[*]} | sed 's/,$//' | tee -a $REDACTED_LOG + echo Allowing ${parts[*]} | sed 's/,$//' | tee -a $REDACTED_LOG_NMAP fi else - echo Open port ${parts[*]} | sed 's/,$//' | tee -a $REDACTED_LOG - echo ${parts[0]}"," | tee -a $OPENPORTSLIST_LOG + echo Open port ${parts[*]} | sed 's/,$//' | tee -a $REDACTED_LOG_NMAP + echo -n ${parts[0]}"," | tee -a $OPENPORTSLIST_LOG_NMAP touch .fail fi fi @@ -88,19 +100,67 @@ done if [ -f .fail ]; then echo Open ports: - cat $REDACTED_LOG + cat $REDACTED_LOG_NMAP + result=fail + SUMMARY_NMAP="Some disallowed ports are open: `cat $OPENPORTSLIST_LOG_NMAP | sed 's/,$//'`." +else + echo No invalid ports found. | tee -a $REDACTED_LOG_NMAP + result=pass + SUMMARY_NMAP="Only allowed ports found open." +fi + +RESULT_AND_SUMMARY_NMAP="RESULT $result $TEST_NAME_NMAP $SUMMARY_NMAP" + +# configure and run the security.nmap.http test +option="-A --script http-methods" # Full NSE scan with the http-methods script +portslist=-p- # scan all ports +echo -e "\nTesting target $TARGET_IP to check open ports exposing HTTP servers" +nmap -v -n -T5 $option --host-timeout=4m --open $portslist -oG $LOG_HTTP $TARGET_IP > /dev/null +cat $LOG_HTTP + +touch $REDACTED_LOG_HTTP +cat $LOG_HTTP | tee -a $REDACTED_LOG_HTTP +touch $REPORT_HTTP +touch $OPENPORTSLIST_LOG_HTTP +rm -f .fail +grep -oh '[0-9]*/open[^[:space:]]*' $LOG_HTTP | while IFS=/ read -ra parts; do + state=${parts[1]} + if [ "$state" == open ]; then + port=${parts[0]} + proto=${parts[4]} + echo $proto + if [ "$proto" == http ]; then + touch .fail + echo Failing ${parts[*]} | sed 's/,$//' | tee -a $REDACTED_LOG_HTTP + echo -n ${parts[0]}"," | tee -a $OPENPORTSLIST_LOG_HTTP + fi + fi +done + +if [ -f .fail ]; then + echo Open http ports: + cat $REDACTED_LOG_HTTP result=fail - SUMMARY="Some disallowed ports are open: `cat $OPENPORTSLIST_LOG | sed 's/,$//'`" + SUMMARY_HTTP="Some ports are running http servers: `cat $OPENPORTSLIST_LOG_HTTP | sed 's/,$//'`." else - echo No invalid ports found. | tee -a $REDACTED_LOG + echo No running http servers have been found. | tee -a $REDACTED_LOG_HTTP result=pass - SUMMARY="Only allowed ports found open." + SUMMARY_HTTP="No running http servers have been found." fi -RESULT_AND_SUMMARY="RESULT $result $TEST_NAME $SUMMARY" +RESULT_AND_SUMMARY_HTTP="RESULT $result $TEST_NAME_HTTP $SUMMARY_HTTP" + +# output test results to the report file +write_out_result $REPORT_NMAP \ + "$TEST_NAME_NMAP" \ + "$TEST_DESCRIPTION_NMAP" \ + "$(cat $REDACTED_LOG_NMAP)" \ + "$RESULT_AND_SUMMARY_NMAP" + +write_out_result $REPORT_HTTP \ + "$TEST_NAME_HTTP" \ + "$TEST_DESCRIPTION_HTTP" \ + "$(cat $REDACTED_LOG_HTTP)" \ + "$RESULT_AND_SUMMARY_HTTP" -write_out_result $REPORT \ - "$TEST_NAME" \ - "$TEST_DESCRIPTION" \ - "$(cat $REDACTED_LOG)" \ - "$RESULT_AND_SUMMARY" +cat $REPORT_NMAP $REPORT_HTTP > $REPORT \ No newline at end of file diff --git a/testing/test_aux.out b/testing/test_aux.out index d29d4f2093..9586d53679 100644 --- a/testing/test_aux.out +++ b/testing/test_aux.out @@ -212,8 +212,10 @@ port-02 module_config modules `\.-''__.-' \ ( \_ `''' `\__ /\ ') -Host: X.X.X.X () Status: Up -Host: X.X.X.X () Ports: 47808/closed/udp//bacnet/// Ignored State: closed (3) +Host: X.X.X.X () Status: Up +Host: X.X.X.X () Ports: 47808/closed/udp//bacnet/// +Host: X.X.X.X () Status: Up +Host: X.X.X.X () Ports: 10000/open/tcp//snet-sensor-mgmt?/// Redacted docs diff No report diff 9a02571e8f01: ['9a02571e8f01:ping:Exception'] diff --git a/testing/test_base.out b/testing/test_base.out index c0d73a57fe..4f96ea4673 100644 --- a/testing/test_base.out +++ b/testing/test_base.out @@ -26,14 +26,15 @@ Overall device result PASS |Expectation|pass|skip| |---|---|---| -|Other|3|1| +|Other|4|1| |Result|Test|Category|Expectation|Notes| |---|---|---|---|---| |pass|base.startup.dhcp|Other|Other|| |skip|base.switch.ping|Other|Other|No local IP has been set, check system config| |pass|base.target.ping|Other|Other|target reached| -|pass|security.ports.nmap|Other|Other|Only allowed ports found open.| +|pass|security.nmap.http|Other|Other|No running http servers have been found.| +|pass|security.nmap.ports|Other|Other|Only allowed ports found open.| ## Module pass @@ -94,16 +95,28 @@ RESULT pass base.target.ping target reached ``` -------------------- -security.ports.nmap +security.nmap.ports -------------------- Automatic TCP/UDP port scan using nmap -------------------- -# Nmap 7.60 scan initiated XXX as: nmap -v -n -T5 -sT --host-timeout=4m --open -p1-1024 -oG /tmp/nmap.log X.X.X.X -# Ports scanned: TCP(1024;1-1024) UDP(0;) SCTP(0;) PROTOCOLS(0;) +# Nmap 7.60 scan initiated XXX as: nmap -v -n -T5 -sT --host-timeout=4m --open -p1-65535 -oG /tmp/nmap.log X.X.X.X +# Ports scanned: TCP(65535;1-65535) UDP(0;) SCTP(0;) PROTOCOLS(0;) # Nmap done at XXX -- 1 IP address (1 host up) scanned in XXX No invalid ports found. -------------------- -RESULT pass security.ports.nmap Only allowed ports found open. +RESULT pass security.nmap.ports Only allowed ports found open. + +-------------------- +security.nmap.http +-------------------- +Check that the device does not have open ports exposing an unencrypted web interface using HTTP +-------------------- +# Nmap 7.60 scan initiated XXX as: nmap -v -n -T5 -A --script http-methods --host-timeout=4m --open -p- -oG /tmp/http.log X.X.X.X +# Ports scanned: TCP(65535;1-65535) UDP(0;) SCTP(0;) PROTOCOLS(0;) +# Nmap done at XXX -- 1 IP address (1 host up) scanned in XXX +No running http servers have been found. +-------------------- +RESULT pass security.nmap.http No running http servers have been found. ``` @@ -125,23 +138,17 @@ terminated %%%%%%%%%%%%%%%%%%%%%% Telnet fail DAQ result code 1 9a02571e8f00: ['9a02571e8f00:hold:DaqException'] -|fail|security.ports.nmap|Other|Other|Some disallowed ports are open: 23| -security.ports.nmap -RESULT fail security.ports.nmap Some disallowed ports are open: 23 %%%%%%%%%%%%%%%%%%%%%% Default MUD -DAQ result code 0 -9a02571e8f00: [] -|pass|security.ports.nmap|Other|Other|Only allowed ports found open.| -security.ports.nmap -RESULT pass security.ports.nmap Only allowed ports found open. +DAQ result code 1 +9a02571e8f00: ['9a02571e8f00:nmap:TimeoutError'] %%%%%%%%%%%%%%%%%%%%%% External switch tests 9a02571e8f00: [] dp_id: 1 dp_id: 4886718345 -Switch test with target 192.0.2.138:2 -RESULT pass base.switch.ping target %% 192.0.2.138:2 -Switch test with target 192.0.2.138:2 -Monolog processing base.switch.ping... +Switch test with target 192.0.2.138:2 +RESULT pass base.switch.ping target %% 192.0.2.138:2 +Switch test with target 192.0.2.138:2 +Monolog processing base.switch.ping... switch ping 2 %%%%%%%%%%%%%%%%%%%%%% Alt switch tests XXX runner INFO 9a:02:57:1e:8f:00 learned on vid 1001 diff --git a/testing/test_base.sh b/testing/test_base.sh index 79f45c5886..8deaaf3d09 100755 --- a/testing/test_base.sh +++ b/testing/test_base.sh @@ -47,7 +47,7 @@ cp config/system/ext.yaml local/system.yaml cmd/run -s cat inst/result.log | tee -a $TEST_RESULTS fgrep dp_id inst/faucet.yaml | tee -a $TEST_RESULTS -fgrep -i switch inst/run-9a02571e8f00/nodes/ping*/activate.log | tee -a $TEST_RESULTS +fgrep -i switch inst/run-9a02571e8f00/nodes/ping*/activate.log | sed -e "s/\r//g" | tee -a $TEST_RESULTS cat -vet inst/run-9a02571e8f00/nodes/ping*/activate.log count=$(fgrep icmp_seq=5 inst/run-9a02571e8f00/nodes/ping*/activate.log | wc -l) echo switch ping $count | tee -a $TEST_RESULTS diff --git a/testing/test_modules.out b/testing/test_modules.out index f0c130ddd3..2e2dfadd4d 100644 --- a/testing/test_modules.out +++ b/testing/test_modules.out @@ -26,11 +26,17 @@ RESULT fail security.tls.v1_2.x509 Certificate is expired. RESULT fail security.tls.v1_3 Certificate could not be validated. RESULT fail security.tls.v1_3.x509 Certificate could not be validated. Testing nmap -RESULT pass security.ports.nmap Only allowed ports found open. +RESULT pass security.nmap.ports Only allowed ports found open. +RESULT pass security.nmap.http No running http servers have been found. Testing nmap bacnet -RESULT pass security.ports.nmap Only allowed ports found open. +RESULT pass security.nmap.ports Only allowed ports found open. +RESULT pass security.nmap.http No running http servers have been found. Testing nmap telnet -RESULT fail security.ports.nmap Some disallowed ports are open: 23 +RESULT fail security.nmap.ports Some disallowed ports are open: 23. +RESULT pass security.nmap.http No running http servers have been found. +Testing nmap ohttp +RESULT fail security.nmap.ports Some disallowed ports are open: 443,12345,54321. +RESULT fail security.nmap.http Some ports are running http servers: 12345,54321. Testing ssh RESULT skip security.ssh.version Device is not running an SSH server Testing ssh ssh diff --git a/testing/test_modules.sh b/testing/test_modules.sh index 88ab08fa0e..711765a9e1 100755 --- a/testing/test_modules.sh +++ b/testing/test_modules.sh @@ -17,6 +17,7 @@ tls alt expiredtls nmap nmap bacnet nmap telnet +nmap ohttp ssh ssh ssh ssh sshv1 diff --git a/testing/test_preamble.sh b/testing/test_preamble.sh index d01fc546f4..1c6f6431b9 100644 --- a/testing/test_preamble.sh +++ b/testing/test_preamble.sh @@ -62,7 +62,10 @@ function redact { -e 's/0\.[0-9]+s latency/XXX/' \ -e 's/open\|filtered/closed/' \ -e 's/DAQ version.*//' \ + -e 's/Seq Index.*//' \ + -e 's/Ignored State.*//' \ -e 's/Not shown: .* ports//' \ + -e 's/\t/ /g' \ -e 's/([0-9]{1,3}\.){3}[0-9]{1,3}/X.X.X.X/' } From 46ed8d2cd43fb252b9a207b7bc5be24b2f64c013 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 16 Aug 2020 23:16:18 -0700 Subject: [PATCH 092/212] Update dependency jsoneditor to v9.0.4 (#597) --- firebase/public/config.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firebase/public/config.html b/firebase/public/config.html index 3149596f26..438013214b 100644 --- a/firebase/public/config.html +++ b/firebase/public/config.html @@ -11,8 +11,8 @@ - - + +
      From 46dfa019d9401d7446348f1f7e55deab2a4429cc Mon Sep 17 00:00:00 2001 From: Trevor Date: Mon, 17 Aug 2020 06:14:46 -0700 Subject: [PATCH 093/212] Do not infinite spawn ntp (#598) --- docker/include/bin/start_faux | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/docker/include/bin/start_faux b/docker/include/bin/start_faux index f0e5ff782c..016a60bb7a 100755 --- a/docker/include/bin/start_faux +++ b/docker/include/bin/start_faux @@ -158,19 +158,15 @@ fi # NTPv4 query to the NTP server learnt from DHCP. # NTPv3 query to the IP of time.google.com (since resolv.conf is modified by other tests) -STATIC_NTP_SERVER=216.239.35.8 if [ -n "${options[ntpv4]}" ]; then dhcp_ntp=$(fgrep NTPSERVERS= /run/ntpdate.dhcp) ntp_server=`echo $dhcp_ntp | cut -d "'" -f 2` echo Transmitting NTP query to $ntp_server using NTPv4 - java -jar NTPClient/build/libs/NTPClient-1.0-SNAPSHOT.jar $ntp_server 123 4 2 & - sleep 5 + java -jar NTPClient/build/libs/NTPClient-1.0-SNAPSHOT.jar $ntp_server 123 4 2 > ntp.log & elif [ -n "${options[ntpv3]}" ]; then - (while date; do - echo Transmitting NTP query to $STATIC_NTP_SERVER using NTPv3 - java -jar NTPClient/build/libs/NTPClient-1.0-SNAPSHOT.jar $STATIC_NTP_SERVER 123 3 2 & - sleep 5 - done) & + STATIC_NTP_SERVER=216.239.35.8 + echo Transmitting NTP query to $STATIC_NTP_SERVER using NTPv3 + java -jar NTPClient/build/libs/NTPClient-1.0-SNAPSHOT.jar $STATIC_NTP_SERVER 123 3 2 > ntp.log & fi # ntp_pass queries the NTP server learnt from DHCP. ntp_fail sends to time.google.com From ffd96eb599e3a30da4b0a30b558b14c66333a032 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 18 Aug 2020 07:41:52 -0700 Subject: [PATCH 094/212] Update dependency @google-cloud/pubsub to v2.5.0 (#599) Co-authored-by: Renovate Bot --- firebase/functions/package-lock.json | 168 ++++++++++++++++----------- firebase/functions/package.json | 2 +- 2 files changed, 99 insertions(+), 71 deletions(-) diff --git a/firebase/functions/package-lock.json b/firebase/functions/package-lock.json index 1b50041c1f..e082de4a9f 100644 --- a/firebase/functions/package-lock.json +++ b/firebase/functions/package-lock.json @@ -358,73 +358,52 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-3.0.4.tgz", "integrity": "sha512-fKI+jYQdV1F9jtG6tSRro3ilNSeBWVmTzxc8Z0kiPRXcj8eshh9fiF8TtxfDefyUKgTdWgHpzGBwLbZ/OGikJg==", - "optional": true, "requires": { "arrify": "^2.0.0", "extend": "^3.0.2" } }, "@google-cloud/precise-date": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@google-cloud/precise-date/-/precise-date-2.0.2.tgz", - "integrity": "sha512-eEnWN8vzy4Gji9dOlcr8rsX0Oz52eI6ZZZj0AIrUbqTXM8JFPqKzx53DpWIYuXW6c8AfiyY1txjOsg1cXvsoyQ==" + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@google-cloud/precise-date/-/precise-date-2.0.3.tgz", + "integrity": "sha512-+SDJ3ZvGkF7hzo6BGa8ZqeK3F6Z4+S+KviC9oOK+XCs3tfMyJCh/4j93XIWINgMMDIh9BgEvlw4306VxlXIlYA==" }, "@google-cloud/projectify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-2.0.1.tgz", - "integrity": "sha512-ZDG38U/Yy6Zr21LaR3BTiiLtpJl6RkPS/JwoRT453G+6Q1DhlV0waNf8Lfu+YVYGIIxgKnLayJRfYlFJfiI8iQ==", - "optional": true + "integrity": "sha512-ZDG38U/Yy6Zr21LaR3BTiiLtpJl6RkPS/JwoRT453G+6Q1DhlV0waNf8Lfu+YVYGIIxgKnLayJRfYlFJfiI8iQ==" }, "@google-cloud/promisify": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-2.0.2.tgz", - "integrity": "sha512-EvuabjzzZ9E2+OaYf+7P9OAiiwbTxKYL0oGLnREQd+Su2NTQBpomkdlkBowFvyWsaV0d1sSGxrKpSNcrhPqbxg==", - "optional": true + "integrity": "sha512-EvuabjzzZ9E2+OaYf+7P9OAiiwbTxKYL0oGLnREQd+Su2NTQBpomkdlkBowFvyWsaV0d1sSGxrKpSNcrhPqbxg==" }, "@google-cloud/pubsub": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@google-cloud/pubsub/-/pubsub-2.3.0.tgz", - "integrity": "sha512-lWFwuzg+d7UN7YY6TGwIFPxiA2pFFHx1ApN0X5xIe0jtuUuF2iPaRNIJwZTOnvZ8xmOSpQqiaj/SwEDgr4b46A==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@google-cloud/pubsub/-/pubsub-2.5.0.tgz", + "integrity": "sha512-7bbbQqa+LSTopVjt20EZ8maO6rEpbO7v8EvDImHMsbRS30HJ5+kClbaQTRvhNzhc1qy221A1GbHPHMCQ/U5E3Q==", "requires": { "@google-cloud/paginator": "^3.0.0", "@google-cloud/precise-date": "^2.0.0", "@google-cloud/projectify": "^2.0.0", "@google-cloud/promisify": "^2.0.0", + "@opentelemetry/api": "^0.10.0", + "@opentelemetry/tracing": "^0.10.0", "@types/duplexify": "^3.6.0", "@types/long": "^4.0.0", "arrify": "^2.0.0", "extend": "^3.0.2", "google-auth-library": "^6.0.0", - "google-gax": "^2.1.0", + "google-gax": "^2.7.0", "is-stream-ended": "^0.1.4", "lodash.snakecase": "^4.1.1", - "p-defer": "^3.0.0", - "protobufjs": "^6.8.1" + "p-defer": "^3.0.0" }, "dependencies": { - "@google-cloud/paginator": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-3.0.2.tgz", - "integrity": "sha512-kXK+Dbz4pNvv8bKU80Aw5HsIdgOe0WuMTd8/fI6tkANUxzvJOVJQQRsWVqcHSWK2RXHPTA9WBniUCwY6gAJDXw==", - "requires": { - "arrify": "^2.0.0", - "extend": "^3.0.2" - } - }, - "@google-cloud/projectify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-2.0.1.tgz", - "integrity": "sha512-ZDG38U/Yy6Zr21LaR3BTiiLtpJl6RkPS/JwoRT453G+6Q1DhlV0waNf8Lfu+YVYGIIxgKnLayJRfYlFJfiI8iQ==" - }, - "@google-cloud/promisify": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-2.0.2.tgz", - "integrity": "sha512-EvuabjzzZ9E2+OaYf+7P9OAiiwbTxKYL0oGLnREQd+Su2NTQBpomkdlkBowFvyWsaV0d1sSGxrKpSNcrhPqbxg==" - }, "@grpc/grpc-js": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.1.2.tgz", - "integrity": "sha512-k2u86Bkm/3xrjUaSWeIyzXScBt/cC8uE7BznR0cpueQi11R33W6qfJdMrkrsmSHirp5likR55JSXUrcWG6ybHA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.1.3.tgz", + "integrity": "sha512-HtOsk2YUofBcm1GkPqGzb6pwHhv+74eC2CUO229USIDKRtg30ycbZmqC+HdNtY3nHqoc9IgcRlntFgopyQoYCA==", "requires": { "semver": "^6.2.0" } @@ -435,9 +414,9 @@ "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" }, "gaxios": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.0.4.tgz", - "integrity": "sha512-97NmFuMETFQh6gqPUxkqjxRMjmY8aRKRMphIkgO/b90AbCt5wAVuXsp8oWjIXlLN2pIK/fsXD8edcM7ULkFMLg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.1.0.tgz", + "integrity": "sha512-DDTn3KXVJJigtz+g0J3vhcfbDbKtAroSTxauWsdnP57sM5KZ3d2c/3D9RKFJ86s43hfw6WULg6TXYw/AYiBlpA==", "requires": { "abort-controller": "^3.0.0", "extend": "^3.0.2", @@ -456,9 +435,9 @@ } }, "google-auth-library": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.0.5.tgz", - "integrity": "sha512-Wj31lfTm2yR4g3WfOOB1Am1tt478Xq9OvzTPQJi17tn/I9R5IcsxjANBsE93nYmxYxtwDedhOdIb8l3vSPG49Q==", + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.0.6.tgz", + "integrity": "sha512-fWYdRdg55HSJoRq9k568jJA1lrhg9i2xgfhVIMJbskUmbDpJGHsbv9l41DGhCDXM21F9Kn4kUwdysgxSYBYJUw==", "requires": { "arrify": "^2.0.0", "base64-js": "^1.3.0", @@ -472,9 +451,9 @@ } }, "google-gax": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-2.6.3.tgz", - "integrity": "sha512-hqY6H53Qmaku8rE8dGAM89RSUc1nc4JYG81whrVJRmDQZ2jhJK8AwCd3pJQ3V48rgp9xiWBzBQsyeaxnb3Eikw==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-2.7.0.tgz", + "integrity": "sha512-0dBATy8mMVlfOBrT85Q+NzBpZ4OJZUMrPI9wJULpiIDq2w1zlN30Duor+fQUcMEjanYEc72G58M4iUVve0jfXw==", "requires": { "@grpc/grpc-js": "~1.1.1", "@grpc/proto-loader": "^0.5.1", @@ -490,28 +469,6 @@ "retry-request": "^4.0.0", "semver": "^6.0.0", "walkdir": "^0.4.0" - }, - "dependencies": { - "protobufjs": { - "version": "6.10.1", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.10.1.tgz", - "integrity": "sha512-pb8kTchL+1Ceg4lFd5XUpK8PdWacbvV5SK2ULH2ebrYtl4GjJmS24m6CKME67jzV53tbJxHlnNOSqQHbTsR9JQ==", - "requires": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/long": "^4.0.1", - "@types/node": "^13.7.0", - "long": "^4.0.0" - } - } } }, "google-p12-pem": { @@ -523,9 +480,9 @@ } }, "gtoken": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.2.tgz", - "integrity": "sha512-lull70rHCTvRTmAt+R/6W5bTtx4MjHku7AwJwK5fGqhOmygcZud0nrZcX+QUNfBJwCzqy7S5i1Bc4NYnr5PMMA==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.3.tgz", + "integrity": "sha512-Nyd1wZCMRc2dj/mAD0LlfQLcAO06uKdpKJXvK85SGrF5+5+Bpfil9u/2aw35ltvEHjvl0h5FMKN5knEU+9JrOg==", "requires": { "gaxios": "^3.0.0", "google-p12-pem": "^3.0.0", @@ -549,6 +506,26 @@ "yallist": "^4.0.0" } }, + "protobufjs": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.10.1.tgz", + "integrity": "sha512-pb8kTchL+1Ceg4lFd5XUpK8PdWacbvV5SK2ULH2ebrYtl4GjJmS24m6CKME67jzV53tbJxHlnNOSqQHbTsR9JQ==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": "^13.7.0", + "long": "^4.0.0" + } + }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -616,6 +593,57 @@ "protobufjs": "^6.8.6" } }, + "@opentelemetry/api": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-0.10.2.tgz", + "integrity": "sha512-GtpMGd6vkzDMYcpu2t9LlhEgMy/SzBwRnz48EejlRArYqZzqSzAsKmegUK7zHgl+EOIaK9mKHhnRaQu3qw20cA==", + "requires": { + "@opentelemetry/context-base": "^0.10.2" + } + }, + "@opentelemetry/context-base": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-base/-/context-base-0.10.2.tgz", + "integrity": "sha512-hZNKjKOYsckoOEgBziGMnBcX0M7EtstnCmwz5jZUOUYwlZ+/xxX6z3jPu1XVO2Jivk0eLfuP9GP+vFD49CMetw==" + }, + "@opentelemetry/core": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-0.10.2.tgz", + "integrity": "sha512-DhkiTp5eje2zTGd+HAIKWpGE6IR6lq7tUpYt4nnkhOi6Hq9WQAANVDCWEZEbYOw57LkdXbE50FZ/kMvHDm450Q==", + "requires": { + "@opentelemetry/api": "^0.10.2", + "@opentelemetry/context-base": "^0.10.2", + "semver": "^7.1.3" + }, + "dependencies": { + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" + } + } + }, + "@opentelemetry/resources": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-0.10.2.tgz", + "integrity": "sha512-5JGC2TPSAIHth615IURt+sSsTljY43zTfJD0JE9PHC6ipZPiQ0dpQDZOrLn8NAMfOHY1jeWwpIuLASjqbXUfuw==", + "requires": { + "@opentelemetry/api": "^0.10.2", + "@opentelemetry/core": "^0.10.2", + "gcp-metadata": "^3.5.0" + } + }, + "@opentelemetry/tracing": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/tracing/-/tracing-0.10.2.tgz", + "integrity": "sha512-mNAhARn4dEdOjTa9OdysjI4fRHMbvr4YSbPuH7jhkyPzgoa+DnvnbY3GGpEay6kpuYJsrW8Ef9OIKAV/GndhbQ==", + "requires": { + "@opentelemetry/api": "^0.10.2", + "@opentelemetry/context-base": "^0.10.2", + "@opentelemetry/core": "^0.10.2", + "@opentelemetry/resources": "^0.10.2" + } + }, "@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", diff --git a/firebase/functions/package.json b/firebase/functions/package.json index 4719ed425c..172ce21f03 100644 --- a/firebase/functions/package.json +++ b/firebase/functions/package.json @@ -12,7 +12,7 @@ "node": "10" }, "dependencies": { - "@google-cloud/pubsub": "2.3.0", + "@google-cloud/pubsub": "2.5.0", "@google-cloud/iot": "1.8.0", "firebase-admin": "9.1.0", "firebase-functions": "3.9.1", From dd08f4250d2b3d533078efdb6048e0cf07a3582e Mon Sep 17 00:00:00 2001 From: Trevor Date: Tue, 18 Aug 2020 10:39:00 -0700 Subject: [PATCH 095/212] Refactor base test module and use stable test set id (#600) --- daq/base_module.py | 37 +++++++++++++++++++++++++++++++++++++ daq/docker_test.py | 26 ++++++-------------------- daq/host.py | 10 +++++----- daq/ipaddr_test.py | 15 ++++++--------- daq/runner.py | 22 ++++++++++++++++++---- testing/unit/test_runner.py | 2 +- 6 files changed, 73 insertions(+), 39 deletions(-) create mode 100644 daq/base_module.py diff --git a/daq/base_module.py b/daq/base_module.py new file mode 100644 index 0000000000..2d1dffc985 --- /dev/null +++ b/daq/base_module.py @@ -0,0 +1,37 @@ +"""Host module base class""" + +from __future__ import absolute_import + +import datetime +import logger + + +LOGGER = logger.get_logger('module') + + +class HostModule: + """Base class for host test modules""" + + def __init__(self, host, tmpdir, test_name, module_config): + self.host = host + self.tmpdir = tmpdir + self.test_name = test_name + self.device = host.device + self.test_config = module_config.get('modules').get(test_name) + self.runner = host.runner + # Host name can't be more than 15 characters + # because it is also used to create an interface in mininet. + self.host_name = '%s%02d' % (test_name, host.device.set_id) + self.callback = None + self._finish_hook = None + self.start_time = None + + def start(self, port, params, callback, finish_hook): + """Start a test module""" + LOGGER.debug('Starting test module %s', self) + self.callback = callback + self._finish_hook = finish_hook + self.start_time = datetime.datetime.now() + + def __repr__(self): + return "Target device %s test %s" % (self.device, self.test_name) diff --git a/daq/docker_test.py b/daq/docker_test.py index fe17657a8e..9c678ee10d 100644 --- a/daq/docker_test.py +++ b/daq/docker_test.py @@ -6,6 +6,8 @@ import string import random +from base_module import HostModule + import logger from clib import docker_host import wrappers @@ -13,7 +15,7 @@ LOGGER = logger.get_logger('docker') -class DockerTest: +class DockerTest(HostModule): """Class for running docker tests""" IMAGE_NAME_FORMAT = 'daqf/test_%s' @@ -21,27 +23,14 @@ class DockerTest: CONTAINER_PREFIX = 'daq' def __init__(self, host, tmpdir, test_name, module_config): - self.device = host.device - self.tmpdir = tmpdir - self.test_name = test_name - self.runner = host.runner - # Host name can't be more than 15 characters - # because it is also used to create an interface in mininet. - self.host_name = '%s_%s' % (test_name[:6], self._get_random_string(3)) + super().__init__(host, tmpdir, test_name, module_config) self.docker_log = None self.docker_host = None - self.callback = None - self.start_time = None self.pipe = None - self._finish_hook = None def start(self, port, params, callback, finish_hook): """Start the docker test""" - LOGGER.debug('%s starting docker test', self) - - self.start_time = datetime.datetime.now() - self.callback = callback - self._finish_hook = finish_hook + super().start(port, params, callback, finish_hook) def opt_param(key): return params.get(key) or '' # Substitute empty string for None @@ -130,7 +119,6 @@ def _docker_error(self, exception): def _docker_finalize(self): assert self.docker_host, 'docker host %s already finalized' % self - LOGGER.info('%s docker finalize', self) if self._finish_hook: self._finish_hook() self.runner.remove_host(self.docker_host) @@ -138,6 +126,7 @@ def _docker_finalize(self): self.runner.monitor_forget(self.pipe.stdout) self.pipe = None return_code = self.docker_host.terminate() + LOGGER.info('%s docker finalize %d', self, return_code) self.docker_host = None self.docker_log.close() self.docker_log = None @@ -174,8 +163,5 @@ def _docker_complete(self): def _get_random_string(self, length): return ''.join(random.choice(string.ascii_letters) for _ in range(length)) - def __repr__(self): - return "Target device %s test %s" % (self.device, self.test_name) - def ip_listener(self, target_ip): """Do nothing b/c docker tests don't care about ip notifications""" diff --git a/daq/host.py b/daq/host.py index d1c68b5bad..5d5f17a74e 100644 --- a/daq/host.py +++ b/daq/host.py @@ -34,6 +34,7 @@ class _STATE: TERM = 'Host terminated' + class MODE: """Test module modes for state reporting.""" INIT = 'init' @@ -109,7 +110,6 @@ def __init__(self, runner, device, config): self._monitor_scan_sec = int(config.get('monitor_scan_sec', 0)) _default_timeout_sec = int(config.get('default_timeout_sec', 0)) self._default_timeout_sec = _default_timeout_sec if _default_timeout_sec else None - self._finish_hook_script = config.get('finish_hook') self._usi_config = config.get('usi_setup', {}) self._topology_hook_script = config.get('topology_hook') self._mirror_intf_name = None @@ -709,13 +709,13 @@ def _host_tmp_path(self): return os.path.join(self._host_dir_path(), 'tmp') def _finish_hook(self): - if self._finish_hook_script: + script = self.config.get('finish_hook') + if script: finish_dir = os.path.join(self.devdir, 'finish', self._host_name()) shutil.rmtree(finish_dir, ignore_errors=True) os.makedirs(finish_dir) - self.logger.info('Executing finish_hook: %s %s', self._finish_hook_script, finish_dir) - os.system('%s %s 2>&1 > %s/finish.out' % - (self._finish_hook_script, finish_dir, finish_dir)) + self.logger.info('Executing finish_hook: %s %s', script, finish_dir) + os.system('%s %s 2>&1 > %s/finish.out' % (script, finish_dir, finish_dir)) def _topology_hook(self): if self._topology_hook_script: diff --git a/daq/ipaddr_test.py b/daq/ipaddr_test.py index 0ce72b7e65..f701404d90 100644 --- a/daq/ipaddr_test.py +++ b/daq/ipaddr_test.py @@ -6,23 +6,20 @@ import copy import logger + +from base_module import HostModule + LOGGER = logger.get_logger('ipaddr') -class IpAddrTest: +class IpAddrTest(HostModule): """Module for inline ipaddr tests""" def __init__(self, host, tmpdir, test_name, module_config): - self.host = host - self.device = host.device - self.tmpdir = tmpdir - self.test_config = module_config.get('modules').get('ipaddr') + super().__init__(host, tmpdir, test_name, module_config) self.test_dhcp_ranges = copy.copy(self.test_config.get('dhcp_ranges', [])) - self.test_name = test_name - self.host_name = '%s_%s' % (test_name, self.device.mac) self.log_path = os.path.join(self.tmpdir, 'nodes', self.host_name, 'activate.log') self.log_file = None - self.callback = None self._ip_callback = None self.tests = [ ('dhcp port_toggle test', self._dhcp_port_toggle_test), @@ -33,7 +30,7 @@ def __init__(self, host, tmpdir, test_name, module_config): def start(self, port, params, callback, finish_hook): """Start the ip-addr tests""" - self.callback = callback + super().start(port, params, callback, finish_hook) LOGGER.debug('Target device %s starting ipaddr test %s', self.device, self.test_name) self.log_file = open(self.log_path, 'w') self._next_test() diff --git a/daq/runner.py b/daq/runner.py index 388721cce6..afb16b07d0 100644 --- a/daq/runner.py +++ b/daq/runner.py @@ -43,9 +43,10 @@ def __init__(self): self.host = None self.gateway = None self.group = None - self.port = PortInfo() + self.port = None self.dhcp_ready = False self.ip_info = IpInfo() + self.set_id = None def __repr__(self): return self.mac.replace(":", "") @@ -55,19 +56,33 @@ class Devices: """Container for all devices""" def __init__(self): self._devices = {} + self._set_ids = set() - def new_device(self, mac): + def new_device(self, mac, port_info=None): """Adding a new device""" assert mac not in self._devices, "Device with mac: %s is already added." % mac device = Device() device.mac = mac self._devices[mac] = device + device.port = port_info if port_info else PortInfo() + port_no = device.port.port_no + set_id = port_no if port_no else self._allocate_set_id() + assert set_id not in self._set_ids, "Duplicate device set id %d" % set_id + self._set_ids.add(set_id) + device.set_id = set_id return device + def _allocate_set_id(self): + set_id = 1 + while set_id in self._set_ids: + set_id += 1 + return set_id + def remove(self, device): """Removing a device""" assert self.contains(device), "Device %s not found." % device del self._devices[device.mac] + self._set_ids.remove(device.set_id) def get(self, device_mac): """Get a device using its mac address""" @@ -303,8 +318,7 @@ def _handle_port_learn(self, dpid, port, vid, target_mac): self._ports[port] = PortInfo() self._ports[port].port_no = port if not self._devices.get(target_mac): - device = self._devices.new_device(target_mac) - device.port = self._ports[port] + self._devices.new_device(target_mac, port_info=self._ports[port]) self._target_set_trigger(self._devices.get(target_mac)) else: LOGGER.debug('Port %s dpid %s learned %s (ignored)', port, dpid, target_mac) diff --git a/testing/unit/test_runner.py b/testing/unit/test_runner.py index eb729be9be..70e285816b 100644 --- a/testing/unit/test_runner.py +++ b/testing/unit/test_runner.py @@ -43,7 +43,7 @@ def setUp(self): def test_reap_stale_ports(self): """Test port flap timeout config override""" self.runner.target_set_error = MagicMock() - device = self.runner._devices.new_device("0000000000") + device = self.runner._devices.new_device("0000000000", None) self.runner._reap_stale_ports() self.runner.target_set_error.assert_not_called() ConnectedHost.__init__ = MagicMock(return_value=None) From f842fd33306ded18bb00d1c34afc595322349081 Mon Sep 17 00:00:00 2001 From: henry54809 Date: Tue, 18 Aug 2020 17:31:10 -0700 Subject: [PATCH 096/212] Feature/convert switchtests (#601) --- bin/setup_base | 1 + daq/host.py | 3 +- subset/switches/Dockerfile.test_switch | 6 +- subset/switches/pom.xml | 177 +++-- subset/switches/readme.md | 8 +- .../src/main/java/switchtest/Main.java | 71 +- .../switchtest/SupportedSwitchModelsEnum.java | 6 - .../java/switchtest/SwitchInterrogator.java | 172 ----- .../switchtest/SwitchTelnetClientSocket.java | 272 ------- .../src/main/java/switchtest/SwitchTest.java | 171 +++++ .../AlliedSwitchTelnetClientSocket.java | 189 ----- .../switchtest/allied/AlliedTelesisX230.java | 676 ------------------ .../main/java/switchtest/cisco/Cisco9300.java | 523 -------------- .../cisco/CiscoSwitchTelnetClientSocket.java | 60 -- subset/switches/test_switch | 6 +- .../daq/usi/allied/AlliedTelesisX230.java | 8 +- .../main/java/daq/usi/cisco/Cisco9300.java | 4 + usi/src/main/proto/usi.proto | 6 + 18 files changed, 362 insertions(+), 1997 deletions(-) delete mode 100644 subset/switches/src/main/java/switchtest/SupportedSwitchModelsEnum.java delete mode 100644 subset/switches/src/main/java/switchtest/SwitchInterrogator.java delete mode 100644 subset/switches/src/main/java/switchtest/SwitchTelnetClientSocket.java create mode 100644 subset/switches/src/main/java/switchtest/SwitchTest.java delete mode 100644 subset/switches/src/main/java/switchtest/allied/AlliedSwitchTelnetClientSocket.java delete mode 100644 subset/switches/src/main/java/switchtest/allied/AlliedTelesisX230.java delete mode 100644 subset/switches/src/main/java/switchtest/cisco/Cisco9300.java delete mode 100644 subset/switches/src/main/java/switchtest/cisco/CiscoSwitchTelnetClientSocket.java diff --git a/bin/setup_base b/bin/setup_base index 6ccd6e8dee..97d830b424 100755 --- a/bin/setup_base +++ b/bin/setup_base @@ -61,6 +61,7 @@ if [ -n "$DEF_IFACE" ]; then echo Allowing docker external access through interface $DEF_IFACE... sudo iptables -o docker0 -i $DEF_IFACE -A FORWARD -j ACCEPT sudo iptables -i docker0 -o $DEF_IFACE -A FORWARD -j ACCEPT + sudo iptables -A INPUT -i docker0 -j ACCEPT fi echo Logout and log back in to run tutorials without sudo! diff --git a/daq/host.py b/daq/host.py index 5d5f17a74e..5fd29cb6ff 100644 --- a/daq/host.py +++ b/daq/host.py @@ -740,7 +740,8 @@ def _merge_run_info(self, config): 'run_id': self.run_id, 'mac_addr': self.target_mac, 'started': gcp.get_timestamp(), - 'switch': self._get_switch_config() + 'switch': self._get_switch_config(), + 'usi': self._usi_config } config['run_info'].update(self.runner.get_run_info()) diff --git a/subset/switches/Dockerfile.test_switch b/subset/switches/Dockerfile.test_switch index 9acd5cb4d6..64cba8f29d 100644 --- a/subset/switches/Dockerfile.test_switch +++ b/subset/switches/Dockerfile.test_switch @@ -1,13 +1,13 @@ FROM daqf/aardvark:latest # Do this alone first so it can be re-used by other build files. -RUN $AG update && $AG install openjdk-8-jre - -RUN $AG update && $AG install openjdk-8-jdk git +RUN $AG update && $AG install openjdk-11-jdk git RUN $AG update && $AG install maven tcpdump COPY subset/switches/ switches/ +RUN mkdir -p switches/src/main/proto +COPY usi/src/main/proto/* switches/src/main/proto/ COPY subset/switches/module_manifest.json . RUN cd switches && mvn clean compile assembly:single diff --git a/subset/switches/pom.xml b/subset/switches/pom.xml index 18d7f9a8d6..93ac0b31ee 100644 --- a/subset/switches/pom.xml +++ b/subset/switches/pom.xml @@ -1,15 +1,28 @@ - 4.0.0 - com.redstone - switchtest - 0.0.1 -jar + 4.0.0 + com.redstone + switchtest + 0.0.1 + jar switchtest UTF-8 1.8 1.8 + + + + + io.grpc + grpc-bom + 1.31.0 + pom + import + + + + junit @@ -20,56 +33,114 @@ commons-net commons-net - 3.7 + 3.6 + + + io.grpc + grpc-netty-shaded + 1.31.0 + + + io.grpc + grpc-protobuf + 1.31.0 + + + io.grpc + grpc-stub + 1.31.0 + + + org.apache.tomcat + annotations-api + 6.0.53 + provided + + + org.junit.jupiter + junit-jupiter + 5.6.2 + compile - - - - - maven-assembly-plugin - - - - switchtest.Main - - - - jar-with-dependencies - - - - - maven-clean-plugin - 3.1.0 - - - - maven-resources-plugin - 3.2.0 - - - maven-compiler-plugin - 3.8.1 - - - maven-surefire-plugin - 2.22.2 - - - maven-jar-plugin - 3.2.0 - - - maven-install-plugin - 2.5.2 - - - maven-deploy-plugin - 2.8.2 - - - + + + kr.motd.maven + os-maven-plugin + 1.6.2 + + + + + + org.xolstice.maven.plugins + protobuf-maven-plugin + 0.6.1 + + com.google.protobuf:protoc:3.12.0:exe:${os.detected.classifier} + grpc-java + io.grpc:protoc-gen-grpc-java:1.30.0:exe:${os.detected.classifier} + + ${basedir}/src/main/proto + + + + + + compile + compile-custom + + + + + + maven-assembly-plugin + + + + switchtest.Main + + + + jar-with-dependencies + + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.1.0 + + + maven-surefire-plugin + 2.22.2 + + + maven-jar-plugin + 3.2.0 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 9 + 9 + + + \ No newline at end of file diff --git a/subset/switches/readme.md b/subset/switches/readme.md index 547afd0f45..7bc1bfab2e 100644 --- a/subset/switches/readme.md +++ b/subset/switches/readme.md @@ -62,12 +62,16 @@ Example of all necessary parameters in the system.conf related to physical switc # Define the model of the switch to use. This parameter is required. switch_setup.model=CISCO_9300 - #Define the username for the switch. This parameter is optional. + # Define the username for the switch. This parameter is optional. switch_setup.username=tester - #Define the password for the switch. This parameter is optional. + # Define the password for the switch. This parameter is optional. switch_setup.password=switch_p@55 + # Define the usi url using your docker0's ip and port 5000, and re-run bin/setup_base if you're upgrading from versions before 1.9.0 + # Make sure docker's ip range doesn't conflict with that of the switch. Default docker0 ip is 172.17.0.1 + usi.url=172.17.0.1:5000 + ## Conditions for connection.port_duplex - pass -> If the duplex mode is detected as full - fail -> If the duplex mode is detected but not full or if the duplex mode cannot be detected diff --git a/subset/switches/src/main/java/switchtest/Main.java b/subset/switches/src/main/java/switchtest/Main.java index f074805ad2..f53b24a6b1 100644 --- a/subset/switches/src/main/java/switchtest/Main.java +++ b/subset/switches/src/main/java/switchtest/Main.java @@ -1,50 +1,47 @@ package switchtest; -import switchtest.allied.AlliedTelesisX230; -import switchtest.cisco.Cisco9300; +import grpc.SwitchInfo; +import grpc.SwitchModel; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; public class Main { - public static void main(String[] args) throws Exception { + /** + * Switch test runner. + * @param args args + */ + public static void main(String[] args) { - if (args.length < 4) { + if (args.length < 6) { throw new IllegalArgumentException( - "Expected ipAddress && port && supportPOE && switchModel as arguments"); + "args: usiUrl rpcTimeoutSec switchIpAddress port supportPOE switchModel" + + " [username] [password]"); } - String ipAddress = args[0]; - - int interfacePort = Integer.parseInt(args[1]); - - boolean supportsPOE = args[2].equals("true"); - - SupportedSwitchModelsEnum switchModel = null; - try { - switchModel = SupportedSwitchModelsEnum.valueOf(args[3]); - } catch (Exception e) { - System.out.println("Unknown Switch Model: " + args[3]); - throw e; + String usiUrl = args[0]; + int rpcTimeoutSec = Integer.parseInt(args[1]); + String ipAddress = args[2]; + + int interfacePort = Integer.parseInt(args[3]); + boolean supportsPoe = args[4].equals("true"); + SwitchModel switchModel = SwitchModel.valueOf(args[5]); + String username = ""; + String password = ""; + if (args.length > 6) { + username = args[6]; } - - String user = null; - if (args.length >= 5) { - user = args[4]; - } - String password = null; - if (args.length >= 6) { - password = args[5]; - } - - SwitchInterrogator switchInterrogator = null; - switch (switchModel) { - case CISCO_9300: - switchInterrogator = new Cisco9300(ipAddress, interfacePort, supportsPOE, user, password); - break; - case ALLIED_TELESIS_X230: - switchInterrogator = - new AlliedTelesisX230(ipAddress, interfacePort, supportsPOE, user, password); + if (args.length > 7) { + password = args[7]; } - Thread switchInterrogatorThread = new Thread(switchInterrogator); - switchInterrogatorThread.start(); + SwitchInfo switchInfo = SwitchInfo.newBuilder() + .setDevicePort(interfacePort) + .setIpAddr(ipAddress) + .setModel(switchModel) + .setUsername(username) + .setPassword(password).build(); + ManagedChannel channel = ManagedChannelBuilder.forTarget(usiUrl).usePlaintext().build(); + SwitchTest switchTest = new SwitchTest(channel, rpcTimeoutSec, supportsPoe, false); + switchTest.test(switchInfo); } } diff --git a/subset/switches/src/main/java/switchtest/SupportedSwitchModelsEnum.java b/subset/switches/src/main/java/switchtest/SupportedSwitchModelsEnum.java deleted file mode 100644 index fb074b2d8c..0000000000 --- a/subset/switches/src/main/java/switchtest/SupportedSwitchModelsEnum.java +++ /dev/null @@ -1,6 +0,0 @@ -package switchtest; - -public enum SupportedSwitchModelsEnum { - ALLIED_TELESIS_X230, - CISCO_9300 -} diff --git a/subset/switches/src/main/java/switchtest/SwitchInterrogator.java b/subset/switches/src/main/java/switchtest/SwitchInterrogator.java deleted file mode 100644 index 9114767afa..0000000000 --- a/subset/switches/src/main/java/switchtest/SwitchInterrogator.java +++ /dev/null @@ -1,172 +0,0 @@ -package switchtest; - -/* - * Licensed to the Google under one or more contributor license agreements. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.HashMap; - -public abstract class SwitchInterrogator implements Runnable { - - // Define Common Variables Required for All Switch Interrogators - protected SwitchTelnetClientSocket telnetClientSocket; - protected Thread telnetClientSocketThread; - - protected String remoteIpAddress; - protected int interfacePort = 12; - protected boolean deviceConfigPoeEnabled = false; - protected int remotePort = 23; - - protected boolean switchSupportsPoe = false; - private boolean userAuthorised = false; - private boolean userEnabled = false; - - private String device_hostname = ""; - protected String reportFilename = "tmp/report.txt"; - protected String login_report = ""; - - protected boolean debug = true; - - // TODO: enabled the user to input their own username and password - protected String username = "admin"; - protected String password = "password"; - - public SwitchInterrogator( - String remoteIpAddress, int interfacePort, boolean deviceConfigPoeEnabled) { - this.remoteIpAddress = remoteIpAddress; - this.interfacePort = interfacePort; - this.deviceConfigPoeEnabled = deviceConfigPoeEnabled; - // Load all the switch specific variables - this.command = commands(); - this.commandToggle = commandToggle(); - this.expected = expected(); - this.interface_expected = interfaceExpected(); - this.login_expected = loginExpected(); - this.platform_expected = platformExpected(); - this.power_expected = powerExpected(); - this.show_interface_expected = showInterfaceExpected(); - this.show_interface_port_expected = showInterfacePortExpected(); - this.show_platform_expected = showPlatformExpected(); - this.show_platform_port_expected = showPlatformPortExpected(); - this.show_power_expected = showPowerExpected(); - this.stack_expected = stackExpected(); - this.show_stack_expected = showStackExpected(); - } - - protected String[] command; - protected String[] commandToggle; - protected String[] expected; - protected String[] interface_expected; - public String[] login_expected; - protected String[] platform_expected; - protected String[] power_expected; - protected String[] show_platform_expected; - protected String[] show_power_expected; - protected String[] show_interface_expected; - protected String[] show_interface_port_expected; - protected String[] show_platform_port_expected; - protected String[] stack_expected; - protected String[] show_stack_expected; - - protected abstract String[] commands(); - - protected abstract String[] commandToggle(); - - protected abstract String[] expected(); - - protected abstract String[] interfaceExpected(); - - protected abstract String[] loginExpected(); - - protected abstract String[] platformExpected(); - - protected abstract String[] powerExpected(); - - protected abstract String[] showInterfaceExpected(); - - protected abstract String[] showInterfacePortExpected(); - - protected abstract String[] showPlatformExpected(); - - protected abstract String[] showPlatformPortExpected(); - - protected abstract String[] showPowerExpected(); - - protected abstract String[] stackExpected(); - - protected abstract String[] showStackExpected(); - - protected HashMap interface_map = new HashMap(); - - protected HashMap platform_map = new HashMap(); - - protected HashMap power_map = new HashMap(); - - protected HashMap stack_map = new HashMap(); - - public void setHostname(String device_hostname) { - this.device_hostname = device_hostname; - } - - public String getHostname() { - return device_hostname; - } - - public boolean getUserAuthorised() { - return userAuthorised; - } - - public void setUserAuthorised(boolean userAuthorised) { - this.userAuthorised = userAuthorised; - } - - public boolean getUserEnabled() { - return userEnabled; - } - - public void setUserEnabled(boolean userEnabled) { - this.userEnabled = userEnabled; - } - - public abstract void receiveData(String data); - - @Override - public void run() { - telnetClientSocketThread = new Thread(telnetClientSocket); - telnetClientSocketThread.start(); - } - - protected void writeReport() { - try { - if (debug) { - System.out.println("login_report:" + login_report); - } - - String[] directory = reportFilename.split("/"); - - File dir = new File(directory[directory.length - 2]); - if (!dir.exists()) dir.mkdirs(); - - BufferedWriter writer = new BufferedWriter(new FileWriter(reportFilename)); - writer.write(login_report); - writer.close(); - } catch (IOException e) { - System.err.println("Exception writeReport:" + e.getMessage()); - } - } -} diff --git a/subset/switches/src/main/java/switchtest/SwitchTelnetClientSocket.java b/subset/switches/src/main/java/switchtest/SwitchTelnetClientSocket.java deleted file mode 100644 index 5ba215537a..0000000000 --- a/subset/switches/src/main/java/switchtest/SwitchTelnetClientSocket.java +++ /dev/null @@ -1,272 +0,0 @@ -package switchtest; - -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.Queue; -import org.apache.commons.net.telnet.EchoOptionHandler; -import org.apache.commons.net.telnet.InvalidTelnetOptionException; -import org.apache.commons.net.telnet.SuppressGAOptionHandler; -import org.apache.commons.net.telnet.TelnetClient; -import org.apache.commons.net.telnet.TelnetNotificationHandler; -import org.apache.commons.net.telnet.TerminalTypeOptionHandler; - -public abstract class SwitchTelnetClientSocket implements TelnetNotificationHandler, Runnable { - protected TelnetClient telnetClient = null; - protected SwitchInterrogator interrogator; - - protected String remoteIpAddress = ""; - protected int remotePort = 23; - - protected InputStream inputStream; - protected OutputStream outputStream; - - protected Queue rxQueue = new LinkedList<>(); - - protected Thread readerThread; - protected Thread gatherThread; - - protected boolean debug = false; - - public SwitchTelnetClientSocket( - String remoteIpAddress, int remotePort, SwitchInterrogator interrogator, boolean debug) { - this.remoteIpAddress = remoteIpAddress; - this.remotePort = remotePort; - this.interrogator = interrogator; - this.debug = debug; - telnetClient = new TelnetClient(); - addOptionHandlers(); - } - - protected void connectTelnetSocket() { - int attempts = 0; - - while (!telnetClient.isConnected() && attempts < 10) { - try { - telnetClient.connect(remoteIpAddress, remotePort); - } catch (IOException e) { - System.err.println("Exception while connecting:" + e.getMessage()); - } - - attempts++; - - try { - Thread.sleep(100); - } catch (InterruptedException e) { - System.err.println("Exception while connecting:" + e.getMessage()); - } - } - } - - @Override - public void run() { - connectTelnetSocket(); - - Runnable readDataRunnable = - () -> { - readData(); - }; - readerThread = new Thread(readDataRunnable); - - readerThread.start(); - - Runnable gatherDataRunnable = - () -> { - gatherData(); - }; - gatherThread = new Thread(gatherDataRunnable); - - gatherThread.start(); - - outputStream = telnetClient.getOutputStream(); - } - - protected abstract void gatherData(); - - /** - * * Callback method called when TelnetClient receives an option negotiation command. - * - * @param negotiation_code - type of negotiation command received (RECEIVED_DO, RECEIVED_DONT, - * RECEIVED_WILL, RECEIVED_WONT, RECEIVED_COMMAND) - * @param option_code - code of the option negotiated * - */ - public void receivedNegotiation(int negotiation_code, int option_code) { - String command = null; - switch (negotiation_code) { - case TelnetNotificationHandler.RECEIVED_DO: - command = "DO"; - break; - case TelnetNotificationHandler.RECEIVED_DONT: - command = "DONT"; - break; - case TelnetNotificationHandler.RECEIVED_WILL: - command = "WILL"; - break; - case TelnetNotificationHandler.RECEIVED_WONT: - command = "WONT"; - break; - case TelnetNotificationHandler.RECEIVED_COMMAND: - command = "COMMAND"; - break; - default: - command = Integer.toString(negotiation_code); // Should not happen - break; - } - System.out.println("Received " + command + " for option code " + option_code); - } - - private void addOptionHandlers() { - TerminalTypeOptionHandler terminalTypeOptionHandler = - new TerminalTypeOptionHandler("VT100", false, false, true, false); - - EchoOptionHandler echoOptionHandler = new EchoOptionHandler(false, false, false, false); - - SuppressGAOptionHandler suppressGAOptionHandler = - new SuppressGAOptionHandler(true, true, true, true); - - try { - telnetClient.addOptionHandler(terminalTypeOptionHandler); - telnetClient.addOptionHandler(echoOptionHandler); - telnetClient.addOptionHandler(suppressGAOptionHandler); - } catch (InvalidTelnetOptionException e) { - System.err.println( - "Error registering option handlers InvalidTelnetOptionException: " + e.getMessage()); - } catch (IOException e) { - System.err.println("Error registering option handlers IOException: " + e.getMessage()); - } - } - - private String normalizeLineEnding(byte[] bytes, char endChar) { - String data = new String(bytes); - - List bytesBuffer = new ArrayList(); - - int countBreak = 0; - int countESC = 0; - - for (int i = 0; i < bytes.length; i++) { - if (bytes[i] != 0) { - switch (bytes[i]) { - case 8: - // backspace \x08 - break; - case 10: - // newLineFeed \x0A - countBreak++; - bytesBuffer.add((byte) endChar); - break; - case 13: - // carriageReturn \x0D - countBreak++; - bytesBuffer.add((byte) endChar); - break; - case 27: - // escape \x1B - countESC = 2; - break; - case 33: - // character:! - break; - default: - if (countESC == 0) { - if (countBreak > 1) { - int size = bytesBuffer.size(); - for (int x = 0; x < countBreak - 1; x++) { - bytesBuffer.remove(size - 1 - x); - } - countBreak = 0; - } - bytesBuffer.add(bytes[i]); - } else { - countESC--; - } - break; - } - } - } - - String bytesString = ""; - - for (Byte byteBuffer : bytesBuffer) { - bytesString = bytesString + (char) (byte) byteBuffer; - } - - return bytesString; - } - - protected void readData() { - int bytesRead = 0; - - inputStream = telnetClient.getInputStream(); - - while (telnetClient.isConnected()) { - try { - byte[] buffer = new byte[1024]; - - bytesRead = inputStream.read(buffer); - if (bytesRead > 0) { - String rawData = normalizeLineEnding(buffer, '\n'); - rxQueue.add(rawData); - // Useful for debugging - // rxQueue.add(new String(buffer, 0, bytesRead, StandardCharsets.UTF_8)); - } else { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - System.err.println("InterruptedException readData:" + e.getMessage()); - } - } - } catch (IOException e) { - System.err.println("Exception while reading socket:" + e.getMessage()); - } - } - } - - public void writeData(String data) { - Runnable runnable = - () -> { - writeOutputStream(data); - }; - Thread writeThread = new Thread(runnable); - writeThread.start(); - } - - private void writeOutputStream(String data) { - try { - outputStream.write(data.getBytes()); - // Useful for debugging - // outputStream.write(data.getBytes(StandardCharsets.UTF_8)); - outputStream.flush(); - } catch (IOException e) { - System.err.println("Exception while writing socket:" + e.getMessage()); - } - } - - public void disposeConnection() { - try { - telnetClient.disconnect(); - } catch (IOException e) { - System.err.println("Exception while disposeConnection:" + e.getMessage()); - } - } -} diff --git a/subset/switches/src/main/java/switchtest/SwitchTest.java b/subset/switches/src/main/java/switchtest/SwitchTest.java new file mode 100644 index 0000000000..45bb9b4550 --- /dev/null +++ b/subset/switches/src/main/java/switchtest/SwitchTest.java @@ -0,0 +1,171 @@ +package switchtest; + +import grpc.InterfaceResponse; +import grpc.LinkStatus; +import grpc.POENegotiation; +import grpc.POEStatus; +import grpc.POESupport; +import grpc.PowerResponse; +import grpc.SwitchInfo; +import grpc.USIServiceGrpc; +import io.grpc.Channel; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +public class SwitchTest { + + enum Result { + PASS, + FAIL, + SKIP + } + + private final USIServiceGrpc.USIServiceBlockingStub blockingStub; + protected String reportFilename = "tmp/report.txt"; + protected boolean debug; + protected boolean deviceConfigPoeEnabled; + protected int rpcTimeoutSec; + protected List results = new ArrayList<>(); + /** + * Generic switch test. + * @param channel GRPC channel + * @param rpcTimeoutSec Timeout in seconds for rpc calls + * @param deviceConfigPoeEnabled poe config from module_config + * @param debug print debug output + */ + + public SwitchTest(Channel channel, int rpcTimeoutSec, boolean deviceConfigPoeEnabled, + boolean debug) { + this.debug = debug; + blockingStub = USIServiceGrpc.newBlockingStub(channel); + this.deviceConfigPoeEnabled = deviceConfigPoeEnabled; + this.rpcTimeoutSec = rpcTimeoutSec; + } + + protected void captureResult(String test, Result result, String additional) { + results.add("RESULT " + result.name().toLowerCase() + " " + test + " " + additional); + } + + protected void testLink(InterfaceResponse interfaceResponse) { + final String testName = "connection.port_link"; + if (interfaceResponse.getLinkStatus() == LinkStatus.UP) { + captureResult(testName, Result.PASS, "Link is up"); + } else { + captureResult(testName, Result.FAIL, "Link is down"); + } + } + + protected void testSpeed(InterfaceResponse interfaceResponse) { + final String testName = "connection.port_speed"; + int linkSpeed = interfaceResponse.getLinkSpeed(); + if (linkSpeed > 0) { + if (linkSpeed >= 10) { + captureResult(testName, Result.PASS, + "Speed auto-negotiated successfully. Speed is greater than 10 MBPS"); + } else { + captureResult(testName, Result.FAIL, + "Speed is too slow. Speed is less than or equal to 10 mbps"); + } + } else { + captureResult(testName, Result.FAIL, "Cannot detect current speed"); + } + } + + protected void testDuplex(InterfaceResponse interfaceResponse) { + final String testName = "connection.port_duplex"; + String duplex = interfaceResponse.getDuplex(); + if (duplex != null) { + if (duplex.equals("full")) { + captureResult(testName, Result.PASS, "Full duplex mode detected"); + } else { + captureResult(testName, Result.FAIL, "Incorrect duplex mode set"); + } + } else { + captureResult(testName, Result.FAIL, " Cannot detect duplex mode"); + } + } + + protected void testPower(PowerResponse powerResponse) { + if (!deviceConfigPoeEnabled) { + captureResult("poe.power", Result.SKIP, "This test is disabled"); + captureResult("poe.negotiation", Result.SKIP, "This test is disabled"); + captureResult("poe.support", Result.SKIP, "This test is disabled"); + return; + } + + POEStatus poeStatus = powerResponse.getPoeStatus(); + // Determine PoE power test result + if (poeStatus == POEStatus.ON) { + if (powerResponse.getMaxPowerConsumption() >= powerResponse.getCurrentPowerConsumption()) { + captureResult("poe.power", Result.PASS, "PoE is applied to device"); + } else { + captureResult("poe.power", Result.FAIL, "device wattage exceeds the max wattage"); + } + } else if (poeStatus == POEStatus.OFF) { + captureResult("poe.power", Result.FAIL, "No poE is applied"); + } else if (poeStatus == POEStatus.FAULT) { + captureResult("poe.power", Result.FAIL, + "Device detection or a powered device is in a faulty state"); + } else { + captureResult("poe.power", Result.FAIL, "A powered device is detected, " + + "but no PoE is available, or the maximum wattage exceeds the " + + "detected powered-device maximum."); + } + + // Determine PoE auto negotiation result + if (powerResponse.getPoeNegotiation() == POENegotiation.NEGOTIATION_ENABLED) { + captureResult("poe.negotiation", Result.PASS, "PoE auto-negotiated successfully"); + } else { + captureResult("poe.negotiation", Result.FAIL, "Incorrect privilege for negotiation"); + } + + // Determine PoE support result + if (powerResponse.getPoeSupport() == POESupport.ENABLED) { + captureResult("poe.support", Result.PASS, "PoE is supported and enabled"); + } else { + captureResult("poe.support", Result.FAIL, + "The switch does not support PoE or it is disabled"); + } + } + + protected void writeReport() { + try { + String report = String.join("\n", results); + if (debug) { + System.out.println("report:" + report); + } + + String[] directory = reportFilename.split("/"); + + File dir = new File(directory[directory.length - 2]); + dir.mkdirs(); + + BufferedWriter writer = new BufferedWriter(new FileWriter(reportFilename)); + writer.write(report); + writer.close(); + } catch (IOException e) { + System.err.println("Exception when writing report:" + e.getMessage()); + } + } + + /** + * Run a switch test with the specified switch info. + * @param switchInfo SwitchInfo from the USI proto file + */ + public void test(SwitchInfo switchInfo) { + final PowerResponse powerResponse = blockingStub + .withDeadlineAfter(rpcTimeoutSec, TimeUnit.SECONDS).getPower(switchInfo); + final InterfaceResponse interfaceResponse = blockingStub + .withDeadlineAfter(rpcTimeoutSec, TimeUnit.SECONDS).getInterface(switchInfo); + testLink(interfaceResponse); + testSpeed(interfaceResponse); + testDuplex(interfaceResponse); + testPower(powerResponse); + writeReport(); + } +} diff --git a/subset/switches/src/main/java/switchtest/allied/AlliedSwitchTelnetClientSocket.java b/subset/switches/src/main/java/switchtest/allied/AlliedSwitchTelnetClientSocket.java deleted file mode 100644 index 79e3cfa609..0000000000 --- a/subset/switches/src/main/java/switchtest/allied/AlliedSwitchTelnetClientSocket.java +++ /dev/null @@ -1,189 +0,0 @@ -package switchtest.allied; - -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import switchtest.SwitchInterrogator; -import switchtest.SwitchTelnetClientSocket; - -public class AlliedSwitchTelnetClientSocket extends SwitchTelnetClientSocket { - public AlliedSwitchTelnetClientSocket( - String remoteIpAddress, int remotePort, SwitchInterrogator interrogator, boolean debug) { - super(remoteIpAddress, remotePort, interrogator, debug); - } - - protected void gatherData() { - StringBuilder rxData = new StringBuilder(); - String rxGathered = ""; - - boolean parseFlag = false; - - int count = 0; - int flush = 0; - int rxQueueCount = 0; - int rxTempCount = 0; - int expectedLength = 1000; - int requestFlag = 0; - - while (telnetClient.isConnected()) { - try { - - if (rxQueue.isEmpty()) { - Thread.sleep(100); - rxQueueCount++; - if (debug) { - System.out.println("rxQueue.isEmpty:" + rxQueueCount); - System.out.println("expectedLength:" + expectedLength); - System.out.println("requestFlag:" + requestFlag); - } - if (rxQueueCount > 70) { - rxQueueCount = 0; - writeData("\n"); - } - } else { - rxQueueCount = 0; - String rxTemp = rxQueue.poll(); - if (rxTemp.equals("")) { - Thread.sleep(100); - rxTempCount++; - if (debug) { - System.out.println("rxTemp.equals:" + rxTempCount); - } - } else if (rxTemp.indexOf("--More--") > 0) { - Thread.sleep(20); - writeData("\n"); - - if (debug) { - System.out.println("more position:" + rxTemp.indexOf("--More--")); - System.out.println("rxTemp.length" + rxTemp.length() + "rxTemp pre:" + rxTemp); - // Useful for debugging - // char[] tempChar = rxTemp.toCharArray(); - // for(char temp:tempChar) { - // System.out.println("tempChar:"+(byte)temp); - // } - } - - rxTemp = rxTemp.substring(0, rxTemp.length() - 9); - - if (debug) { - System.out.println("rxTemp.length" + rxTemp.length() + "rxTemp post:" + rxTemp); - } - - rxData.append(rxTemp); - } else { - rxQueueCount = 0; - rxTempCount = 0; - rxData.append(rxTemp); - rxGathered = rxData.toString(); - System.out.println( - java.time.LocalTime.now() - + "rxDataLen:" - + rxGathered.length() - + "rxData:" - + rxGathered); - - int position = -1; - - int charLength = 1; - int beginPosition = 0; - System.out.println("count is:" + count); - - String[] loginExpected = interrogator.login_expected; - int[] loginExpectedLength = {5, 5, 40}; - - String hostname = interrogator.getHostname(); - requestFlag = ((AlliedTelesisX230) interrogator).getRequestFlag() - 1; - - boolean[] requestFlagIndexOf = {false, false, false, true, false}; - String[] requestFlagExpected = {hostname, hostname, hostname, "end", hostname}; - int[] requestFlagExpectedLength = {600, 600, 50, 1000, 290}; - int[] requestFlagCharLength = { - hostname.length() + 1, hostname.length() + 1, hostname.length() + 1, 3, -1 - }; - int[] requestFlagFlush = {0, 0, 0, 15, 0}; - - // login & enable process - if (count < 3) { - position = rxGathered.indexOf(loginExpected[count]); - if (position >= 0) { - expectedLength = loginExpectedLength[count]; - if (count == 2) { - interrogator.setUserAuthorised(true); - } - count++; - } - } else if ((count % 2) != 0) { - position = rxGathered.indexOf(interrogator.getHostname()); - if (position >= 0) { - interrogator.setUserEnabled(true); - expectedLength = 2; - charLength = interrogator.getHostname().length() + 1; - flush = 0; - beginPosition = 0; - count++; - } - } else { - position = - findPosition( - rxGathered, - requestFlagExpected[requestFlag], - requestFlagIndexOf[requestFlag]); - if (position >= 0) { - expectedLength = requestFlagExpectedLength[requestFlag]; - charLength = requestFlagCharLength[requestFlag]; - flush = requestFlagFlush[requestFlag]; - if (rxGathered.length() >= expectedLength) { - beginPosition = 4; - count++; - } - } - } - System.out.println("Position: " + position); - System.out.println("RxGathered: " + rxGathered.length()); - System.out.println("Expected Length: " + expectedLength); - System.out.println("rxGathered: " + rxGathered); - - if (position >= 0 && rxGathered.length() >= expectedLength) { - rxGathered = rxGathered.substring(beginPosition, position + charLength); - System.out.println( - java.time.LocalTime.now() - + "rxGatheredLen:" - + rxGathered.length() - + "rxGathered:" - + rxGathered); - rxData.delete(0, position + charLength + flush); - - interrogator.receiveData(rxGathered); - } - } - } - } catch (InterruptedException e) { - System.err.println("InterruptedException gatherData:" + e.getMessage()); - } - } - } - - protected int findPosition(String rxGathered, String value, boolean indexOf) { - int position = -1; - if (indexOf) { - position = rxGathered.indexOf(value); - } else { - position = rxGathered.lastIndexOf(value); - } - return position; - } -} diff --git a/subset/switches/src/main/java/switchtest/allied/AlliedTelesisX230.java b/subset/switches/src/main/java/switchtest/allied/AlliedTelesisX230.java deleted file mode 100644 index 306eb8ba64..0000000000 --- a/subset/switches/src/main/java/switchtest/allied/AlliedTelesisX230.java +++ /dev/null @@ -1,676 +0,0 @@ -package switchtest.allied; - -/* - * Licensed to the Google under one or more contributor license agreements. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import switchtest.SwitchInterrogator; - -import java.util.HashMap; - -public class AlliedTelesisX230 extends SwitchInterrogator { - - protected int interfacePos = 1; - protected int platformPos = 2; - protected int powerinlinePos = 3; - - protected int shortPacketLength = 20; - protected int requestFlag = 0; - protected int number_switch_ports = 1; // 48 - protected boolean extendedTests = false; - - protected int[] show_platform_pointers; - protected String[] show_platform_data; - protected int[] show_platform_port_pointers; - protected int[] show_interface_pointers; - protected String[] show_interface_data; - protected int[] show_interface_port_pointers; - protected int[] show_power_pointers; - protected String[] show_power_data; - protected int[] show_stack_pointers; - protected String[] show_stack_data; - - public AlliedTelesisX230( - String remoteIpAddress, - int interfacePort, - boolean deviceConfigPoeEnabled, - String user, - String password) { - super(remoteIpAddress, interfacePort, deviceConfigPoeEnabled); - telnetClientSocket = - new AlliedSwitchTelnetClientSocket(remoteIpAddress, remotePort, this, debug); - this.username = user == null ? "manager" : user; - this.password = password == null ? "friend" : password; - // Adjust commands to active switch configuration - command[interfacePos] = command[interfacePos] + interfacePort; - command[platformPos] = command[platformPos] + interfacePort; - command[powerinlinePos] = command[powerinlinePos] + interfacePort; - - // Initialize data arrays based on switch specific command sets - show_interface_pointers = new int[show_interface_expected.length]; - show_interface_data = new String[show_interface_expected.length / 2]; - show_interface_port_pointers = new int[show_interface_port_expected.length]; - - show_platform_pointers = new int[show_platform_expected.length]; - show_platform_data = new String[show_platform_expected.length / 2]; - show_platform_port_pointers = new int[show_platform_port_expected.length]; - - show_power_pointers = new int[show_power_expected.length]; - show_power_data = new String[show_power_expected.length - 1]; - - show_stack_pointers = new int[show_stack_expected.length]; - show_stack_data = new String[show_stack_expected.length - 1]; - } - - public int getRequestFlag() { - return requestFlag - 1; - } - - public void receiveData(String data) { - if (debug) { - System.out.println( - java.time.LocalTime.now() + "receiveDataLen:" + data.length() + "receiveData:" + data); - } - if (data != null) { - Thread parseThread = new Thread(() -> parseData(data)); - parseThread.start(); - } - } - - private String cleanShowRunData(String data) { - data = data.replace("\n\n\n\n", "\n"); - data = data.replace("\n\n\n", "\n"); - data = data.replace("\n\n", "\n"); - data = data.replace("end", ""); - return data; - } - - private String poeNormalizeData(String data) { - data = trashLagLines(data, data.indexOf("Interface"), 0); - data = trashLagLines(data, data.indexOf("port"), 1); - return data; - } - - protected void parseData(String data) { - try { - if (data.length() > 0) { - - if (!getUserAuthorised()) { - data = data.substring(0, data.indexOf(":") + 1); - System.out.println("decoded_data:" + data); - - // login procedure - if (data.indexOf(expected[0]) >= 0) { - // username request - String[] data_array = data.split(" "); - setHostname(data_array[0]); - telnetClientSocket.writeData(username + "\n"); - } else if (data.indexOf(expected[1]) >= 0) { - // password request - telnetClientSocket.writeData(password + "\n"); - } - } else { - if (!getUserEnabled()) { - data = data.substring(0, data.indexOf(":") + 1); - if (data.indexOf(expected[2]) >= 0) { - // login success - telnetClientSocket.writeData(command[requestFlag] + "\n"); - requestFlag = 1; - } - } else { - // running configuration requests - if (data.indexOf(getHostname()) >= 0 && data.length() < shortPacketLength) { - int requestFinish = powerinlinePos; - if (extendedTests) { - requestFinish = command.length; - } - if (requestFlag <= requestFinish) { - telnetClientSocket.writeData(command[requestFlag] + "\n"); - System.out.println( - "command:" + command[requestFlag] + " request_flag:" + requestFlag); - requestFlag += 1; - } else { - System.out.println("finished running configuration requests"); - validateTests(); - telnetClientSocket.disposeConnection(); - } - } else { - parseRequestFlag(data, requestFlag); - } - } - } - } - } catch (Exception e) { - System.err.println("Exception parseData:" + e.getMessage()); - } - } - - private void parseRequestFlag(String data, int requestFlag) { - try { - switch (requestFlag) { - case 2: - // parse show interface - login_report += "show interface:\n"; - parse_packet(data, show_interface_port_expected, show_interface_port_pointers); - interface_map = dataToMap(interface_expected, show_interface_data); - writeReport(); - telnetClientSocket.writeData("\n"); - break; - case 3: - // parse show platform - login_report += "\nshow platform:\n"; - parse_packet(data, show_platform_port_expected, show_platform_port_pointers); - platform_map = dataToMap(platform_expected, show_platform_data); - writeReport(); - telnetClientSocket.writeData("\n"); - break; - case 4: - // parse show power-inline - login_report += "\nshow power-inline:\n"; - if (data.contains("Power-inline is disabled")) { - login_report += "Power-inline is disabled\n"; - } else { - switchSupportsPoe = true; - data = poeNormalizeData(data); - parse_inline(data, show_power_expected, show_power_pointers, show_power_data); - power_map = dataToMap(power_expected, show_power_data); - } - writeReport(); - telnetClientSocket.writeData("\n"); - break; - case 5: - // parse show run - data = cleanShowRunData(data); - login_report += "\n" + data; - writeReport(); - telnetClientSocket.writeData("\n"); - break; - case 6: - // parse show stack - login_report += "\nshow stack:\n"; - parse_inline(data, show_stack_expected, show_stack_pointers, show_stack_data); - stack_map = dataToMap(stack_expected, show_stack_data); - writeReport(); - telnetClientSocket.writeData("\n"); - break; - } - } catch (Exception e) { - System.err.println("Exception parseRequestFlag:" + e.getMessage()); - System.exit(1); - } - } - - private void parse_packet(String raw_data, String[] show_expected, int[] show_pointers) { - try { - int start = 0; - for (int port = 0; port < number_switch_ports; port++) { - for (int x = 0; x < show_expected.length; x++) { - start = recursive_data(raw_data, show_expected[x], start); - show_pointers[x] = start; - } - - int chunk_s = show_pointers[0]; - int chunk_e = show_pointers[3]; - - if (chunk_e == -1) chunk_e = raw_data.length(); - - String temp_data = raw_data.substring(chunk_s, chunk_e); - - if (debug) System.out.println("length" + temp_data.length() + "temp_data:" + temp_data); - - if (requestFlag == (interfacePos + 1)) { - parse_single( - temp_data, show_interface_expected, show_interface_pointers, show_interface_data); - } else if (requestFlag == (platformPos + 1)) { - parse_single( - temp_data, show_platform_expected, show_platform_pointers, show_platform_data); - } - } - } catch (Exception e) { - System.err.println("Exception parse_packet:" + e.getMessage()); - System.exit(1); - } - } - - private void parse_single( - String raw_data, String[] expected_array, int[] pointers_array, String[] data_array) { - try { - int start = 0; - for (int x = 0; x < expected_array.length; x++) { - start = recursive_data(raw_data, expected_array[x], start); - if (start == -1) { - start = pointers_array[x - 1]; - pointers_array[x] = -1; - } else { - pointers_array[x] = start; - } - } - - for (int x = 0; x < data_array.length; x++) { - int chunk_start = x * 2; - int chunk_end = 1 + (x * 2); - - int chunk_s = pointers_array[chunk_start]; - int chunk_e = pointers_array[chunk_end]; - - if (chunk_s > 0) { - if (chunk_e == -1) chunk_e = raw_data.length(); - - data_array[x] = raw_data.substring(chunk_s, chunk_e); - - data_array[x] = data_array[x].substring(expected_array[chunk_start].length()); - - String extracted_data = expected_array[chunk_start] + data_array[x]; - - if (debug) System.out.println(extracted_data); - - login_report += extracted_data + "\n"; - } - } - } catch (Exception e) { - System.err.println("Exception parse_single:" + e.getMessage()); - System.exit(1); - } - } - - protected void parse_inline( - String raw_data, String[] expected, int[] pointers, String[] data_array) { - try { - int start = 0; - - for (int x = 0; x < expected.length; x++) { - start = recursive_data(raw_data, expected[x], start); - pointers[x] = start; - if (x > 0) { - pointers[x - 1] = pointers[x] - pointers[x - 1]; - } - } - int chunk_start = pointers[pointers.length - 1]; - int chunk_end = pointers[pointers.length - 1]; - - for (int x = 0; x < data_array.length; x++) { - chunk_start = chunk_end; - - if (x > 0) { - chunk_start += 1; - } - - chunk_end += pointers[x]; - - if (x != data_array.length - 1) { - data_array[x] = - raw_data.substring(chunk_start, chunk_end).replace("\n", "").replace(" ", ""); - } else { - chunk_end = recursive_data(raw_data, "\n", chunk_start); - data_array[x] = raw_data.substring(chunk_start, chunk_end).replace("\n", ""); - } - login_report += expected[x] + ":" + data_array[x] + "\n"; - } - } catch (Exception e) { - System.err.println("Exception parse_inline:" + e.getMessage()); - System.exit(1); - } - } - - private int recursive_data(String data, String search, int start) { - int pointer = data.indexOf(search, start); - if (debug) { - System.out.println("pointer:" + pointer); - } - return pointer; - } - - protected HashMap dataToMap(String[] expected_key, String[] data_array) { - System.out.println("Data To mape"); - HashMap hashMap = new HashMap(); - for (int i = 0; i < expected_key.length; i++) { - System.out.println("expectedKey: " + expected_key[i]); - hashMap.put(expected_key[i], data_array[i]); - } - return hashMap; - } - - protected String trashLagLines(String data, int index, int lineIndex) { - byte[] dataBytes = data.getBytes(); - int counter = 0; - for (int i = 0; i < index; i++) { - if (dataBytes[i] == '\n') { - counter++; - } - } - if (counter > 0) { - counter -= lineIndex; - } - for (int i = counter; i > 0; i--) { - data = trash_line(data, lineIndex); - } - return data; - } - - private String trash_line(String data, int trash_line) { - String[] lineArray = data.split("\n"); - String tempData = ""; - for (int i = 0; i < lineArray.length; i++) { - if (i != trash_line) { - tempData += lineArray[i] + "\n"; - } - } - return tempData; - } - - private void validateTests() { - try { - login_report += "\n"; - - if (interface_map.get("link_status").equals("UP")) { - login_report += "RESULT pass connection.port_link Link is up\n"; - } else { - login_report += "RESULT fail connection.port_link Link is down\n"; - } - - if (interface_map.get("current_speed") != null) { - if (interface_map.get("configured_speed").equals("auto") - && Integer.parseInt(interface_map.get("current_speed")) >= 10) { - login_report += - "RESULT pass connection.port_speed Speed auto-negotiated successfully. Speed is greater than 10 MBPS\n"; - } else { - login_report += "RESULT fail connection.port_speed Speed is too slow\n"; - } - } else { - login_report += "RESULT fail connection.port_speed Cannot detect current speed\n"; - } - - if (interface_map.get("current_duplex") != null) { - if (interface_map.get("configured_duplex").equals("auto") - && interface_map.get("current_duplex").equals("full")) { - login_report += "RESULT pass connection.port_duplex Full duplex mode detected\n"; - } else { - login_report += "RESULT fail connection.port_duplex Incorrect duplex mode set\n"; - } - } else { - login_report += "RESULT fail connection.port_duplex Cannot detect duplex mode\n"; - } - - if (switchSupportsPoe && deviceConfigPoeEnabled) { - String current_max_power = power_map.get("max").replaceAll("\\D+", ""); - String current_power = power_map.get("power").replaceAll("\\D+", ""); - String current_PoE_admin = power_map.get("admin"); - String current_oper = power_map.get("oper"); - - System.out.println( - "current_max_power:" - + current_max_power - + "current_power:" - + current_power - + "current_PoE_admin:" - + current_PoE_admin - + "current_oper:" - + current_oper); - - if (current_max_power.length() > 0 - && current_power.length() > 0 - && current_PoE_admin.length() > 0 - && current_oper.length() > 0) { - if (Integer.parseInt(current_max_power) > Integer.parseInt(current_power) - && !current_oper.equals("Fault")) { - login_report += "RESULT pass poe.power PoE is applied to device\n"; - } else { - login_report += - "RESULT fail poe.power The DUT is drawing too much current or there is a fault on the line\n"; - } - if (current_PoE_admin.equals("Enabled")) { - login_report += "RESULT pass poe.negotiation PoE auto-negotiated successfully\n"; - } else { - login_report += "RESULT fail poe.negotiation Incorrect privilege for negotiation\n"; - } - if (!current_oper.equals("Off")) { - login_report += "RESULT pass poe.support PoE supported and enabled\n"; - } else { - login_report += - "RESULT fail poe.support The AT switch does not support PoE or it is disabled\n"; - } - } else { - login_report += "RESULT fail poe.power Could not detect any current being drawn\n"; - login_report += "RESULT fail poe.negotiation Could not detect any current being drawn\n"; - login_report += "RESULT fail poe.support Could not detect any current being drawn\n"; - } - } else { - login_report += - "RESULT skip poe.power The AT switch does not support PoE or this test is disabled\n"; - login_report += - "RESULT skip poe.negotiation The AT switch does not support PoE or this test is disabled\n"; - login_report += - "RESULT skip poe.support The AT switch does not support PoE or this test is disabled\n"; - } - - writeReport(); - } catch (Exception e) { - System.err.println("Exception validateTests:" + e.getMessage()); - e.printStackTrace(); - } - } - - public String[] commands() { - return new String[] { - "enable", - "show interface port1.0.", - "show platform port port1.0.", - "show power-inline interface port1.0.", - "show run", - "show stack" - }; - } - - public String[] commandToggle() { - return new String[] {"interface ethernet port1.0.", "shutdown", "no shutdown"}; - } - - public String[] expected() { - return new String[] { - "login:", - "Password:", - "Last login:", - "#", - "Login incorrect", - "Connection closed by foreign host." - }; - } - - public String[] interfaceExpected() { - return new String[] { - "port_number", - "link_status", - "administrative_state", - "current_duplex", - "current_speed", - "current_polarity", - "configured_duplex", - "configured_speed", - "configured_polarity", - "left_chevron", - "input_packets", - "bytes", - "dropped", - "multicast_packets", - "output_packets", - "multicast_packets2", - "broadcast_packets", - "input_average_rate", - "output_average_rate", - "input_peak_rate", - "time_since_last_state_change" - }; - } - - public String[] loginExpected() { - return new String[] {":", ":", ">"}; - } - - public String[] platformExpected() { - return new String[] { - "port_number", - "enabled", - "loopback", - "link", - "speed", - "max_speed", - "duplex", - "linkscan", - "autonegotiate", - "master", - "tx_pause", - "rx_pause", - "untagged_vlan", - "vlan_filter", - "stp_state", - "learn", - "discard", - "jam", - "max_frame_size", - "mc_disable_sa", - "mc_disable_ttl", - "mc_egress_untag", - "mc_egress_vid", - "mc_ttl_threshold" - }; - } - - public String[] powerExpected() { - return new String[] { - "dev_interface", "admin", "pri", "oper", "power", "device", "dev_class", "max" - }; - } - - public String[] showInterfaceExpected() { - return new String[] { - "port1", - "\n", - "Link is ", - ",", - "administrative state is ", - "\n", - "current duplex ", - ",", - "current speed ", - ",", - "current polarity ", - "\n", - "configured duplex ", - ",", - "configured speed ", - ",", - "configured polarity ", - "\n", - "<", - "\n", - "input packets ", - ",", - "bytes ", - ",", - "dropped ", - ",", - "multicast packets ", - "\n", - "output packets ", - ",", - "multicast packets ", - ",", - "broadcast packets ", - "\n", - "input average rate : ", - "\n", - "output average rate: ", - "\n", - "input peak rate ", - "\n", - "Time since last state change: ", - "\n" - }; - } - - public String[] showInterfacePortExpected() { - return new String[] {"port1", "\n", "Time since last state change: ", "\n"}; - } - - public String[] showPlatformExpected() { - return new String[] { - "port1", - "\n", - "enabled:", - "\n", - "loopback:", - "\n", - "link:", - "\n", - "speed:", - "m", - "max speed:", - "\n", - "duplex:", - "\n", - "linkscan:", - "\n", - "autonegotiate:", - "\n", - "master:", - "\n", - "tx pause:", - "r", - "rx pause:", - "\n", - "untagged vlan:", - "\n", - "vlan filter:", - "\n", - "stp state:", - "\n", - "learn:", - "\n", - "discard:", - "\n", - "jam:", - "\n", - "max frame size:", - "\n", - "MC Disable SA:", - "\n", - "MC Disable TTL:", - "\n", - "MC egress untag:", - "\n", - "MC egress vid:", - "\n", - "MC TTL threshold:", - "\n" - }; - } - - public String[] showPlatformPortExpected() { - return new String[] {"port1", "\n", "MC TTL threshold:", "\n"}; - } - - public String[] showPowerExpected() { - return new String[] { - "Interface", "Admin", "Pri", "Oper", "Power", "Device", "Class", "Max", "\n" - }; - } - - public String[] stackExpected() { - return new String[] {"id", "pending_id", "mac_address", "priority", "status", "role"}; - } - - public String[] showStackExpected() { - return new String[] {"ID", "Pending ID", "MAC address", "Priority", "Status", "Role", "\n"}; - } -} diff --git a/subset/switches/src/main/java/switchtest/cisco/Cisco9300.java b/subset/switches/src/main/java/switchtest/cisco/Cisco9300.java deleted file mode 100644 index eaa420e402..0000000000 --- a/subset/switches/src/main/java/switchtest/cisco/Cisco9300.java +++ /dev/null @@ -1,523 +0,0 @@ -package switchtest.cisco; - -/* - * Licensed to the Google under one or more contributor license agreements. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import switchtest.SwitchInterrogator; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -public class Cisco9300 extends SwitchInterrogator { - - int commandIndex = 0; - boolean commandPending = false; - boolean promptReady = false; - StringBuilder rxData = new StringBuilder(); - - /** Cisco Terminal Prompt ends with # when enabled */ - String consolePromptEndingEnabled = "#"; - - String consolePromptEndingLogin = ">"; - - public Cisco9300( - String remoteIpAddress, - int interfacePort, - boolean deviceConfigPoeEnabled, - String user, - String password) { - super(remoteIpAddress, interfacePort, deviceConfigPoeEnabled); - telnetClientSocket = - new CiscoSwitchTelnetClientSocket(remoteIpAddress, remotePort, this, debug); - this.username = user == null ? "admin" : user; - this.password = password == null ? "password" : password; - } - - /** Generic Cisco Switch command to retrieve the Status of an interface. */ - private String showIfaceStatusCommand() { - return "show interface gigabitethernet1/0/" + interfacePort + " status"; - } - - /** - * Generic Cisco Switch command to retrieve the Power Status of an interface. Replace asterisk - * with actual port number for complete message - */ - private String showIfacePowerStatusCommand() { - return "show power inline gigabitethernet1/0/" + interfacePort + " detail"; - } - - /** - * Builds an array of currently supported commands to send to the Cisco Switch for the port - * specified. - * - * @return String array of commands to be submitted to the switch - */ - public String[] commands() { - return new String[] {showIfaceStatusCommand(), showIfacePowerStatusCommand()}; - } - - /** Run all current tests in order and create and store the results */ - public void generateTestResults() { - login_report += "\n"; - login_report += validateLinkTest(); - login_report += validateSpeedTests(); - login_report += validateDuplexTests(); - login_report += validatePowerTests(); - } - - public boolean handleCommandResponse(String consoleData) { - if (consoleData == null) return false; - if (consoleData.endsWith(getHostname() + consolePromptEndingEnabled)) { - // Strip trailing command prompt - String response = - consoleData.substring(0, consoleData.length() - (getHostname() + "#").length()); - // Strip leading command that was sent - response = response.substring(command[commandIndex].length()); - processCommandResponse(response); - promptReady = true; - commandPending = false; - ++commandIndex; - return true; - } - return false; - } - - /** - * Handles the process when using the enter command. Enable is a required step before commands can - * be sent to the switch. - * - * @param consoleData Raw console data received the the telnet connection. - * @return True if the data provided was understood and processed. False if the data is not an - * expected result or the enable process failed. - */ - public boolean handleEnableMessage(String consoleData) throws Exception { - if (consoleData == null) return false; - if (consoleData.indexOf("Password:") >= 0) { - telnetClientSocket.writeData(password + "\n"); - return true; - } else if (consoleData.endsWith(consolePromptEndingEnabled)) { - setUserEnabled(true); - return true; - } else if (consoleData.indexOf("% Bad passwords") >= 0) { - telnetClientSocket.disposeConnection(); - throw new Exception("Could not Enable the User, Bad Password"); - } - return false; - } - - /** - * Handles the process when logging into the switch. - * - * @param consoleData Raw console data received the the telnet connection. - * @return True if the data provided was understood and processed. False if the data is not an - * expected result or if the login failed. - */ - public boolean handleLoginMessage(String consoleData) throws Exception { - if (consoleData == null) return false; - if (consoleData.indexOf("Username:") >= 0) { - telnetClientSocket.writeData(username + "\n"); - return true; - } else if (consoleData.indexOf("Password:") >= 0) { - telnetClientSocket.writeData(password + "\n"); - return true; - } else if (consoleData.endsWith(consolePromptEndingLogin)) { - setUserAuthorised(true); - setHostname(consoleData.split(">")[0]); - telnetClientSocket.writeData("enable\n"); - return true; - } else if (consoleData.indexOf("% Login invalid") >= 0) { - telnetClientSocket.disposeConnection(); - throw new Exception("Failked to Login, Login Invalid"); - } else if (consoleData.indexOf("% Bad passwords") >= 0) { - telnetClientSocket.disposeConnection(); - throw new Exception("Failed to Login, Bad Password"); - } - return false; - } - - /** - * If the message --More-- is present in the current data packet, this indicates the message is - * incomplete. To complete the message, we need to tell the console to continue the response and - * strip the --More-- entry from the data packet as it is not actually part of the response. - * - * @param consoleData Current unprocessed data packet - */ - public void handleMore(String consoleData) { - consoleData = consoleData.substring(0, consoleData.length() - "--More--".length()); - telnetClientSocket.writeData("\n"); - rxData.append(consoleData); - } - - /** - * Receive the raw data packet from the telnet connection and process accordingly. - * - * @param data Most recent data read from the telnet socket buffer - */ - public void receiveData(String data) { - if (debug) { - System.out.println( - java.time.LocalTime.now() + "receiveDataLen:" + data.length() + "receiveData:" + data); - } - if (data != null) { - if (!data.isEmpty()) { - if (data.indexOf("--More--") > 0) { - handleMore(data); - return; - } else { - rxData.append(data); - } - } - try { - if (parseData(rxData.toString())) { - // If we have processed the current buffers data we will clear the buffer - rxData = new StringBuilder(); - } - } catch (Exception e) { - telnetClientSocket.disposeConnection(); - e.printStackTrace(); - } - } - } - - /** - * Handles current data in the buffer read from the telnet console InputStream and sends it to the - * appropriate process. - * - * @param consoleData Current unhandled data in the buffered reader - * @return true if the data was an expected value and appropriately processed and return false if - * the data is not-expected. - */ - public boolean parseData(String consoleData) throws Exception { - consoleData = consoleData.trim(); - if (!getUserAuthorised()) { - return handleLoginMessage(consoleData); - } else if (!getUserEnabled()) { - return handleEnableMessage(consoleData); - } else { - // Logged in and enabled - if (commandPending) { // Command has been sent and awaiting a response - if (handleCommandResponse(consoleData)) { - telnetClientSocket.writeData("\n"); - return true; - } - } else if (command.length > commandIndex) { - if (consoleData.endsWith(getHostname() + consolePromptEndingEnabled)) { - sendNextCommand(); - return true; - } - } else { - generateTestResults(); - writeReport(); - telnetClientSocket.disposeConnection(); - } - } - return false; - } - - public String validateLinkTest() { - String testResults = ""; - if (interface_map.get("status").equals("connected")) { - testResults += "RESULT pass connection.port_link Link is up\n"; - } else { - testResults += "RESULT fail connection.port_link Link is down\n"; - } - return testResults; - } - - public String validateSpeedTests() { - String testResults = ""; - if (interface_map.get("speed") != null) { - String speed = interface_map.get("speed"); - if (speed.startsWith("a-")) { // Interface in Auto Speed - speed = speed.replaceFirst("a-", ""); - } - if (Integer.parseInt(speed) >= 10) { - testResults += - "RESULT pass connection.port_speed Speed auto-negotiated successfully. Speed is greater than 10 MBPS\n"; - } else { - testResults += - "RESULT fail connection.port_speed Speed is too slow. Speed is less than or equal to 10 mbps\n"; - } - } else { - testResults += "RESULT fail connection.port_speed Cannot detect current speed\n"; - } - return testResults; - } - - public String validateDuplexTests() { - String testResults = ""; - if (interface_map.get("duplex") != null) { - String duplex = interface_map.get("duplex"); - if (duplex.startsWith("a-")) { // Interface in Auto Duplex - duplex = duplex.replaceFirst("a-", ""); - } - if (duplex.equals("full")) { - testResults += "RESULT pass connection.port_duplex Full duplex mode detected\n"; - } else { - testResults += "RESULT fail connection.port_duplex Incorrect duplex mode set\n"; - } - } else { - testResults += "RESULT fail connection.port_duplex Cannot detect duplex mode\n"; - } - return testResults; - } - - public String validatePowerTests() { - String testResults = ""; - double maxPower = 0; - double currentPower = 0; - boolean powerAuto = false; - boolean poeDisabled = false; - boolean poeOn = false; - boolean poeOff = false; - boolean poeFault = false; - boolean poeDeny = false; - try { - // Generate test data from mapped results - maxPower = Double.parseDouble(power_map.get("max")); - currentPower = Double.parseDouble(power_map.get("power")); - powerAuto = "auto".equals(power_map.get("admin")); - poeDisabled = "off".equals(power_map.get("admin")); - poeOn = "on".equals(power_map.get("oper")); - poeOff = "off".equals(power_map.get("oper")); - poeFault = "fault".equals(power_map.get("oper")); - poeDeny = "power-deny".equals(power_map.get("oper")); - } catch (Exception e) { - // ToDo: Make these failures specific to the data resolve errors instead of all or nothing - System.out.println("Power Tests Failed: " + e.getMessage()); - e.printStackTrace(); - testResults += "RESULT fail poe.power Could not detect any current being drawn\n"; - testResults += "RESULT fail poe.negotiation Could not detect any current being drawn\n"; - testResults += "RESULT fail poe.support Could not detect any current being drawn\n"; - return testResults; - } - - if (!deviceConfigPoeEnabled) { - testResults += "RESULT skip poe.power This test is disabled\n"; - testResults += "RESULT skip poe.negotiation This test is disabled\n"; - testResults += "RESULT skip poe.support This test is disabled\n"; - - } else if (poeDisabled) { - testResults += "RESULT skip poe.power The switch does not support PoE\n"; - testResults += "RESULT skip poe.negotiation The switch does not support PoE\n"; - testResults += "RESULT skip poe.support The switch does not support PoE\n"; - } else { - - // Determine PoE power test result - if (maxPower >= currentPower && poeOn) { - testResults += "RESULT pass poe.power PoE is applied to device\n"; - } else if (poeOff) { - testResults += "RESULT fail poe.power No poE is applied\n"; - } else if (poeFault) { - testResults += - "RESULT fail poe.power Device detection or a powered device is in a faulty state\n"; - } else if (poeDeny) { - testResults += - "RESULT fail poe.power A powered device is detected, but no PoE is available, or the maximum wattage exceeds the detected powered-device maximum.\n"; - } - - // Determine PoE auto negotiation result - if (powerAuto) { - testResults += "RESULT pass poe.negotiation PoE auto-negotiated successfully\n"; - } else { - testResults += "RESULT fail poe.negotiation Incorrect privilege for negotiation\n"; - } - - // Determine PoE support result - if (poeOn) { - testResults += "RESULT pass poe.support PoE supported and enabled\n"; - } else { - testResults += - "RESULT fail poe.support The switch does not support PoE or it is disabled\n"; - } - } - - return testResults; - } - - private void processCommandResponse(String response) { - response = response.trim(); - System.out.println("\nProcessing Command Response:\n" + response); - login_report += "\n\n" + response; - switch (commandIndex) { - case 0: // show interface status - processInterfaceStatus(response); - break; - case 1: // show power status - processPowerStatusInline(response); - } - } - - public HashMap processInterfaceStatus(String response) { - interface_map = mapSimpleTable(response, show_interface_expected, interface_expected); - return interface_map; - } - - public Map processPowerStatusInline(String response) { - Map inlineMap = powerInlineMap(); - Arrays.stream(response.split("\n")) - .forEach( - line -> { - String[] lineParts = line.trim().split(":"); - if (lineParts.length > 1) { - String powerMapKey = inlineMap.getOrDefault(lineParts[0], null); - if (powerMapKey != null) { - power_map.put(powerMapKey, lineParts[1].trim()); - } - } - }); - return power_map; - } - - /** - * Map a simple table containing a header and 1 row of data to a hashmap - * - *

      his method will also attempt ot correct for mis-aligned tabular data as well as empty - * columns values. - * - * @param rawPacket Raw table response from a switch command - * @param colNames Array containing the names of the columns in the response - * @param mapNames Array containing names key names to map values to - * @return A HashMap containing the values mapped to the key names provided in the mapNames array - */ - public HashMap mapSimpleTable( - String rawPacket, String[] colNames, String[] mapNames) { - HashMap colMap = new HashMap(); - String[] lines = rawPacket.split("\n"); - if (lines.length > 0) { - String header = lines[0].trim(); - String values = lines[1].trim(); - int lastSectionEnd = 0; - for (int i = 0; i < colNames.length; ++i) { - int secStart = lastSectionEnd; - int secEnd; - if ((i + 1) >= colNames.length) { - // Resolving last column - secEnd = values.length(); - } else { - // Tabular data is not always reported in perfectly alignment, we need to calculate the - // correct values based off of the sections in between white spaces - int firstWhiteSpace = - getFirstWhiteSpace(values.substring(lastSectionEnd)) + lastSectionEnd; - int lastWhiteSpace = - getIndexOfNonWhitespaceAfterWhitespace(values.substring(firstWhiteSpace)) - + firstWhiteSpace; - int nextHeaderStart = header.indexOf(colNames[i + 1]); - secEnd = Math.min(lastWhiteSpace, nextHeaderStart); - } - lastSectionEnd = secEnd; - String sectionRaw = values.substring(secStart, secEnd).trim(); - colMap.put(mapNames[i], sectionRaw); - } - } - return colMap; - } - - public static int getFirstWhiteSpace(String string) { - char[] characters = string.toCharArray(); - for (int i = 0; i < string.length(); i++) { - if (Character.isWhitespace(characters[i])) { - return i; - } - } - return -1; - } - - public static int getIndexOfNonWhitespaceAfterWhitespace(String string) { - char[] characters = string.toCharArray(); - boolean lastWhitespace = false; - for (int i = 0; i < string.length(); i++) { - if (Character.isWhitespace(characters[i])) { - lastWhitespace = true; - } else if (lastWhitespace) { - return i; - } - } - return -1; - } - - public void sendNextCommand() { - login_report += "\n" + command[commandIndex]; - telnetClientSocket.writeData(command[commandIndex] + "\n"); - commandPending = true; - promptReady = false; - } - - public String[] interfaceExpected() { - return new String[] {"interface", "name", "status", "vlan", "duplex", "speed", "type"}; - } - - public String[] powerExpected() { - return new String[] {"dev_interface", "admin", "oper", "power", "device", "dev_class", "max"}; - } - - public String[] showInterfaceExpected() { - return new String[] {"Port", "Name", "Status", "Vlan", "Duplex", "Speed", "Type"}; - } - - public String[] showPowerExpected() { - return new String[] {"Interface", "Admin", "Oper", "Power", "Device", "Class", "Max"}; - } - - // Unused methods implemented for compiling only - public String[] commandToggle() { - return new String[] {}; - } - - public String[] expected() { - return new String[] {}; - } - - public String[] loginExpected() { - return new String[] {}; - } - - public String[] platformExpected() { - return new String[] {}; - } - - public String[] showInterfacePortExpected() { - return new String[] {}; - } - - public String[] showPlatformExpected() { - return new String[] {}; - } - - public String[] showPlatformPortExpected() { - return new String[] {}; - } - - public String[] stackExpected() { - return new String[] {}; - } - - public String[] showStackExpected() { - return new String[] {}; - } - - private static HashMap powerInlineMap() { - HashMap map = new HashMap(); - map.put("Interface", "dev_interface"); - map.put("Inline Power Mode", "admin"); - map.put("Operational status", "oper"); - map.put("Measured at the port", "power"); - map.put("Device Type", "device"); - map.put("IEEE Class", "dev_class"); - map.put("Power available to the device", "max"); - return map; - } -} diff --git a/subset/switches/src/main/java/switchtest/cisco/CiscoSwitchTelnetClientSocket.java b/subset/switches/src/main/java/switchtest/cisco/CiscoSwitchTelnetClientSocket.java deleted file mode 100644 index 111b6071f5..0000000000 --- a/subset/switches/src/main/java/switchtest/cisco/CiscoSwitchTelnetClientSocket.java +++ /dev/null @@ -1,60 +0,0 @@ -package switchtest.cisco; - -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import switchtest.SwitchInterrogator; -import switchtest.SwitchTelnetClientSocket; - -public class CiscoSwitchTelnetClientSocket extends SwitchTelnetClientSocket { - public CiscoSwitchTelnetClientSocket( - String remoteIpAddress, int remotePort, SwitchInterrogator interrogator, boolean debug) { - super(remoteIpAddress, remotePort, interrogator, debug); - } - - /** - * Continuous scan of data in the rxQueue and send to SwitchInterrogator for processing. If no - * data can be read for 70 scans, send a new line to force something into the queue. - */ - protected void gatherData() { - int rxQueueCount = 0; - - int expectedLength = 1000; - - while (telnetClient.isConnected()) { - try { - if (rxQueue.isEmpty()) { - Thread.sleep(100); - rxQueueCount++; - if (debug) { - System.out.println("rxQueue.isEmpty:" + rxQueueCount); - System.out.println("expectedLength:" + expectedLength); - } - if (rxQueueCount > 70) { - rxQueueCount = 0; - writeData("\n"); - } - } else { - String rxGathered = rxQueue.poll(); - interrogator.receiveData(rxGathered); - } - } catch (InterruptedException e) { - System.err.println("InterruptedException gatherData:" + e.getMessage()); - } - } - } -} diff --git a/subset/switches/test_switch b/subset/switches/test_switch index 549c3fdccc..d3ed57350c 100755 --- a/subset/switches/test_switch +++ b/subset/switches/test_switch @@ -7,11 +7,15 @@ MONO_LOG=/tmp/monolog.switch.txt RESULT_LINES=/tmp/results.switch.txt MODULE_CONFIG=/config/device/module_config.json +route add default gw $GATEWAY_IP +ping -c 2 $GATEWAY_IP # Setup for accessing control plane switch. If LOCAL_IP is defined, which # is the intended local address for this node on the control plane then # SWITCH_IP will be the IP address of the OpenFlow switch. if [ -n "$LOCAL_IP" ]; then + USI_URL=`jq -r .run_info.usi.url $MODULE_CONFIG` + RPC_TIMEOUT=`jq -r .run_info.usi.rpc_timeout_sec $MODULE_CONFIG` || 10 SWITCH_IP=`jq -r .run_info.switch.ip $MODULE_CONFIG` SWITCH_MODEL=`jq -r .run_info.switch.model $MODULE_CONFIG` SWITCH_USERNAME=`jq -r .run_info.switch.username $MODULE_CONFIG` @@ -24,7 +28,7 @@ if [ -n "$LOCAL_IP" ]; then echo Switch test with username:password $SWITCH_USERNAME:$SWITCH_PASSWORD ping -n -c 10 $SWITCH_IP POE_ENABLED=`jq -r .modules.switch.poe.enabled $MODULE_CONFIG` - java -jar switches/target/switchtest-0.0.1-jar-with-dependencies.jar $SWITCH_IP $TARGET_PORT $POE_ENABLED $SWITCH_MODEL $SWITCH_USERNAME $SWITCH_PASSWORD + java -jar switches/target/switchtest-0.0.1-jar-with-dependencies.jar $USI_URL $RPC_TIMEOUT $SWITCH_IP $TARGET_PORT $POE_ENABLED $SWITCH_MODEL $SWITCH_USERNAME $SWITCH_PASSWORD grep -v "RESULT" $LOCAL_REPORT | tee -a $MONO_LOG grep "RESULT" $LOCAL_REPORT | tee -a $RESULT_LINES diff --git a/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java b/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java index 15af00f907..098c7456ba 100644 --- a/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java +++ b/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java @@ -4,6 +4,7 @@ import daq.usi.ResponseHandler; import grpc.InterfaceResponse; import grpc.LinkStatus; +import grpc.POENegotiation; import grpc.POEStatus; import grpc.POESupport; import grpc.PowerResponse; @@ -28,6 +29,8 @@ public class AlliedTelesisX230 extends BaseSwitchController { // TODO Not certain about AT power "Deny" status string. Can't find a device to produce that state private static final Map poeSupportMap = Map.of("Enabled", POESupport.ENABLED, "Disabled", POESupport.DISABLED); + private static final Map poeNegotiationMap = Map.of("Enabled", + POENegotiation.NEGOTIATION_ENABLED, "Disabled", POENegotiation.NEGOTIATION_DISABLED); private static final Map interfaceProcessMap = Map.of(Pattern.compile("Link is (\\w+)"), "link", Pattern.compile("current duplex (\\w+)"), "duplex", @@ -211,8 +214,9 @@ private PowerResponse buildPowerResponse(Map powerMap) { } String poeSupport = powerMap.getOrDefault("admin", null); String poeStatus = powerMap.getOrDefault("oper", null); - return response.setPoeStatus(poeStatusMap.getOrDefault(poeStatus, POEStatus.OFF)) - .setPoeSupport(poeSupportMap.getOrDefault(poeSupport, POESupport.DISABLED)) + return response.setPoeStatus(poeStatusMap.getOrDefault(poeStatus, null)) + .setPoeSupport(poeSupportMap.getOrDefault(poeSupport, null)) + .setPoeNegotiation(poeNegotiationMap.getOrDefault(poeSupport, null)) .setMaxPowerConsumption(maxPower) .setCurrentPowerConsumption(currentPower).build(); } diff --git a/usi/src/main/java/daq/usi/cisco/Cisco9300.java b/usi/src/main/java/daq/usi/cisco/Cisco9300.java index fded5d6041..f10d237291 100644 --- a/usi/src/main/java/daq/usi/cisco/Cisco9300.java +++ b/usi/src/main/java/daq/usi/cisco/Cisco9300.java @@ -4,6 +4,7 @@ import daq.usi.ResponseHandler; import grpc.InterfaceResponse; import grpc.LinkStatus; +import grpc.POENegotiation; import grpc.POEStatus; import grpc.POESupport; import grpc.PowerResponse; @@ -33,6 +34,8 @@ public class Cisco9300 extends BaseSwitchController { "off", POEStatus.OFF, "fault", POEStatus.FAULT, "power-deny", POEStatus.DENY); private static final Map poeSupportMap = Map.of("auto", POESupport.ENABLED, "off", POESupport.DISABLED); + private static final Map poeNegotiationtMap = Map.of("auto", + POENegotiation.NEGOTIATION_ENABLED, "off", POENegotiation.NEGOTIATION_DISABLED); private static final int WAIT_MS = 100; private ResponseHandler responseHandler; @@ -244,6 +247,7 @@ private PowerResponse buildPowerResponse(Map powerMap) { String poeStatus = powerMap.getOrDefault("oper", null); return response.setPoeStatus(poeStatusMap.getOrDefault(poeStatus, null)) .setPoeSupport(poeSupportMap.getOrDefault(poeSupport, null)) + .setPoeNegotiation(poeNegotiationtMap.getOrDefault(poeStatus, null)) .setMaxPowerConsumption(maxPower) .setCurrentPowerConsumption(currentPower).build(); } diff --git a/usi/src/main/proto/usi.proto b/usi/src/main/proto/usi.proto index 6107b0afc7..b0ef6c7f03 100644 --- a/usi/src/main/proto/usi.proto +++ b/usi/src/main/proto/usi.proto @@ -24,6 +24,7 @@ message PowerResponse { float max_power_consumption = 2; POESupport poe_support = 3; POEStatus poe_status = 4; + POENegotiation poe_negotiation = 5; } message InterfaceResponse { @@ -55,6 +56,11 @@ enum POEStatus { DENY = 3; } +enum POENegotiation { + NEGOTIATION_ENABLED = 0; + NEGOTIATION_DISABLED = 1; +} + /* * System configuraiton of the access switch. This is used by the system * to setup and configure the switch itself. From 1b73798e014b84b65a25765b350229dd21781607 Mon Sep 17 00:00:00 2001 From: Trevor Pering Date: Tue, 18 Aug 2020 18:27:39 -0700 Subject: [PATCH 097/212] Build script tweaks --- bin/build_release | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bin/build_release b/bin/build_release index ac035a50bf..b0d0783cf1 100755 --- a/bin/build_release +++ b/bin/build_release @@ -17,11 +17,14 @@ if [ -n "$changes" ]; then false fi +git checkout release_stable +git fetch faucet +git merge faucet/release_stable git checkout master changed=`git diff --name-only release_stable docs/changelog.md` if [ -z "$changed" ]; then - git log release_stable..HEAD --pretty=oneline | sed -e 's/[a-z0-9]+/\*/g' + git log release_stable..HEAD --pretty=oneline | sed -e 's/^[a-z0-9]\+ //g' echo docs/changelog.md has not been updated since last release_stable echo Use the log lines above for inspiration. false From 9e008a2ce4c3e97cdb61629f308ad56fd94d97dc Mon Sep 17 00:00:00 2001 From: Trevor Pering Date: Tue, 18 Aug 2020 18:29:04 -0700 Subject: [PATCH 098/212] 1.9.1 changelog --- docs/changelog.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index 5cdbb47729..a6e1d7ad43 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,4 +1,14 @@ # Changelog +* 1.9.1 + Feature/convert switchtests (#601) + Do not infinite spawn ntp (#598) + security.nmap.http test (#563) + Update registrar tool for latest UDMI version (#596) + Feature/vlan trigger (#588) + fix gcp combine report test (#587) + Adding default dns for static ip faux devices (#576) + Add perodic tests (#575) + security.admin.password changes (#461) * 1.9.0 * Test infrastructure cleanup (#572) * Remove faux dependencies from subset directory (#567) From 8b5723942f8537631a18fdb85df5af19773a87c2 Mon Sep 17 00:00:00 2001 From: Trevor Pering Date: Tue, 18 Aug 2020 19:27:59 -0700 Subject: [PATCH 099/212] Updating docker_images --- etc/docker_images.txt | 56 +++++++++++++++++++++---------------------- etc/docker_images.ver | 2 +- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/etc/docker_images.txt b/etc/docker_images.txt index 86709318c1..8b1ea34353 100644 --- a/etc/docker_images.txt +++ b/etc/docker_images.txt @@ -1,28 +1,28 @@ -daqf/aardvark 6e4060d0a709 -daqf/default aeb62fb24aec -daqf/faucet ed05522dc9a9 -daqf/faux1 8f7ea8f17cd6 -daqf/faux2 a850c4b2a543 -daqf/gauge 639232dbf1fa -daqf/networking 5751109cde18 -daqf/switch 083e95f1e99a -daqf/test_bacext 47ae2409fb29 -daqf/test_bacnet e0c2d561fed4 -daqf/test_brute bfa1aee20a20 -daqf/test_discover 82c7c43a2511 -daqf/test_fail 714d948b6704 -daqf/test_hold cb0be5cc6344 -daqf/test_macoui fd9c99e49a9e -daqf/test_manual 47cc832d53c4 -daqf/test_mudgee 239b96416b74 -daqf/test_network b55e8fdb12ed -daqf/test_nmap 16ec57a5e432 -daqf/test_ntp a62a00c53442 -daqf/test_pass 1da28b1cdfdc -daqf/test_password ac7b8f36cfd6 -daqf/test_ping 805a48f03a8d -daqf/test_ssh 836e7a6c54ad -daqf/test_switch 5f5dff0d9222 -daqf/test_tls 36f9e52f5df5 -daqf/test_udmi 1dc5b32d827a -daqf/usi f5ceac56a634 +daqf/aardvark 6fb0f6c52222 +daqf/default f8652a12fdd8 +daqf/faucet 1ec12d632685 +daqf/faux1 3d8f075bf6de +daqf/faux2 58b756b90505 +daqf/gauge ace0ffe33b8f +daqf/networking 4f25f942b538 +daqf/switch b2113d0aa5d9 +daqf/test_bacext daa0a06c718e +daqf/test_bacnet 6a3c93c4decc +daqf/test_brute aa76b01d5eed +daqf/test_discover 0ca76d766349 +daqf/test_fail 8ef4103069a5 +daqf/test_hold 5c923cd1a464 +daqf/test_macoui a605473e0f8d +daqf/test_manual 8026fdd99a5b +daqf/test_mudgee 189aa0b635fd +daqf/test_network 557df3ae19f9 +daqf/test_nmap 8ceb63e71c79 +daqf/test_ntp a5b21e0039e6 +daqf/test_pass 62dd10381336 +daqf/test_password d318555d2d3e +daqf/test_ping fe8e4dd5ddc2 +daqf/test_ssh 054efbf1b3c3 +daqf/test_switch 5db7f2b0c428 +daqf/test_tls 17de1ebf13ce +daqf/test_udmi b6d5381f32f0 +daqf/usi 3e773df34234 diff --git a/etc/docker_images.ver b/etc/docker_images.ver index f8e233b273..9ab8337f39 100644 --- a/etc/docker_images.ver +++ b/etc/docker_images.ver @@ -1 +1 @@ -1.9.0 +1.9.1 From c35b375a84dd0b8bed87221f982a6fb5600deeee Mon Sep 17 00:00:00 2001 From: Trevor Date: Wed, 19 Aug 2020 16:13:13 -0700 Subject: [PATCH 100/212] Add assert for module name length (#603) --- daq/base_module.py | 5 +++-- testing/test_aux.sh | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/daq/base_module.py b/daq/base_module.py index 2d1dffc985..f8062e4dd8 100644 --- a/daq/base_module.py +++ b/daq/base_module.py @@ -19,9 +19,10 @@ def __init__(self, host, tmpdir, test_name, module_config): self.device = host.device self.test_config = module_config.get('modules').get(test_name) self.runner = host.runner - # Host name can't be more than 15 characters - # because it is also used to create an interface in mininet. self.host_name = '%s%02d' % (test_name, host.device.set_id) + # Host name can't be more than 10 characters because it is also used to create a + # network interface with -eth0 on the end and there's a hard linux limit on length. + assert len(self.host_name) <= 10, 'Hostname %s too long' self.callback = None self._finish_hook = None self.start_time = None diff --git a/testing/test_aux.sh b/testing/test_aux.sh index e19d5a1334..11603ae121 100755 --- a/testing/test_aux.sh +++ b/testing/test_aux.sh @@ -115,8 +115,8 @@ done capture_test_results bacext capture_test_results macoui capture_test_results tls -capture_test_results passwo # test host names are truncated to 6 characters -capture_test_results discov +capture_test_results password +capture_test_results discover capture_test_results networ capture_test_results ntp From 53697257c4c925b214e53ad77c722096ed663545 Mon Sep 17 00:00:00 2001 From: henry54809 Date: Wed, 19 Aug 2020 16:24:28 -0700 Subject: [PATCH 101/212] Auto rewrite usi_set.url (#602) --- cmd/exrun | 9 +++++++-- subset/switches/readme.md | 5 +++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/cmd/exrun b/cmd/exrun index f690c50ee2..a6ff5bd90b 100755 --- a/cmd/exrun +++ b/cmd/exrun @@ -16,6 +16,7 @@ export DAQ_LSB_RELEASE=$(echo $LSB_RAW) export DAQ_SYS_UNAME=$(uname -a) skip_autostart= cleanup_file=inst/exrun_cleanup.sh +uri_url_override="" run_args="$@" if [ `whoami` != root ]; then @@ -118,7 +119,11 @@ else fi docker rm -f daq-usi || true -autostart cmd/usi +if [ "$usi_setup_url" == "localhost:5000" ]; then + autostart cmd/usi + docker0_ip=`ifconfig docker0 | grep 'inet ' | awk '{print $2}'` + uri_url_override="usi_setup.url=$docker0_ip:5000" +fi # Kill any gateways so that they don't prematurely assign an IP address. gwids=$(docker ps --format '{{ .Image }} {{ .Names }}' | fgrep daqf/networking | awk '{print $2}') || true @@ -164,7 +169,7 @@ export OVSVSCTL_ORIG=`which ovs-vsctl` export PATH=$ROOT/binhack:$PATH exit_code=0 -$runcmd daq/daq.py $conf_file $@ 2>&1 || exit_code=$? +$runcmd daq/daq.py $conf_file $uri_url_override $@ 2>&1 || exit_code=$? if [ -f "$cleanup_file" ]; then source $cleanup_file diff --git a/subset/switches/readme.md b/subset/switches/readme.md index 7bc1bfab2e..b2e970aee1 100644 --- a/subset/switches/readme.md +++ b/subset/switches/readme.md @@ -68,9 +68,10 @@ Example of all necessary parameters in the system.conf related to physical switc # Define the password for the switch. This parameter is optional. switch_setup.password=switch_p@55 + # If you're using a custom docker network bridge or hosting USI somewhere other than the DAQ machine, do the following: # Define the usi url using your docker0's ip and port 5000, and re-run bin/setup_base if you're upgrading from versions before 1.9.0 - # Make sure docker's ip range doesn't conflict with that of the switch. Default docker0 ip is 172.17.0.1 - usi.url=172.17.0.1:5000 + # Make sure docker's ip range doesn't conflict with that of the switch. Default docker ip range is 172.17.0.0/16. Default switch ip range is 192.168.0.0/16 + usi_setup.url=172.17.0.1:5000 ## Conditions for connection.port_duplex - pass -> If the duplex mode is detected as full From ed460691c8cc3231547c87ec6c0529af8f0a1fc0 Mon Sep 17 00:00:00 2001 From: Trevor Pering Date: Wed, 19 Aug 2020 16:38:20 -0700 Subject: [PATCH 102/212] Cleaning up build script --- bin/build_release | 4 ++-- etc/docker_images.txt | 2 +- etc/docker_images.ver | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/build_release b/bin/build_release index b0d0783cf1..fb523b8c08 100755 --- a/bin/build_release +++ b/bin/build_release @@ -47,7 +47,7 @@ cmd/build force $VERSION cmd/build push -cat > /tmp/git_expected.expected < /tmp/git_status.expected < /tmp/git_status.found if ! diff /tmp/git_status.expected /tmp/git_status.found; then - echo Expected build images not found. Something went wrong. + echo Expected build index changes not found. Something went wrong. false fi rm -f /tmp/git_status.* diff --git a/etc/docker_images.txt b/etc/docker_images.txt index 8b1ea34353..e5ba459100 100644 --- a/etc/docker_images.txt +++ b/etc/docker_images.txt @@ -22,7 +22,7 @@ daqf/test_pass 62dd10381336 daqf/test_password d318555d2d3e daqf/test_ping fe8e4dd5ddc2 daqf/test_ssh 054efbf1b3c3 -daqf/test_switch 5db7f2b0c428 +daqf/test_switch 5daf5774fb11 daqf/test_tls 17de1ebf13ce daqf/test_udmi b6d5381f32f0 daqf/usi 3e773df34234 diff --git a/etc/docker_images.ver b/etc/docker_images.ver index 9ab8337f39..8fdcf38694 100644 --- a/etc/docker_images.ver +++ b/etc/docker_images.ver @@ -1 +1 @@ -1.9.1 +1.9.2 From 253be7e767f9678c6a380ed9257a61f7c5133cc4 Mon Sep 17 00:00:00 2001 From: Trevor Pering Date: Wed, 19 Aug 2020 17:17:28 -0700 Subject: [PATCH 103/212] 1.9.3 release --- bin/build_release | 13 ------------- etc/docker_images.ver | 2 +- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/bin/build_release b/bin/build_release index fb523b8c08..8a080a938d 100755 --- a/bin/build_release +++ b/bin/build_release @@ -47,19 +47,6 @@ cmd/build force $VERSION cmd/build push -cat > /tmp/git_status.expected < /tmp/git_status.found - -if ! diff /tmp/git_status.expected /tmp/git_status.found; then - echo Expected build index changes not found. Something went wrong. - false -fi -rm -f /tmp/git_status.* - git commit -a -m "$VERSION release" git tag -a $VERSION -m "$VERSION release" git push diff --git a/etc/docker_images.ver b/etc/docker_images.ver index 8fdcf38694..77fee73a8c 100644 --- a/etc/docker_images.ver +++ b/etc/docker_images.ver @@ -1 +1 @@ -1.9.2 +1.9.3 From 368f729c98d438493dbcbe59d157e261255e5f3d Mon Sep 17 00:00:00 2001 From: henry54809 Date: Thu, 20 Aug 2020 12:19:43 -0700 Subject: [PATCH 104/212] USI debug messages (#606) --- bin/setup_base | 2 +- cmd/exrun | 10 ++- cmd/usi | 10 ++- firebase/public/protos.hash | 2 +- firebase/public/protos.html | 7 ++ libs/proto/system_config_pb2.py | 35 ++++++---- libs/proto/usi_pb2.py | 69 ++++++++++++++----- proto/system_config.proto | 3 + usi/src/main/java/daq/usi/UsiImpl.java | 34 ++++++++- usi/src/main/java/daq/usi/UsiServer.java | 12 ++-- .../main/java/daq/usi/cisco/Cisco9300.java | 17 ++++- usi/start | 2 +- 12 files changed, 158 insertions(+), 45 deletions(-) diff --git a/bin/setup_base b/bin/setup_base index 97d830b424..42b5a7de7f 100755 --- a/bin/setup_base +++ b/bin/setup_base @@ -61,7 +61,7 @@ if [ -n "$DEF_IFACE" ]; then echo Allowing docker external access through interface $DEF_IFACE... sudo iptables -o docker0 -i $DEF_IFACE -A FORWARD -j ACCEPT sudo iptables -i docker0 -o $DEF_IFACE -A FORWARD -j ACCEPT - sudo iptables -A INPUT -i docker0 -j ACCEPT fi +sudo iptables -A INPUT -i docker0 -j ACCEPT echo Logout and log back in to run tutorials without sudo! diff --git a/cmd/exrun b/cmd/exrun index a6ff5bd90b..863544ae5a 100755 --- a/cmd/exrun +++ b/cmd/exrun @@ -118,10 +118,16 @@ else echo No external switch model specified. fi +# USI related setup docker rm -f daq-usi || true -if [ "$usi_setup_url" == "localhost:5000" ]; then +docker0_ip=`sudo ifconfig docker0 | grep 'inet ' | awk '{print $2}'` +if [ -z "$usi_setup_url" -o "$usi_setup_url" == "localhost:5000" -o "$usi_setup_url" == "$docker0_ip:5000" ]; then + sudo iptables -C INPUT -i docker0 -j ACCEPT + if [ $? == "1" ]; then + sudo iptables -A INPUT -i docker0 -j ACCEPT + fi autostart cmd/usi - docker0_ip=`ifconfig docker0 | grep 'inet ' | awk '{print $2}'` + docker0_ip=`sudo ifconfig docker0 | grep 'inet ' | awk '{print $2}'` uri_url_override="usi_setup.url=$docker0_ip:5000" fi diff --git a/cmd/usi b/cmd/usi index 79fa946d9a..d69f387f52 100755 --- a/cmd/usi +++ b/cmd/usi @@ -2,11 +2,17 @@ ROOT=$(realpath $(dirname $0)/..) USI_DIR=$ROOT/inst/network +DEBUG="" +if [ -n $debug_mode ]; then + DEBUG="debug" + echo Starting USI in debug mode +else + echo Starting USI +fi -echo Starting USI rm -rf $USI_DIR mkdir -p $USI_DIR -docker run -d -v $USI_DIR:/ovs --privileged --network=host --name daq-usi daqf/usi +docker run -d -v $USI_DIR:/ovs --privileged --network=host -e DEBUG=$DEBUG --name daq-usi daqf/usi echo DAQ autoclean docker kill daq-usi diff --git a/firebase/public/protos.hash b/firebase/public/protos.hash index 1a7397bfdf..4ddf9485f8 100644 --- a/firebase/public/protos.hash +++ b/firebase/public/protos.hash @@ -1 +1 @@ -5e1ffaa617230e5ae366e281660ff3d38056d6e6 proto/system_config.proto +f76de649c75ed722febfc0750c53672f22af5ab1 proto/system_config.proto diff --git a/firebase/public/protos.html b/firebase/public/protos.html index 637d0b9911..f4cf44b2e7 100644 --- a/firebase/public/protos.html +++ b/firebase/public/protos.html @@ -500,6 +500,13 @@

      DaqConfig

      Configures events that trigger a DAQ run

      + + debug_mode + bool + +

      verbose output

      + + diff --git a/libs/proto/system_config_pb2.py b/libs/proto/system_config_pb2.py index 716bb36fe3..f2784ab726 100644 --- a/libs/proto/system_config_pb2.py +++ b/libs/proto/system_config_pb2.py @@ -20,7 +20,7 @@ package='', syntax='proto3', serialized_options=None, - serialized_pb=_b('\n\x1d\x64\x61q/proto/system_config.proto\"\xc8\x08\n\tDaqConfig\x12\x18\n\x10site_description\x18\x01 \x01(\t\x12\x18\n\x10monitor_scan_sec\x18\x02 \x01(\x05\x12\x1b\n\x13\x64\x65\x66\x61ult_timeout_sec\x18\x03 \x01(\x05\x12\x12\n\nsettle_sec\x18& \x01(\x05\x12\x11\n\tbase_conf\x18\x04 \x01(\t\x12\x11\n\tsite_path\x18\x05 \x01(\t\x12\x1f\n\x17initial_dhcp_lease_time\x18\x06 \x01(\t\x12\x17\n\x0f\x64hcp_lease_time\x18\x07 \x01(\t\x12\x19\n\x11\x64hcp_response_sec\x18\' \x01(\x05\x12\x1e\n\x16long_dhcp_response_sec\x18\x08 \x01(\x05\x12\"\n\x0cswitch_setup\x18\t \x01(\x0b\x32\x0c.SwitchSetup\x12\x12\n\nhost_tests\x18\x10 \x01(\t\x12\x13\n\x0b\x62uild_tests\x18$ \x01(\x08\x12\x11\n\trun_limit\x18\x11 \x01(\x05\x12\x11\n\tfail_mode\x18\x12 \x01(\x08\x12\x13\n\x0bsingle_shot\x18\" \x01(\x08\x12\x15\n\rresult_linger\x18\x13 \x01(\x08\x12\x0f\n\x07no_test\x18\x14 \x01(\x08\x12\x11\n\tkeep_hold\x18( \x01(\x08\x12\x14\n\x0c\x64\x61q_loglevel\x18\x15 \x01(\t\x12\x18\n\x10mininet_loglevel\x18\x16 \x01(\t\x12\x13\n\x0b\x66inish_hook\x18# \x01(\t\x12\x10\n\x08gcp_cred\x18\x17 \x01(\t\x12\x11\n\tgcp_topic\x18\x18 \x01(\t\x12\x13\n\x0bschema_path\x18\x19 \x01(\t\x12\x11\n\tmud_files\x18\x1a \x01(\t\x12\x14\n\x0c\x64\x65vice_specs\x18\x1b \x01(\t\x12\x13\n\x0btest_config\x18\x1c \x01(\t\x12\x19\n\x11port_debounce_sec\x18\x1d \x01(\x05\x12\x15\n\rtopology_hook\x18\x1e \x01(\t\x12\x17\n\x0f\x64\x65vice_template\x18\x1f \x01(\t\x12\x14\n\x0csite_reports\x18 \x01(\t\x12\x1f\n\x17run_data_retention_days\x18! \x01(\x02\x12.\n\ninterfaces\x18% \x03(\x0b\x32\x1a.DaqConfig.InterfacesEntry\x12/\n\x0b\x66\x61il_module\x18/ \x03(\x0b\x32\x1a.DaqConfig.FailModuleEntry\x12\x1d\n\x15port_flap_timeout_sec\x18\x30 \x01(\x05\x12\x1c\n\tusi_setup\x18\x31 \x01(\x0b\x32\t.USISetup\x12)\n\x10run_trigger_type\x18\x32 \x01(\x0e\x32\x0f.RunTriggerType\x1a=\n\x0fInterfacesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x19\n\x05value\x18\x02 \x01(\x0b\x32\n.Interface:\x02\x38\x01\x1a\x31\n\x0f\x46\x61ilModuleEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"0\n\x08USISetup\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x17\n\x0frpc_timeout_sec\x18\x02 \x01(\x05\"\xf4\x01\n\x0bSwitchSetup\x12\x11\n\tctrl_intf\x18\t \x01(\t\x12\x0f\n\x07ip_addr\x18\x0b \x01(\t\x12\x13\n\x0buplink_port\x18\r \x01(\x05\x12\x0f\n\x07lo_port\x18\x0e \x01(\x05\x12\x10\n\x08\x61lt_port\x18\x10 \x01(\x05\x12\x0f\n\x07lo_addr\x18\x12 \x01(\t\x12\x11\n\tmods_addr\x18\x14 \x01(\t\x12\x0f\n\x07of_dpid\x18) \x01(\t\x12\x11\n\tdata_intf\x18* \x01(\t\x12\x0e\n\x06\x65xt_br\x18+ \x01(\t\x12\r\n\x05model\x18, \x01(\t\x12\x10\n\x08username\x18- \x01(\t\x12\x10\n\x08password\x18. \x01(\t\"\'\n\tInterface\x12\x0c\n\x04opts\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05*$\n\x0eRunTriggerType\x12\x08\n\x04PORT\x10\x00\x12\x08\n\x04VLAN\x10\x01\x62\x06proto3') + serialized_pb=_b('\n\x1d\x64\x61q/proto/system_config.proto\"\xdc\x08\n\tDaqConfig\x12\x18\n\x10site_description\x18\x01 \x01(\t\x12\x18\n\x10monitor_scan_sec\x18\x02 \x01(\x05\x12\x1b\n\x13\x64\x65\x66\x61ult_timeout_sec\x18\x03 \x01(\x05\x12\x12\n\nsettle_sec\x18& \x01(\x05\x12\x11\n\tbase_conf\x18\x04 \x01(\t\x12\x11\n\tsite_path\x18\x05 \x01(\t\x12\x1f\n\x17initial_dhcp_lease_time\x18\x06 \x01(\t\x12\x17\n\x0f\x64hcp_lease_time\x18\x07 \x01(\t\x12\x19\n\x11\x64hcp_response_sec\x18\' \x01(\x05\x12\x1e\n\x16long_dhcp_response_sec\x18\x08 \x01(\x05\x12\"\n\x0cswitch_setup\x18\t \x01(\x0b\x32\x0c.SwitchSetup\x12\x12\n\nhost_tests\x18\x10 \x01(\t\x12\x13\n\x0b\x62uild_tests\x18$ \x01(\x08\x12\x11\n\trun_limit\x18\x11 \x01(\x05\x12\x11\n\tfail_mode\x18\x12 \x01(\x08\x12\x13\n\x0bsingle_shot\x18\" \x01(\x08\x12\x15\n\rresult_linger\x18\x13 \x01(\x08\x12\x0f\n\x07no_test\x18\x14 \x01(\x08\x12\x11\n\tkeep_hold\x18( \x01(\x08\x12\x14\n\x0c\x64\x61q_loglevel\x18\x15 \x01(\t\x12\x18\n\x10mininet_loglevel\x18\x16 \x01(\t\x12\x13\n\x0b\x66inish_hook\x18# \x01(\t\x12\x10\n\x08gcp_cred\x18\x17 \x01(\t\x12\x11\n\tgcp_topic\x18\x18 \x01(\t\x12\x13\n\x0bschema_path\x18\x19 \x01(\t\x12\x11\n\tmud_files\x18\x1a \x01(\t\x12\x14\n\x0c\x64\x65vice_specs\x18\x1b \x01(\t\x12\x13\n\x0btest_config\x18\x1c \x01(\t\x12\x19\n\x11port_debounce_sec\x18\x1d \x01(\x05\x12\x15\n\rtopology_hook\x18\x1e \x01(\t\x12\x17\n\x0f\x64\x65vice_template\x18\x1f \x01(\t\x12\x14\n\x0csite_reports\x18 \x01(\t\x12\x1f\n\x17run_data_retention_days\x18! \x01(\x02\x12.\n\ninterfaces\x18% \x03(\x0b\x32\x1a.DaqConfig.InterfacesEntry\x12/\n\x0b\x66\x61il_module\x18/ \x03(\x0b\x32\x1a.DaqConfig.FailModuleEntry\x12\x1d\n\x15port_flap_timeout_sec\x18\x30 \x01(\x05\x12\x1c\n\tusi_setup\x18\x31 \x01(\x0b\x32\t.USISetup\x12)\n\x10run_trigger_type\x18\x32 \x01(\x0e\x32\x0f.RunTriggerType\x12\x12\n\ndebug_mode\x18\x33 \x01(\x08\x1a=\n\x0fInterfacesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x19\n\x05value\x18\x02 \x01(\x0b\x32\n.Interface:\x02\x38\x01\x1a\x31\n\x0f\x46\x61ilModuleEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"0\n\x08USISetup\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x17\n\x0frpc_timeout_sec\x18\x02 \x01(\x05\"\xf4\x01\n\x0bSwitchSetup\x12\x11\n\tctrl_intf\x18\t \x01(\t\x12\x0f\n\x07ip_addr\x18\x0b \x01(\t\x12\x13\n\x0buplink_port\x18\r \x01(\x05\x12\x0f\n\x07lo_port\x18\x0e \x01(\x05\x12\x10\n\x08\x61lt_port\x18\x10 \x01(\x05\x12\x0f\n\x07lo_addr\x18\x12 \x01(\t\x12\x11\n\tmods_addr\x18\x14 \x01(\t\x12\x0f\n\x07of_dpid\x18) \x01(\t\x12\x11\n\tdata_intf\x18* \x01(\t\x12\x0e\n\x06\x65xt_br\x18+ \x01(\t\x12\r\n\x05model\x18, \x01(\t\x12\x10\n\x08username\x18- \x01(\t\x12\x10\n\x08password\x18. \x01(\t\"\'\n\tInterface\x12\x0c\n\x04opts\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05*$\n\x0eRunTriggerType\x12\x08\n\x04PORT\x10\x00\x12\x08\n\x04VLAN\x10\x01\x62\x06proto3') ) _RUNTRIGGERTYPE = _descriptor.EnumDescriptor( @@ -40,8 +40,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=1470, - serialized_end=1506, + serialized_start=1490, + serialized_end=1526, ) _sym_db.RegisterEnumDescriptor(_RUNTRIGGERTYPE) @@ -84,8 +84,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1018, - serialized_end=1079, + serialized_start=1038, + serialized_end=1099, ) _DAQCONFIG_FAILMODULEENTRY = _descriptor.Descriptor( @@ -121,8 +121,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1081, - serialized_end=1130, + serialized_start=1101, + serialized_end=1150, ) _DAQCONFIG = _descriptor.Descriptor( @@ -398,6 +398,13 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='debug_mode', full_name='DaqConfig.debug_mode', index=38, + number=51, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], @@ -411,7 +418,7 @@ oneofs=[ ], serialized_start=34, - serialized_end=1130, + serialized_end=1150, ) @@ -448,8 +455,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1132, - serialized_end=1180, + serialized_start=1152, + serialized_end=1200, ) @@ -563,8 +570,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1183, - serialized_end=1427, + serialized_start=1203, + serialized_end=1447, ) @@ -601,8 +608,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1429, - serialized_end=1468, + serialized_start=1449, + serialized_end=1488, ) _DAQCONFIG_INTERFACESENTRY.fields_by_name['value'].message_type = _INTERFACE diff --git a/libs/proto/usi_pb2.py b/libs/proto/usi_pb2.py index c9189dc119..780ac2e1c2 100644 --- a/libs/proto/usi_pb2.py +++ b/libs/proto/usi_pb2.py @@ -20,7 +20,7 @@ syntax='proto3', serialized_options=b'\n\004grpcB\010USIProtoP\001', create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\tusi.proto\x12\x03usi\"\'\n\x14SwitchActionResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\"\x9b\x01\n\rPowerResponse\x12!\n\x19\x63urrent_power_consumption\x18\x01 \x01(\x02\x12\x1d\n\x15max_power_consumption\x18\x02 \x01(\x02\x12$\n\x0bpoe_support\x18\x03 \x01(\x0e\x32\x0f.usi.POESupport\x12\"\n\npoe_status\x18\x04 \x01(\x0e\x32\x0e.usi.POEStatus\"]\n\x11InterfaceResponse\x12$\n\x0blink_status\x18\x01 \x01(\x0e\x32\x0f.usi.LinkStatus\x12\x12\n\nlink_speed\x18\x02 \x01(\x05\x12\x0e\n\x06\x64uplex\x18\x03 \x01(\t\"w\n\nSwitchInfo\x12\x0f\n\x07ip_addr\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65vice_port\x18\x03 \x01(\x05\x12\x1f\n\x05model\x18\x04 \x01(\x0e\x32\x10.usi.SwitchModel\x12\x10\n\x08username\x18\x05 \x01(\t\x12\x10\n\x08password\x18\x06 \x01(\t*F\n\x0bSwitchModel\x12\x17\n\x13\x41LLIED_TELESIS_X230\x10\x00\x12\x0e\n\nCISCO_9300\x10\x01\x12\x0e\n\nOVS_SWITCH\x10\x02*\x1e\n\nLinkStatus\x12\x06\n\x02UP\x10\x00\x12\x08\n\x04\x44OWN\x10\x01*\'\n\nPOESupport\x12\x0b\n\x07\x45NABLED\x10\x00\x12\x0c\n\x08\x44ISABLED\x10\x01*1\n\tPOEStatus\x12\x06\n\x02ON\x10\x00\x12\x07\n\x03OFF\x10\x01\x12\t\n\x05\x46\x41ULT\x10\x02\x12\x08\n\x04\x44\x45NY\x10\x03\x32\xef\x01\n\nUSIService\x12\x31\n\x08GetPower\x12\x0f.usi.SwitchInfo\x1a\x12.usi.PowerResponse\"\x00\x12\x39\n\x0cGetInterface\x12\x0f.usi.SwitchInfo\x1a\x16.usi.InterfaceResponse\"\x00\x12:\n\ndisconnect\x12\x0f.usi.SwitchInfo\x1a\x19.usi.SwitchActionResponse\"\x00\x12\x37\n\x07\x63onnect\x12\x0f.usi.SwitchInfo\x1a\x19.usi.SwitchActionResponse\"\x00\x42\x12\n\x04grpcB\x08USIProtoP\x01\x62\x06proto3' + serialized_pb=b'\n\tusi.proto\x12\x03usi\"\'\n\x14SwitchActionResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\"\xc9\x01\n\rPowerResponse\x12!\n\x19\x63urrent_power_consumption\x18\x01 \x01(\x02\x12\x1d\n\x15max_power_consumption\x18\x02 \x01(\x02\x12$\n\x0bpoe_support\x18\x03 \x01(\x0e\x32\x0f.usi.POESupport\x12\"\n\npoe_status\x18\x04 \x01(\x0e\x32\x0e.usi.POEStatus\x12,\n\x0fpoe_negotiation\x18\x05 \x01(\x0e\x32\x13.usi.POENegotiation\"]\n\x11InterfaceResponse\x12$\n\x0blink_status\x18\x01 \x01(\x0e\x32\x0f.usi.LinkStatus\x12\x12\n\nlink_speed\x18\x02 \x01(\x05\x12\x0e\n\x06\x64uplex\x18\x03 \x01(\t\"w\n\nSwitchInfo\x12\x0f\n\x07ip_addr\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65vice_port\x18\x03 \x01(\x05\x12\x1f\n\x05model\x18\x04 \x01(\x0e\x32\x10.usi.SwitchModel\x12\x10\n\x08username\x18\x05 \x01(\t\x12\x10\n\x08password\x18\x06 \x01(\t*F\n\x0bSwitchModel\x12\x17\n\x13\x41LLIED_TELESIS_X230\x10\x00\x12\x0e\n\nCISCO_9300\x10\x01\x12\x0e\n\nOVS_SWITCH\x10\x02*\x1e\n\nLinkStatus\x12\x06\n\x02UP\x10\x00\x12\x08\n\x04\x44OWN\x10\x01*\'\n\nPOESupport\x12\x0b\n\x07\x45NABLED\x10\x00\x12\x0c\n\x08\x44ISABLED\x10\x01*1\n\tPOEStatus\x12\x06\n\x02ON\x10\x00\x12\x07\n\x03OFF\x10\x01\x12\t\n\x05\x46\x41ULT\x10\x02\x12\x08\n\x04\x44\x45NY\x10\x03*C\n\x0ePOENegotiation\x12\x17\n\x13NEGOTIATION_ENABLED\x10\x00\x12\x18\n\x14NEGOTIATION_DISABLED\x10\x01\x32\xef\x01\n\nUSIService\x12\x31\n\x08GetPower\x12\x0f.usi.SwitchInfo\x1a\x12.usi.PowerResponse\"\x00\x12\x39\n\x0cGetInterface\x12\x0f.usi.SwitchInfo\x1a\x16.usi.InterfaceResponse\"\x00\x12:\n\ndisconnect\x12\x0f.usi.SwitchInfo\x1a\x19.usi.SwitchActionResponse\"\x00\x12\x37\n\x07\x63onnect\x12\x0f.usi.SwitchInfo\x1a\x19.usi.SwitchActionResponse\"\x00\x42\x12\n\x04grpcB\x08USIProtoP\x01\x62\x06proto3' ) _SWITCHMODEL = _descriptor.EnumDescriptor( @@ -48,8 +48,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=433, - serialized_end=503, + serialized_start=479, + serialized_end=549, ) _sym_db.RegisterEnumDescriptor(_SWITCHMODEL) @@ -74,8 +74,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=505, - serialized_end=535, + serialized_start=551, + serialized_end=581, ) _sym_db.RegisterEnumDescriptor(_LINKSTATUS) @@ -100,8 +100,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=537, - serialized_end=576, + serialized_start=583, + serialized_end=622, ) _sym_db.RegisterEnumDescriptor(_POESUPPORT) @@ -136,12 +136,38 @@ ], containing_type=None, serialized_options=None, - serialized_start=578, - serialized_end=627, + serialized_start=624, + serialized_end=673, ) _sym_db.RegisterEnumDescriptor(_POESTATUS) POEStatus = enum_type_wrapper.EnumTypeWrapper(_POESTATUS) +_POENEGOTIATION = _descriptor.EnumDescriptor( + name='POENegotiation', + full_name='usi.POENegotiation', + filename=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + values=[ + _descriptor.EnumValueDescriptor( + name='NEGOTIATION_ENABLED', index=0, number=0, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='NEGOTIATION_DISABLED', index=1, number=1, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + ], + containing_type=None, + serialized_options=None, + serialized_start=675, + serialized_end=742, +) +_sym_db.RegisterEnumDescriptor(_POENEGOTIATION) + +POENegotiation = enum_type_wrapper.EnumTypeWrapper(_POENEGOTIATION) ALLIED_TELESIS_X230 = 0 CISCO_9300 = 1 OVS_SWITCH = 2 @@ -153,6 +179,8 @@ OFF = 1 FAULT = 2 DENY = 3 +NEGOTIATION_ENABLED = 0 +NEGOTIATION_DISABLED = 1 @@ -224,6 +252,13 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='poe_negotiation', full_name='usi.PowerResponse.poe_negotiation', index=4, + number=5, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), ], extensions=[ ], @@ -237,7 +272,7 @@ oneofs=[ ], serialized_start=60, - serialized_end=215, + serialized_end=261, ) @@ -282,8 +317,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=217, - serialized_end=310, + serialized_start=263, + serialized_end=356, ) @@ -342,12 +377,13 @@ extension_ranges=[], oneofs=[ ], - serialized_start=312, - serialized_end=431, + serialized_start=358, + serialized_end=477, ) _POWERRESPONSE.fields_by_name['poe_support'].enum_type = _POESUPPORT _POWERRESPONSE.fields_by_name['poe_status'].enum_type = _POESTATUS +_POWERRESPONSE.fields_by_name['poe_negotiation'].enum_type = _POENEGOTIATION _INTERFACERESPONSE.fields_by_name['link_status'].enum_type = _LINKSTATUS _SWITCHINFO.fields_by_name['model'].enum_type = _SWITCHMODEL DESCRIPTOR.message_types_by_name['SwitchActionResponse'] = _SWITCHACTIONRESPONSE @@ -358,6 +394,7 @@ DESCRIPTOR.enum_types_by_name['LinkStatus'] = _LINKSTATUS DESCRIPTOR.enum_types_by_name['POESupport'] = _POESUPPORT DESCRIPTOR.enum_types_by_name['POEStatus'] = _POESTATUS +DESCRIPTOR.enum_types_by_name['POENegotiation'] = _POENEGOTIATION _sym_db.RegisterFileDescriptor(DESCRIPTOR) SwitchActionResponse = _reflection.GeneratedProtocolMessageType('SwitchActionResponse', (_message.Message,), { @@ -398,8 +435,8 @@ index=0, serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_start=630, - serialized_end=869, + serialized_start=745, + serialized_end=984, methods=[ _descriptor.MethodDescriptor( name='GetPower', diff --git a/proto/system_config.proto b/proto/system_config.proto index 9b3c60c54c..966a5b780a 100644 --- a/proto/system_config.proto +++ b/proto/system_config.proto @@ -120,6 +120,9 @@ message DaqConfig { // Configures events that trigger a DAQ run RunTriggerType run_trigger_type = 50; + + // verbose output + bool debug_mode = 51; } enum RunTriggerType { diff --git a/usi/src/main/java/daq/usi/UsiImpl.java b/usi/src/main/java/daq/usi/UsiImpl.java index 840bfe3e90..a8dd1e87db 100644 --- a/usi/src/main/java/daq/usi/UsiImpl.java +++ b/usi/src/main/java/daq/usi/UsiImpl.java @@ -14,10 +14,17 @@ public class UsiImpl extends USIServiceGrpc.USIServiceImplBase { private final Map switchControllers; + private final boolean debug; - public UsiImpl() { + /** + * UsiImpl. + * + * @param debug for verbose output + */ + public UsiImpl(boolean debug) { super(); switchControllers = new HashMap<>(); + this.debug = debug; } private SwitchController createController(SwitchInfo switchInfo) { @@ -25,12 +32,12 @@ private SwitchController createController(SwitchInfo switchInfo) { switch (switchInfo.getModel()) { case ALLIED_TELESIS_X230: { newController = new AlliedTelesisX230(switchInfo.getIpAddr(), switchInfo.getUsername(), - switchInfo.getPassword()); + switchInfo.getPassword(), debug); break; } case CISCO_9300: { newController = new Cisco9300(switchInfo.getIpAddr(), switchInfo.getUsername(), - switchInfo.getPassword()); + switchInfo.getPassword(), debug); break; } case OVS_SWITCH: { @@ -53,9 +60,15 @@ private SwitchController getSwitchController(SwitchInfo switchInfo) { @Override public void getPower(SwitchInfo request, StreamObserver responseObserver) { + System.out.println("Received request in getPower"); SwitchController sc = getSwitchController(request); try { sc.getPower(request.getDevicePort(), data -> { + System.out.println("Sent response in getPower"); + if (debug) { + System.out.println(data); + } + System.out.println("Received request in getPower"); responseObserver.onNext(data); responseObserver.onCompleted(); }); @@ -67,9 +80,14 @@ public void getPower(SwitchInfo request, StreamObserver responseO @Override public void getInterface(SwitchInfo request, StreamObserver responseObserver) { + System.out.println("Received request in getInterface"); SwitchController sc = getSwitchController(request); try { sc.getInterface(request.getDevicePort(), data -> { + System.out.println("Sent response in getInterface"); + if (debug) { + System.out.println(data); + } responseObserver.onNext(data); responseObserver.onCompleted(); }); @@ -81,9 +99,14 @@ public void getInterface(SwitchInfo request, StreamObserver r @Override public void connect(SwitchInfo request, StreamObserver responseObserver) { + System.out.println("Received request in connect"); SwitchController sc = getSwitchController(request); try { sc.connect(request.getDevicePort(), data -> { + System.out.println("Sent response in connect"); + if (debug) { + System.out.println(data); + } responseObserver.onNext(data); responseObserver.onCompleted(); }); @@ -96,9 +119,14 @@ public void connect(SwitchInfo request, StreamObserver res @Override public void disconnect(SwitchInfo request, StreamObserver responseObserver) { + System.out.println("Received request in disconnect"); SwitchController sc = getSwitchController(request); try { sc.disconnect(request.getDevicePort(), data -> { + System.out.println("Sent response in disconnect"); + if (debug) { + System.out.println(data); + } responseObserver.onNext(data); responseObserver.onCompleted(); }); diff --git a/usi/src/main/java/daq/usi/UsiServer.java b/usi/src/main/java/daq/usi/UsiServer.java index b5ce26374a..83fd51325e 100644 --- a/usi/src/main/java/daq/usi/UsiServer.java +++ b/usi/src/main/java/daq/usi/UsiServer.java @@ -8,13 +8,16 @@ public class UsiServer { private Server server; - private void start() throws IOException { + private void start(boolean debug) throws IOException { /* The port on which the server should run */ int port = 5000; server = ServerBuilder.forPort(port) - .addService(new UsiImpl()) + .addService(new UsiImpl(debug)) .build() .start(); + if (debug) { + System.out.println("************DEBUG MODE************"); + } System.out.println("Server started, listening on " + port); Runtime.getRuntime().addShutdownHook(new Thread() { @Override @@ -48,12 +51,13 @@ private void blockUntilShutdown() throws InterruptedException { /** * Main method. - * @param args not used. + * @param args "debug". * @throws Exception Maybe a refactor is needed to throw more specific exceptions. */ public static void main(String[] args) throws Exception { + final boolean debug = args.length > 0 ? args[0].equals("debug") : false; final UsiServer server = new UsiServer(); - server.start(); + server.start(debug); server.blockUntilShutdown(); } } diff --git a/usi/src/main/java/daq/usi/cisco/Cisco9300.java b/usi/src/main/java/daq/usi/cisco/Cisco9300.java index f10d237291..52c0dd250c 100644 --- a/usi/src/main/java/daq/usi/cisco/Cisco9300.java +++ b/usi/src/main/java/daq/usi/cisco/Cisco9300.java @@ -50,7 +50,22 @@ public Cisco9300( String remoteIpAddress, String user, String password) { - super(remoteIpAddress, user, password); + this(remoteIpAddress, user, password, false); + } + + /** + * Cisco 9300 Switch Controller. + * + * @param remoteIpAddress switch ip + * @param user switch username + * @param password switch password + * @param debug for verbose output + */ + public Cisco9300( + String remoteIpAddress, + String user, + String password, boolean debug) { + super(remoteIpAddress, user, password, debug); this.username = user == null ? "admin" : user; this.password = password == null ? "password" : password; commandPending = true; diff --git a/usi/start b/usi/start index c3fc5e5b8a..7e1837a619 100755 --- a/usi/start +++ b/usi/start @@ -1,2 +1,2 @@ #!/bin/bash -e -java -cp /ovs:usi/target/usi-0.0.1-jar-with-dependencies.jar daq.usi.UsiServer +java -cp /ovs:usi/target/usi-0.0.1-jar-with-dependencies.jar daq.usi.UsiServer $DEBUG From 173e60f3db6c711ac99acaba51236119cb00a0f3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 20 Aug 2020 15:36:10 -0700 Subject: [PATCH 105/212] Update dependency firebase-admin to v9.1.1 (#608) --- firebase/functions/package-lock.json | 285 +++++++++++++++++++++++++-- firebase/functions/package.json | 2 +- 2 files changed, 265 insertions(+), 22 deletions(-) diff --git a/firebase/functions/package-lock.json b/firebase/functions/package-lock.json index e082de4a9f..42589bac2c 100644 --- a/firebase/functions/package-lock.json +++ b/firebase/functions/package-lock.json @@ -14,24 +14,24 @@ "integrity": "sha512-88h74TMQ6wXChPA6h9Q3E1Jg6TkTHep2+k63OWg3s0ozyGVMeY+TTOti7PFPzq5RhszQPQOoCi59es4MaRvgCw==" }, "@firebase/component": { - "version": "0.1.17", - "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.1.17.tgz", - "integrity": "sha512-/tN5iLcFp9rdpTfCJPfQ/o2ziGHlDxOzNx6XD2FoHlu4pG/PPGu+59iRfQXIowBGhxcTGD/l7oJhZEY/PVg0KQ==", + "version": "0.1.18", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.1.18.tgz", + "integrity": "sha512-c8gd1k/e0sbBTR0xkLIYUN8nVkA0zWxcXGIvdfYtGEsNw6n7kh5HkcxKXOPB8S7bcPpqZkGgBIfvd94IyG2gaQ==", "requires": { - "@firebase/util": "0.3.0", + "@firebase/util": "0.3.1", "tslib": "^1.11.1" } }, "@firebase/database": { - "version": "0.6.10", - "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.6.10.tgz", - "integrity": "sha512-Hc8zIPAroIbAoRe6xFCI5oFHubcHKoDsbYE3J5G1/BhT6DnEUSoLgx8kJ2npybVSCVyb8BvsD6swh17DGEz+0g==", + "version": "0.6.11", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.6.11.tgz", + "integrity": "sha512-QOHhB7+CdjVhEXG9CyX0roA9ARJcEuwbozz0Bix+ULuZqjQ58KUFHMH1apW6EEiUP22d/mYD7dNXsUGshjL9PA==", "requires": { "@firebase/auth-interop-types": "0.1.5", - "@firebase/component": "0.1.17", + "@firebase/component": "0.1.18", "@firebase/database-types": "0.5.2", "@firebase/logger": "0.2.6", - "@firebase/util": "0.3.0", + "@firebase/util": "0.3.1", "faye-websocket": "0.11.3", "tslib": "^1.11.1" } @@ -50,9 +50,9 @@ "integrity": "sha512-KIxcUvW/cRGWlzK9Vd2KB864HlUnCfdTH0taHE0sXW5Xl7+W68suaeau1oKNEqmc3l45azkd4NzXTCWZRZdXrw==" }, "@firebase/util": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.3.0.tgz", - "integrity": "sha512-GTwC+FSLeCPc44/TXCDReNQ5FPRIS5cb8Gr1XcD1TgiNBOvmyx61Om2YLwHp2GnN++6m6xmwmXARm06HOukATA==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.3.1.tgz", + "integrity": "sha512-zjVd9rfL08dRRdZILFn1RZTHb1euCcnD9N/9P56gdBcm2bvT5XsCC4G6t5toQBpE/H/jYe5h6MZMqfLu3EQLXw==", "requires": { "tslib": "^1.11.1" } @@ -202,14 +202,38 @@ }, "dependencies": { "@grpc/grpc-js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.1.3.tgz", - "integrity": "sha512-HtOsk2YUofBcm1GkPqGzb6pwHhv+74eC2CUO229USIDKRtg30ycbZmqC+HdNtY3nHqoc9IgcRlntFgopyQoYCA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.1.5.tgz", + "integrity": "sha512-2huf5z85TdZI4nLmJQ9Zdfd+6vmIyBDs7B4L71bTaHKA9pRsGKAH24XaktMk/xneKJIqAgeIZtg1cyivVZtvrg==", "optional": true, "requires": { + "@grpc/proto-loader": "^0.6.0-pre14", + "@types/node": "^12.12.47", + "google-auth-library": "^6.0.0", "semver": "^6.2.0" + }, + "dependencies": { + "@grpc/proto-loader": { + "version": "0.6.0-pre9", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.6.0-pre9.tgz", + "integrity": "sha512-oM+LjpEjNzW5pNJjt4/hq1HYayNeQT+eGrOPABJnYHv7TyNPDNzkQ76rDYZF86X5swJOa4EujEMzQ9iiTdPgww==", + "optional": true, + "requires": { + "@types/long": "^4.0.1", + "lodash.camelcase": "^4.3.0", + "long": "^4.0.0", + "protobufjs": "^6.9.0", + "yargs": "^15.3.1" + } + } } }, + "@types/node": { + "version": "12.12.54", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.54.tgz", + "integrity": "sha512-ge4xZ3vSBornVYlDnk7yZ0gK6ChHf/CHB7Gl1I0Jhah8DDnEQqBzgohYG4FX4p81TNirSETOiSyn+y1r9/IR6w==", + "optional": true + }, "bignumber.js": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", @@ -336,6 +360,14 @@ "@types/long": "^4.0.1", "@types/node": "^13.7.0", "long": "^4.0.0" + }, + "dependencies": { + "@types/node": { + "version": "13.13.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.15.tgz", + "integrity": "sha512-kwbcs0jySLxzLsa2nWUAGOd/s21WU1jebrEdtzhsj1D4Yps1EOuyI1Qcu+FD56dL7NRNIJtDDjcqIG22NwkgLw==", + "optional": true + } } }, "yallist": { @@ -573,6 +605,15 @@ "is-stream": "^2.0.0", "node-fetch": "^2.3.0" } + }, + "p-limit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz", + "integrity": "sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==", + "optional": true, + "requires": { + "p-try": "^2.0.0" + } } } }, @@ -713,6 +754,12 @@ "@types/node": "*" } }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "optional": true + }, "@types/connect": { "version": "3.4.33", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz", @@ -816,6 +863,22 @@ "debug": "4" } }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "optional": true + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "optional": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -884,6 +947,38 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "optional": true + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "optional": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "optional": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "optional": true + }, "compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -996,6 +1091,12 @@ "ms": "^2.1.1" } }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "optional": true + }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -1047,6 +1148,12 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "optional": true + }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -1191,10 +1298,20 @@ } } }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "optional": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, "firebase-admin": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-9.1.0.tgz", - "integrity": "sha512-tGGREJpoRM/mbV/5bs/q9SQRZkVhxMMq1HIJEzSEh3mtz5hC9VtaCkuLt6chuAsqHMBoc1pvnrGTOC5nOme9VQ==", + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-9.1.1.tgz", + "integrity": "sha512-HkzY9yN/kOe1EQgjheURAQ4pFBerI54TBL0+nj1fwzKnAnGCpcI73Bbwx99Pk3u2x4rj6bDcsZfz9bA8y7DWtQ==", "requires": { "@firebase/database": "^0.6.10", "@firebase/database-types": "^0.5.2", @@ -1369,6 +1486,12 @@ } } }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "optional": true + }, "google-auth-library": { "version": "5.10.1", "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-5.10.1.tgz", @@ -1521,6 +1644,12 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "optional": true + }, "is-obj": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", @@ -1618,6 +1747,15 @@ "safe-buffer": "^5.0.1" } }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "optional": true, + "requires": { + "p-locate": "^4.1.0" + } + }, "lodash": { "version": "4.17.20", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", @@ -1795,14 +1933,23 @@ "integrity": "sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw==" }, "p-limit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz", - "integrity": "sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "optional": true, "requires": { "p-try": "^2.0.0" } }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "optional": true, + "requires": { + "p-limit": "^2.2.0" + } + }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -1814,6 +1961,12 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "optional": true + }, "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", @@ -1948,6 +2101,18 @@ } } }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "optional": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "optional": true + }, "retry-request": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-4.1.1.tgz", @@ -2030,6 +2195,12 @@ "send": "0.17.1" } }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "optional": true + }, "setprototypeof": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", @@ -2071,6 +2242,17 @@ "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "optional": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -2086,6 +2268,15 @@ } } }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "optional": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, "stubs": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", @@ -2202,6 +2393,23 @@ "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==" }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "optional": true + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "optional": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -2231,10 +2439,45 @@ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "optional": true }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "optional": true + }, "yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "optional": true, + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + } + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "optional": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } } } } diff --git a/firebase/functions/package.json b/firebase/functions/package.json index 172ce21f03..78a3f2e8e4 100644 --- a/firebase/functions/package.json +++ b/firebase/functions/package.json @@ -14,7 +14,7 @@ "dependencies": { "@google-cloud/pubsub": "2.5.0", "@google-cloud/iot": "1.8.0", - "firebase-admin": "9.1.0", + "firebase-admin": "9.1.1", "firebase-functions": "3.9.1", "extend": "3.0.2" }, From 63328b6d7a97d975b63ca518c1b80a21e53944c7 Mon Sep 17 00:00:00 2001 From: Trevor Date: Thu, 20 Aug 2020 21:37:55 -0700 Subject: [PATCH 106/212] Add module config system logging (#607) --- bin/build_release | 7 +++++-- daq/host.py | 14 ++++++++------ daq/runner.py | 9 ++++++--- docs/changelog.md | 20 ++++++++++---------- 4 files changed, 29 insertions(+), 21 deletions(-) diff --git a/bin/build_release b/bin/build_release index 8a080a938d..a74a8c9a03 100755 --- a/bin/build_release +++ b/bin/build_release @@ -49,6 +49,8 @@ cmd/build push git commit -a -m "$VERSION release" git tag -a $VERSION -m "$VERSION release" +firebase/deploy.sh bos-daq-testing + git push git push --tags @@ -59,13 +61,14 @@ if [ -n "$faucetgit" ]; then git push faucet --tags fi -firebase/deploy.sh bos-daq-testing git checkout release_testing && git reset --hard $VERSION - +git push if [ -n "$faucetgit" ]; then git push faucet fi +git log -n 1 + # QA pass to make sure everything is ok. # `firebase/deploy.sh daq-qualification-labs` # `git checkout release_stable && git reset --hard $VERSION` diff --git a/daq/host.py b/daq/host.py index 5fd29cb6ff..5afce889a6 100644 --- a/daq/host.py +++ b/daq/host.py @@ -214,14 +214,16 @@ def _get_unique_upload_path(self, file_name): partial = os.path.join('tests', self.test_name, base) if self.test_name else base return os.path.join('run_id', self.run_id, partial) - def _load_config(self, config, path): + def _load_config(self, name, config, path): + if name: + self.logger.info('Loading %s module config from %s', name, path) return self.configurator.load_and_merge(config, path, self._MODULE_CONFIG, optional=True) def _write_module_config(self, config, path): self.configurator.write_config(config, path, self._MODULE_CONFIG) def _type_path(self): - dev_config = self._load_config({}, self._device_base) + dev_config = self._load_config(None, {}, self._device_base) device_type = dev_config.get('device_type') if not device_type: return None @@ -749,9 +751,9 @@ def _load_module_config(self, run_info=True): config = self.runner.get_base_config() if run_info: self._merge_run_info(config) - self._load_config(config, self._type_path()) - self._load_config(config, self._device_base) - self._load_config(config, self._port_base) + self._load_config('type', config, self._type_path()) + self._load_config('device', config, self._device_base) + self._load_config('port', config, self._port_base) return config def record_result(self, name, **kwargs): @@ -819,7 +821,7 @@ def _dev_config_updated(self, dev_config): self.reload_config() def _initialize_config(self): - dev_config = self._load_config({}, self._device_base) + dev_config = self._load_config('base', {}, self._device_base) self._gcp.register_config(self._DEVICE_PATH % self.target_mac, dev_config, self._dev_config_updated) if self.target_port: diff --git a/daq/runner.py b/daq/runner.py index afb16b07d0..ad3f18a82d 100644 --- a/daq/runner.py +++ b/daq/runner.py @@ -796,9 +796,12 @@ def _base_config_changed(self, new_config): _ = [device.host.reload_config() for device in self._devices.get_triggered_devices()] def _load_base_config(self, register=True): - base = self.configurator.load_and_merge({}, self.config.get('base_conf')) - site_config = self.configurator.load_config(self.config.get('site_path'), - self._MODULE_CONFIG, optional=True) + base_conf = self.config.get('base_conf') + LOGGER.info('Loading base module config from %s', base_conf) + base = self.configurator.load_and_merge({}, base_conf) + site_path = self.config.get('site_path') + LOGGER.info('Loading site module config from %s', base_conf) + site_config = self.configurator.load_config(site_path, self._MODULE_CONFIG, optional=True) if register: self.gcp.register_config(self._RUNNER_CONFIG_PATH, site_config, self._base_config_changed) diff --git a/docs/changelog.md b/docs/changelog.md index a6e1d7ad43..32f526538b 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,14 +1,14 @@ # Changelog -* 1.9.1 - Feature/convert switchtests (#601) - Do not infinite spawn ntp (#598) - security.nmap.http test (#563) - Update registrar tool for latest UDMI version (#596) - Feature/vlan trigger (#588) - fix gcp combine report test (#587) - Adding default dns for static ip faux devices (#576) - Add perodic tests (#575) - security.admin.password changes (#461) +* 1.9.4 + * Feature/convert switchtests (#601) + * Do not infinite spawn ntp (#598) + * security.nmap.http test (#563) + * Update registrar tool for latest UDMI version (#596) + * Feature/vlan trigger (#588) + * fix gcp combine report test (#587) + * Adding default dns for static ip faux devices (#576) + * Add perodic tests (#575) + * security.admin.password changes (#461) * 1.9.0 * Test infrastructure cleanup (#572) * Remove faux dependencies from subset directory (#567) From 5a50a50082745798b6ca2c3013779fc04c953908 Mon Sep 17 00:00:00 2001 From: henry54809 Date: Fri, 21 Aug 2020 16:01:19 -0700 Subject: [PATCH 107/212] Adding enum defaults and more USI AT switch tests (#610) --- cmd/exrun | 5 +- .../src/main/java/switchtest/SwitchTest.java | 14 +++--- .../daq/usi/allied/AlliedTelesisX230.java | 34 +++++++------ .../main/java/daq/usi/cisco/Cisco9300.java | 48 ++++++++++++------ .../main/java/daq/usi/ovs/OpenVSwitch.java | 7 +-- usi/src/main/proto/usi.proto | 49 ++++++++++++------- .../java/daq/usi/AlliedTelesisX230Test.java | 45 +++++++++++++++++ .../daq/usi/FakeSwitchTelnetClientSocket.java | 19 +++++++ 8 files changed, 158 insertions(+), 63 deletions(-) create mode 100644 usi/src/test/java/daq/usi/AlliedTelesisX230Test.java create mode 100644 usi/src/test/java/daq/usi/FakeSwitchTelnetClientSocket.java diff --git a/cmd/exrun b/cmd/exrun index 863544ae5a..da52e80451 100755 --- a/cmd/exrun +++ b/cmd/exrun @@ -122,10 +122,7 @@ fi docker rm -f daq-usi || true docker0_ip=`sudo ifconfig docker0 | grep 'inet ' | awk '{print $2}'` if [ -z "$usi_setup_url" -o "$usi_setup_url" == "localhost:5000" -o "$usi_setup_url" == "$docker0_ip:5000" ]; then - sudo iptables -C INPUT -i docker0 -j ACCEPT - if [ $? == "1" ]; then - sudo iptables -A INPUT -i docker0 -j ACCEPT - fi + sudo iptables -C INPUT -i docker0 -j ACCEPT || sudo iptables -A INPUT -i docker0 -j ACCEPT autostart cmd/usi docker0_ip=`sudo ifconfig docker0 | grep 'inet ' | awk '{print $2}'` uri_url_override="usi_setup.url=$docker0_ip:5000" diff --git a/subset/switches/src/main/java/switchtest/SwitchTest.java b/subset/switches/src/main/java/switchtest/SwitchTest.java index 45bb9b4550..16dd960fca 100644 --- a/subset/switches/src/main/java/switchtest/SwitchTest.java +++ b/subset/switches/src/main/java/switchtest/SwitchTest.java @@ -53,7 +53,7 @@ protected void captureResult(String test, Result result, String additional) { protected void testLink(InterfaceResponse interfaceResponse) { final String testName = "connection.port_link"; - if (interfaceResponse.getLinkStatus() == LinkStatus.UP) { + if (interfaceResponse.getLinkStatus() == LinkStatus.State.UP) { captureResult(testName, Result.PASS, "Link is up"); } else { captureResult(testName, Result.FAIL, "Link is down"); @@ -98,17 +98,17 @@ protected void testPower(PowerResponse powerResponse) { return; } - POEStatus poeStatus = powerResponse.getPoeStatus(); + POEStatus.State poeStatus = powerResponse.getPoeStatus(); // Determine PoE power test result - if (poeStatus == POEStatus.ON) { + if (poeStatus == POEStatus.State.ON) { if (powerResponse.getMaxPowerConsumption() >= powerResponse.getCurrentPowerConsumption()) { captureResult("poe.power", Result.PASS, "PoE is applied to device"); } else { captureResult("poe.power", Result.FAIL, "device wattage exceeds the max wattage"); } - } else if (poeStatus == POEStatus.OFF) { + } else if (poeStatus == POEStatus.State.OFF) { captureResult("poe.power", Result.FAIL, "No poE is applied"); - } else if (poeStatus == POEStatus.FAULT) { + } else if (poeStatus == POEStatus.State.FAULT) { captureResult("poe.power", Result.FAIL, "Device detection or a powered device is in a faulty state"); } else { @@ -118,14 +118,14 @@ protected void testPower(PowerResponse powerResponse) { } // Determine PoE auto negotiation result - if (powerResponse.getPoeNegotiation() == POENegotiation.NEGOTIATION_ENABLED) { + if (powerResponse.getPoeNegotiation() == POENegotiation.State.ENABLED) { captureResult("poe.negotiation", Result.PASS, "PoE auto-negotiated successfully"); } else { captureResult("poe.negotiation", Result.FAIL, "Incorrect privilege for negotiation"); } // Determine PoE support result - if (powerResponse.getPoeSupport() == POESupport.ENABLED) { + if (powerResponse.getPoeSupport() == POESupport.State.ENABLED) { captureResult("poe.support", Result.PASS, "PoE is supported and enabled"); } else { captureResult("poe.support", Result.FAIL, diff --git a/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java b/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java index 098c7456ba..f9ab852b33 100644 --- a/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java +++ b/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java @@ -24,13 +24,14 @@ public class AlliedTelesisX230 extends BaseSwitchController { {"dev_interface", "admin", "pri", "oper", "power", "device", "dev_class", "max"}; private static final String[] showPowerExpected = {"Interface", "Admin", "Pri", "Oper", "Power", "Device", "Class", "Max"}; - private static final Map poeStatusMap = Map.of("Powered", POEStatus.ON, - "Off", POEStatus.OFF, "Fault", POEStatus.FAULT, "Deny", POEStatus.DENY); + private static final Map poeStatusMap = Map.of("Powered", + POEStatus.State.ON, "Off", POEStatus.State.OFF, + "Fault", POEStatus.State.FAULT, "Deny", POEStatus.State.DENY); // TODO Not certain about AT power "Deny" status string. Can't find a device to produce that state - private static final Map poeSupportMap = Map.of("Enabled", - POESupport.ENABLED, "Disabled", POESupport.DISABLED); - private static final Map poeNegotiationMap = Map.of("Enabled", - POENegotiation.NEGOTIATION_ENABLED, "Disabled", POENegotiation.NEGOTIATION_DISABLED); + private static final Map poeSupportMap = Map.of("Enabled", + POESupport.State.ENABLED, "Disabled", POESupport.State.DISABLED); + private static final Map poeNegotiationMap = Map.of("Enabled", + POENegotiation.State.ENABLED, "Disabled", POENegotiation.State.DISABLED); private static final Map interfaceProcessMap = Map.of(Pattern.compile("Link is (\\w+)"), "link", Pattern.compile("current duplex (\\w+)"), "duplex", @@ -190,12 +191,14 @@ private InterfaceResponse buildInterfaceResponse(Map interfaceMa String duplex = interfaceMap.getOrDefault("duplex", ""); int speed = 0; try { - speed = Integer.parseInt(interfaceMap.get("speed")); + speed = Integer.parseInt(interfaceMap.getOrDefault("speed", "")); } catch (NumberFormatException e) { System.out.println("Could not parse int: " + interfaceMap.get("speed")); + return response.build(); } String linkStatus = interfaceMap.getOrDefault("link", ""); - return response.setLinkStatus(linkStatus.equals("UP") ? LinkStatus.UP : LinkStatus.DOWN) + return response + .setLinkStatus(linkStatus.equals("UP") ? LinkStatus.State.UP : LinkStatus.State.DOWN) .setDuplex(duplex) .setLinkSpeed(speed) .build(); @@ -206,17 +209,18 @@ private PowerResponse buildPowerResponse(Map powerMap) { float maxPower = 0; float currentPower = 0; try { - maxPower = Float.parseFloat(powerMap.get("max")); - currentPower = Float.parseFloat(powerMap.get("power")); + maxPower = Float.parseFloat(powerMap.getOrDefault("max", "")); + currentPower = Float.parseFloat(powerMap.getOrDefault("power", "")); } catch (NumberFormatException e) { System.out.println( "Could not parse float: " + powerMap.get("max") + " or " + powerMap.get("power")); } - String poeSupport = powerMap.getOrDefault("admin", null); - String poeStatus = powerMap.getOrDefault("oper", null); - return response.setPoeStatus(poeStatusMap.getOrDefault(poeStatus, null)) - .setPoeSupport(poeSupportMap.getOrDefault(poeSupport, null)) - .setPoeNegotiation(poeNegotiationMap.getOrDefault(poeSupport, null)) + String poeSupport = powerMap.getOrDefault("admin", ""); + String poeStatus = powerMap.getOrDefault("oper", ""); + return response + .setPoeStatus(poeStatusMap.getOrDefault(poeStatus, POEStatus.State.UNKNOWN)) + .setPoeSupport(poeSupportMap.getOrDefault(poeSupport, POESupport.State.UNKNOWN)) + .setPoeNegotiation(poeNegotiationMap.getOrDefault(poeSupport, POENegotiation.State.UNKNOWN)) .setMaxPowerConsumption(maxPower) .setCurrentPowerConsumption(currentPower).build(); } diff --git a/usi/src/main/java/daq/usi/cisco/Cisco9300.java b/usi/src/main/java/daq/usi/cisco/Cisco9300.java index 52c0dd250c..4d226b0c31 100644 --- a/usi/src/main/java/daq/usi/cisco/Cisco9300.java +++ b/usi/src/main/java/daq/usi/cisco/Cisco9300.java @@ -30,12 +30,13 @@ public class Cisco9300 extends BaseSwitchController { "Device Type", "device", "IEEE Class", "dev_class", "Power available to the device", "max"); - private static final Map poeStatusMap = Map.of("on", POEStatus.ON, - "off", POEStatus.OFF, "fault", POEStatus.FAULT, "power-deny", POEStatus.DENY); - private static final Map poeSupportMap = Map.of("auto", POESupport.ENABLED, - "off", POESupport.DISABLED); - private static final Map poeNegotiationtMap = Map.of("auto", - POENegotiation.NEGOTIATION_ENABLED, "off", POENegotiation.NEGOTIATION_DISABLED); + private static final Map poeStatusMap = Map.of("on", + POEStatus.State.ON, "off", POEStatus.State.OFF, "fault", POEStatus.State.FAULT, + "power-deny", POEStatus.State.DENY); + private static final Map poeSupportMap = Map.of("auto", + POESupport.State.ENABLED, "off", POESupport.State.DISABLED); + private static final Map poeNegotiationtMap = Map.of("auto", + POENegotiation.State.ENABLED, "off", POENegotiation.State.DISABLED); private static final int WAIT_MS = 100; private ResponseHandler responseHandler; @@ -245,24 +246,41 @@ private InterfaceResponse buildInterfaceResponse(Map interfaceMa if (speed.startsWith("a-")) { // Interface in Auto Speed speed = speed.replaceFirst("a-", ""); } + int speedNum = 0; + try { + speedNum = Integer.parseInt(speed); + } catch (NumberFormatException e) { + System.out.println("Could not parse int for interface speed: " + speed); + return response.build(); + } String linkStatus = interfaceMap.getOrDefault("status", ""); - return response.setLinkStatus(linkStatus.equals("connected") ? LinkStatus.UP : LinkStatus.DOWN) + return response + .setLinkStatus(linkStatus.equals("connected") ? LinkStatus.State.UP : LinkStatus.State.DOWN) .setDuplex(duplex) - .setLinkSpeed(Integer.parseInt(speed)) + .setLinkSpeed(speedNum) .build(); } private PowerResponse buildPowerResponse(Map powerMap) { PowerResponse.Builder response = PowerResponse.newBuilder(); - float maxPower = Float.parseFloat(powerMap.get("max")); - float currentPower = Float.parseFloat(powerMap.get("power")); + float maxPower = 0; + float currentPower = 0; + try { + maxPower = Float.parseFloat(powerMap.getOrDefault("max", "")); + currentPower = Float.parseFloat(powerMap.getOrDefault("power", "")); + } catch (NumberFormatException e) { + System.out.println( + "Could not parse float: " + powerMap.get("max") + " or " + powerMap.get("power")); + } - String poeSupport = powerMap.getOrDefault("admin", null); - String poeStatus = powerMap.getOrDefault("oper", null); - return response.setPoeStatus(poeStatusMap.getOrDefault(poeStatus, null)) - .setPoeSupport(poeSupportMap.getOrDefault(poeSupport, null)) - .setPoeNegotiation(poeNegotiationtMap.getOrDefault(poeStatus, null)) + String poeSupport = powerMap.getOrDefault("admin", ""); + String poeStatus = powerMap.getOrDefault("oper", ""); + return response + .setPoeStatus(poeStatusMap.getOrDefault(poeStatus, POEStatus.State.UNKNOWN)) + .setPoeSupport(poeSupportMap.getOrDefault(poeSupport, POESupport.State.UNKNOWN)) + .setPoeNegotiation( + poeNegotiationtMap.getOrDefault(poeStatus, POENegotiation.State.UNKNOWN)) .setMaxPowerConsumption(maxPower) .setCurrentPowerConsumption(currentPower).build(); } diff --git a/usi/src/main/java/daq/usi/ovs/OpenVSwitch.java b/usi/src/main/java/daq/usi/ovs/OpenVSwitch.java index f95afe27d4..91366218c2 100644 --- a/usi/src/main/java/daq/usi/ovs/OpenVSwitch.java +++ b/usi/src/main/java/daq/usi/ovs/OpenVSwitch.java @@ -42,8 +42,9 @@ protected String getInterfaceByPort(int devicePort) throws IOException { @Override public void getPower(int devicePort, ResponseHandler handler) throws Exception { PowerResponse.Builder response = PowerResponse.newBuilder(); - PowerResponse power = response.setPoeStatus(POEStatus.OFF).setPoeSupport(POESupport.DISABLED) - .setMaxPowerConsumption(0).setCurrentPowerConsumption(0).build(); + PowerResponse power = response.setPoeStatus(POEStatus.State.OFF) + .setPoeSupport(POESupport.State.DISABLED) + .build(); handler.receiveData(power); } @@ -52,7 +53,7 @@ public void getInterface(int devicePort, ResponseHandler hand throws Exception { InterfaceResponse.Builder response = InterfaceResponse.newBuilder(); InterfaceResponse iface = - response.setLinkStatus(LinkStatus.UP).setDuplex("").setLinkSpeed(0).build(); + response.setLinkStatus(LinkStatus.State.UP).build(); handler.receiveData(iface); } diff --git a/usi/src/main/proto/usi.proto b/usi/src/main/proto/usi.proto index b0ef6c7f03..156df5eaca 100644 --- a/usi/src/main/proto/usi.proto +++ b/usi/src/main/proto/usi.proto @@ -22,13 +22,13 @@ message SwitchActionResponse { message PowerResponse { float current_power_consumption = 1; float max_power_consumption = 2; - POESupport poe_support = 3; - POEStatus poe_status = 4; - POENegotiation poe_negotiation = 5; + POESupport.State poe_support = 3; + POEStatus.State poe_status = 4; + POENegotiation.State poe_negotiation = 5; } message InterfaceResponse { - LinkStatus link_status = 1; + LinkStatus.State link_status = 1; int32 link_speed = 2; string duplex = 3; } @@ -39,26 +39,37 @@ enum SwitchModel { OVS_SWITCH = 2; } -enum LinkStatus { - UP = 0; - DOWN = 1; +message LinkStatus { + enum State { + UNKNOWN = 0; + DOWN = 1; + UP = 2; + } } - -enum POESupport { - ENABLED = 0; - DISABLED = 1; +message POESupport { + enum State { + UNKNOWN = 0; + ENABLED = 1; + DISABLED = 2; + } } -enum POEStatus { - ON = 0; - OFF = 1; - FAULT = 2; - DENY = 3; +message POEStatus { + enum State { + UNKNOWN = 0; + ON = 1; + OFF = 2; + FAULT = 3; + DENY = 4; + } } -enum POENegotiation { - NEGOTIATION_ENABLED = 0; - NEGOTIATION_DISABLED = 1; +message POENegotiation { + enum State { + UNKNOWN = 0; + ENABLED = 1; + DISABLED = 2; + } } /* diff --git a/usi/src/test/java/daq/usi/AlliedTelesisX230Test.java b/usi/src/test/java/daq/usi/AlliedTelesisX230Test.java new file mode 100644 index 0000000000..c19a767c3d --- /dev/null +++ b/usi/src/test/java/daq/usi/AlliedTelesisX230Test.java @@ -0,0 +1,45 @@ +package daq.usi; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import daq.usi.allied.AlliedTelesisX230; +import grpc.POENegotiation; +import grpc.POEStatus; +import grpc.POESupport; +import grpc.PowerResponse; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class AlliedTelesisX230Test { + + private AlliedTelesisX230 at; + + @BeforeEach + void setUp() { + at = new AlliedTelesisX230(null, null, null); + at.telnetClientSocket = new FakeSwitchTelnetClientSocket(null, 0, null, false); + } + + @AfterEach + void tearDown() { + } + + @Test + void testEmptyPower() throws Exception { + at.userAuthorised = true; + at.userEnabled = true; + at.commandPending = false; + at.getPower(1, new ResponseHandler() { + @Override + public void receiveData(PowerResponse data) throws Exception { + assertEquals(data.getPoeSupport(), POESupport.State.UNKNOWN); + assertEquals(data.getPoeNegotiation(), POENegotiation.State.UNKNOWN); + assertEquals(data.getPoeStatus(), POEStatus.State.UNKNOWN); + assertEquals(data.getCurrentPowerConsumption(), 0); + assertEquals(data.getMaxPowerConsumption(), 0); + } + }); + at.receiveData(""); + } +} diff --git a/usi/src/test/java/daq/usi/FakeSwitchTelnetClientSocket.java b/usi/src/test/java/daq/usi/FakeSwitchTelnetClientSocket.java new file mode 100644 index 0000000000..0c2e70ee21 --- /dev/null +++ b/usi/src/test/java/daq/usi/FakeSwitchTelnetClientSocket.java @@ -0,0 +1,19 @@ +package daq.usi; + +public class FakeSwitchTelnetClientSocket extends SwitchTelnetClientSocket { + + public FakeSwitchTelnetClientSocket( + String remoteIpAddress, int remotePort, BaseSwitchController interrogator, boolean debug) { + super(remoteIpAddress, remotePort, interrogator, debug); + } + + @Override + public void writeData(String data) { + System.out.println(data); + } + + @Override + public void disposeConnection() { + System.out.println("disposing connection."); + } +} \ No newline at end of file From 9c0ad5e54638bf64766ad1a22d864289cd6c5768 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 21 Aug 2020 16:29:07 -0700 Subject: [PATCH 108/212] Update dependency firebase-functions to v3.11.0 (#604) --- firebase/functions/package-lock.json | 6 +++--- firebase/functions/package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/firebase/functions/package-lock.json b/firebase/functions/package-lock.json index 42589bac2c..d39919d4fe 100644 --- a/firebase/functions/package-lock.json +++ b/firebase/functions/package-lock.json @@ -1331,9 +1331,9 @@ } }, "firebase-functions": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-3.9.1.tgz", - "integrity": "sha512-LnQQ5EJp8RaSvNZSOz/Ulp9ZQbKUXme/8sa5bLAmcKMc1o/cLu6IMB4GmWJXoi/4O5IFqSrWI9vNqb14LpfSIQ==", + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/firebase-functions/-/firebase-functions-3.11.0.tgz", + "integrity": "sha512-i1uMhZ/M6i5SCI3ulKo7EWX0/LD+I5o6N+sk0HbOWfzyWfOl0iJTvQkR3BVDcjrlhPVC4xG1bDTLxd+DTkLqaw==", "requires": { "@types/express": "4.17.3", "cors": "^2.8.5", diff --git a/firebase/functions/package.json b/firebase/functions/package.json index 78a3f2e8e4..3e506ecf77 100644 --- a/firebase/functions/package.json +++ b/firebase/functions/package.json @@ -15,7 +15,7 @@ "@google-cloud/pubsub": "2.5.0", "@google-cloud/iot": "1.8.0", "firebase-admin": "9.1.1", - "firebase-functions": "3.9.1", + "firebase-functions": "3.11.0", "extend": "3.0.2" }, "private": true From 6f2879b10e6a4739587f1f4195a8edb8c25a6c4b Mon Sep 17 00:00:00 2001 From: Trevor Date: Fri, 21 Aug 2020 21:07:14 -0700 Subject: [PATCH 109/212] Improvements for test development debugging (#609) --- .github/workflows/tests.yml | 9 ++++++++- README.md | 4 ---- bin/test_daq | 7 +++++-- docs/device_report.md | 4 ++-- testing/test_aux.out | 8 ++++---- testing/test_aux.sh | 18 +++++++++++------- testing/test_preamble.sh | 1 - 7 files changed, 30 insertions(+), 21 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e8711c3272..fe101d0ee7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -36,7 +36,14 @@ jobs: DOCKER_STARTUP_TIMEOUT_MS: 60000 GCP_BASE64_CRED: ${{ secrets.GCP_BASE64_CRED }} run: | - DAQ_TEST=${{ matrix.test }} bin/test_daq + bin/test_daq ${{ matrix.test }} + - name: Generated test report + if: ${{ always() }} + run: | + echo '************* Use sed to filter out timestamp prefix *************' + echo 'Download log archive, find the right job, and use:' + echo " sed -e 's/^[-:.0-9TZ]\+ //' 7_Generated\ test\ report.txt" + cat inst/test_${{ matrix.test }}.out unit_tests: runs-on: ubuntu-latest diff --git a/README.md b/README.md index 753bf6bdc4..d162f17012 100644 --- a/README.md +++ b/README.md @@ -19,10 +19,6 @@ More details about the goals and objectives behind this can be found in the IEEE [SDN capabilities](https://queue.acm.org/detail.cfm?id=2560327), such as the [FAUCET OpenFlow controller](https://faucet.nz/), to orchestrate "microsegmentation" on the network for improved security. -* [_Universal Device Management Interface (UDMI)_](schemas/udmi/README.md): An interface -specification designed to normalize the management of IoT devices from different manufacturers. -This is a simple standard that provides for many of the common features not present in -existing protocols (e.g. BACnet). * _Device Management Tools_: A suite of tools, consoles, and dashboards that help operate a robust ecosystem of IoT devices. (Details forthcoming.) diff --git a/bin/test_daq b/bin/test_daq index 38028a4fb0..416d027886 100755 --- a/bin/test_daq +++ b/bin/test_daq @@ -3,11 +3,14 @@ # Catch errors in diff piped through cat set -o pipefail -if [ -z "$DAQ_TEST" ]; then - echo DAQ_TEST not defined. +if [ $# != 1 ]; then + echo Usage: $0 test_name false fi +DAQ_TEST=$1 +shift + function test_finish { echo Exiting test script. } diff --git a/docs/device_report.md b/docs/device_report.md index 9ba625a067..57fc3834ce 100644 --- a/docs/device_report.md +++ b/docs/device_report.md @@ -176,8 +176,8 @@ Check that the device does not have open ports exposing an unencrypted web inter -------------------- # Nmap 7.60 scan initiated XXX as: nmap -v -n -T5 -A --script http-methods --host-timeout=4m --open -p- -oG /tmp/http.log X.X.X.X # Ports scanned: TCP(65535;1-65535) UDP(0;) SCTP(0;) PROTOCOLS(0;) -Host: X.X.X.X () Status: Up -Host: X.X.X.X () Ports: 10000/open/tcp//snet-sensor-mgmt?/// +Host: X.X.X.X () Status: Up +Host: X.X.X.X () Ports: 10000/open/tcp//snet-sensor-mgmt?/// # Nmap done at XXX -- 1 IP address (1 host up) scanned in XXX No running http servers have been found. -------------------- diff --git a/testing/test_aux.out b/testing/test_aux.out index 9586d53679..ba5b105d5a 100644 --- a/testing/test_aux.out +++ b/testing/test_aux.out @@ -212,10 +212,10 @@ port-02 module_config modules `\.-''__.-' \ ( \_ `''' `\__ /\ ') -Host: X.X.X.X () Status: Up -Host: X.X.X.X () Ports: 47808/closed/udp//bacnet/// -Host: X.X.X.X () Status: Up -Host: X.X.X.X () Ports: 10000/open/tcp//snet-sensor-mgmt?/// +Host: X.X.X.X () Status: Up +Host: X.X.X.X () Ports: 47808/closed/udp//bacnet/// +Host: X.X.X.X () Status: Up +Host: X.X.X.X () Ports: 10000/open/tcp//snet-sensor-mgmt?/// Redacted docs diff No report diff 9a02571e8f01: ['9a02571e8f01:ping:Exception'] diff --git a/testing/test_aux.sh b/testing/test_aux.sh index 11603ae121..afddb3ae3c 100755 --- a/testing/test_aux.sh +++ b/testing/test_aux.sh @@ -36,7 +36,7 @@ EOF function capture_test_results { module_name=$1 - for mac in 9a02571e8f01 3c5ab41e8f0b 3c5ab41e8f0a; do + for mac in 9a02571e8f01 3c5ab41e8f0b 3c5ab41e8f0a; do fgrep -h RESULT inst/run-$mac/nodes/$module_name*/tmp/report.txt | tee -a $TEST_RESULTS done } @@ -65,11 +65,11 @@ site_path: inst/test_site schema_path: schemas/udmi interfaces: faux-1: - opts: brute broadcast_client ntpv4 + opts: brute broadcast_client ntpv4 faux-2: - opts: nobrute expiredtls bacnetfail pubber passwordfail ntpv3 opendns ssh + opts: nobrute expiredtls bacnetfail pubber passwordfail ntpv3 opendns ssh faux-3: - opts: tls macoui passwordpass bacnet pubber broadcast_client ssh + opts: tls macoui passwordpass bacnet pubber broadcast_client ssh long_dhcp_response_sec: 0 monitor_scan_sec: 20 EOF @@ -107,7 +107,7 @@ echo %%%%%%%%%%%%%%%%%%%%%%%%% Starting aux test run cmd/run -s # Capture RESULT lines from ping activation logs (not generated report). -for mac in 9a02571e8f01 3c5ab41e8f0b 3c5ab41e8f0a; do +for mac in 9a02571e8f01 3c5ab41e8f0b 3c5ab41e8f0a; do fgrep -h RESULT inst/run-$mac/nodes/ping*/activate.log \ | sed -e 's/\s*\(%%.*\)*$//' | tee -a $TEST_RESULTS done @@ -166,8 +166,12 @@ cat inst/reports/report_9a02571e8f01_*.md | redact > out/redacted_file.md fgrep Host: out/redacted_file.md | tee -a $TEST_RESULTS echo Redacted docs diff | tee -a $TEST_RESULTS -(diff out/redacted_docs.md out/redacted_file.md && echo No report diff) \ - | tee -a $TEST_RESULTS +diff out/redacted_docs.md out/redacted_file.md > out/redacted_file.diff +cat -vet out/redacted_file.diff | tee -a $TEST_RESULTS +diff_lines=`cat out/redacted_file.diff | wc -l` +if [ $diff_lines == 0 ]; then + echo No report diff | tee -a $TEST_RESULTS +fi # Make sure there's no file pollution from the test run. git status --porcelain | tee -a $TEST_RESULTS diff --git a/testing/test_preamble.sh b/testing/test_preamble.sh index 1c6f6431b9..247822623c 100644 --- a/testing/test_preamble.sh +++ b/testing/test_preamble.sh @@ -65,7 +65,6 @@ function redact { -e 's/Seq Index.*//' \ -e 's/Ignored State.*//' \ -e 's/Not shown: .* ports//' \ - -e 's/\t/ /g' \ -e 's/([0-9]{1,3}\.){3}[0-9]{1,3}/X.X.X.X/' } From 68830e6063c486cdf8b57c87d537bc80c96d8329 Mon Sep 17 00:00:00 2001 From: Trevor Date: Sat, 22 Aug 2020 06:27:18 -0700 Subject: [PATCH 110/212] Increase nmap module timeout (#611) --- docs/device_report.md | 3 ++- resources/setups/baseline/module_config.json | 2 ++ testing/test_aux.out | 6 ++++-- testing/test_base.out | 11 +++++++++-- testing/test_base.sh | 4 ++-- 5 files changed, 19 insertions(+), 7 deletions(-) diff --git a/docs/device_report.md b/docs/device_report.md index 57fc3834ce..2ea1fb5032 100644 --- a/docs/device_report.md +++ b/docs/device_report.md @@ -189,6 +189,7 @@ RESULT pass security.nmap.http No running http servers have been found. |Attribute|Value| |---|---| +|timeout_sec|600| |enabled|True| ## Module discover @@ -476,8 +477,8 @@ RESULT skip security.passwords.telnet Port 23 not open on target device. |Attribute|Value| |---|---| -|enabled|True| |dictionary_dir|resources/faux| +|enabled|True| ## Module udmi diff --git a/resources/setups/baseline/module_config.json b/resources/setups/baseline/module_config.json index a6c53b8ba0..5999aa59b6 100644 --- a/resources/setups/baseline/module_config.json +++ b/resources/setups/baseline/module_config.json @@ -10,6 +10,7 @@ "enabled": true }, "nmap": { + "timeout_sec": 600, "enabled": true }, "switch": { @@ -19,6 +20,7 @@ "enabled": true }, "password": { + "dictionary_dir": "resources/faux", "enabled": true }, "bacext": { diff --git a/testing/test_aux.out b/testing/test_aux.out index ba5b105d5a..1d0feffb64 100644 --- a/testing/test_aux.out +++ b/testing/test_aux.out @@ -120,7 +120,8 @@ port-01 module_config modules "enabled": true }, "nmap": { - "enabled": true + "enabled": true, + "timeout_sec": 600 }, "pass": { "enabled": true @@ -178,7 +179,8 @@ port-02 module_config modules "enabled": true }, "nmap": { - "enabled": true + "enabled": true, + "timeout_sec": 600 }, "pass": { "enabled": false diff --git a/testing/test_base.out b/testing/test_base.out index 4f96ea4673..c0208bd8de 100644 --- a/testing/test_base.out +++ b/testing/test_base.out @@ -124,6 +124,7 @@ RESULT pass security.nmap.http No running http servers have been found. |Attribute|Value| |---|---| +|timeout_sec|600| |enabled|True| ## Module hold @@ -138,9 +139,15 @@ terminated %%%%%%%%%%%%%%%%%%%%%% Telnet fail DAQ result code 1 9a02571e8f00: ['9a02571e8f00:hold:DaqException'] +|fail|security.nmap.ports|Other|Other|Some disallowed ports are open: 23.| +security.nmap.ports +RESULT fail security.nmap.ports Some disallowed ports are open: 23. %%%%%%%%%%%%%%%%%%%%%% Default MUD -DAQ result code 1 -9a02571e8f00: ['9a02571e8f00:nmap:TimeoutError'] +DAQ result code 0 +9a02571e8f00: [] +|pass|security.nmap.ports|Other|Other|Only allowed ports found open.| +security.nmap.ports +RESULT pass security.nmap.ports Only allowed ports found open. %%%%%%%%%%%%%%%%%%%%%% External switch tests 9a02571e8f00: [] dp_id: 1 diff --git a/testing/test_base.sh b/testing/test_base.sh index 8deaaf3d09..1a0701144e 100755 --- a/testing/test_base.sh +++ b/testing/test_base.sh @@ -31,7 +31,7 @@ cmd/run -s -k interfaces.faux.opts=telnet echo DAQ result code $? | tee -a $TEST_RESULTS cat inst/result.log | tee -a $TEST_RESULTS cat inst/run-9a02571e8f00/nodes/nmap01/activate.log -fgrep 'security.ports.nmap' inst/reports/report_9a02571e8f00_*.md | tee -a $TEST_RESULTS +fgrep 'security.nmap.ports' inst/reports/report_9a02571e8f00_*.md | tee -a $TEST_RESULTS DAQ_TARGETS=test_hold cmd/build # Except with a default MUD file that blocks the port. @@ -39,7 +39,7 @@ echo %%%%%%%%%%%%%%%%%%%%%% Default MUD | tee -a $TEST_RESULTS cmd/run -s interfaces.faux.opts=telnet device_specs=resources/device_specs/simple.json echo DAQ result code $? | tee -a $TEST_RESULTS cat inst/result.log | tee -a $TEST_RESULTS -fgrep 'security.ports.nmap' inst/reports/report_9a02571e8f00_*.md | tee -a $TEST_RESULTS +fgrep 'security.nmap.ports' inst/reports/report_9a02571e8f00_*.md | tee -a $TEST_RESULTS cat inst/run-9a02571e8f00/nodes/nmap01/activate.log echo %%%%%%%%%%%%%%%%%%%%%% External switch tests | tee -a $TEST_RESULTS From 18124ad380f6d23d52d62c09f7e0c761695cf385 Mon Sep 17 00:00:00 2001 From: Trevor Pering Date: Sat, 22 Aug 2020 06:30:23 -0700 Subject: [PATCH 111/212] Changelog 1.9.5 --- docs/changelog.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changelog.md b/docs/changelog.md index 32f526538b..bedd5c2366 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,4 +1,8 @@ # Changelog +* 1.9.5 + * Increase nmap module timeout (#611) + * Improvements for test development debugging (#609) + * Add module config system logging (#607) * 1.9.4 * Feature/convert switchtests (#601) * Do not infinite spawn ntp (#598) From a8cae2d381acf2248c2621ccb43bb1fb47eb9639 Mon Sep 17 00:00:00 2001 From: Trevor Pering Date: Sat, 22 Aug 2020 06:40:02 -0700 Subject: [PATCH 112/212] 1.9.5 release --- etc/docker_images.txt | 4 ++-- etc/docker_images.ver | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/etc/docker_images.txt b/etc/docker_images.txt index e5ba459100..f8a184f0ab 100644 --- a/etc/docker_images.txt +++ b/etc/docker_images.txt @@ -22,7 +22,7 @@ daqf/test_pass 62dd10381336 daqf/test_password d318555d2d3e daqf/test_ping fe8e4dd5ddc2 daqf/test_ssh 054efbf1b3c3 -daqf/test_switch 5daf5774fb11 +daqf/test_switch e5bb16e85362 daqf/test_tls 17de1ebf13ce daqf/test_udmi b6d5381f32f0 -daqf/usi 3e773df34234 +daqf/usi 348d54ddbb7c diff --git a/etc/docker_images.ver b/etc/docker_images.ver index 77fee73a8c..158c747293 100644 --- a/etc/docker_images.ver +++ b/etc/docker_images.ver @@ -1 +1 @@ -1.9.3 +1.9.5 From d8fb74d6c6950c883d4c39021bd36f26e528f620 Mon Sep 17 00:00:00 2001 From: Trevor Date: Sat, 22 Aug 2020 11:36:59 -0700 Subject: [PATCH 113/212] Restore tab redaction (#612) --- testing/test_aux.out | 8 ++++---- testing/test_preamble.sh | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/testing/test_aux.out b/testing/test_aux.out index 1d0feffb64..36df1a799f 100644 --- a/testing/test_aux.out +++ b/testing/test_aux.out @@ -214,10 +214,10 @@ port-02 module_config modules `\.-''__.-' \ ( \_ `''' `\__ /\ ') -Host: X.X.X.X () Status: Up -Host: X.X.X.X () Ports: 47808/closed/udp//bacnet/// -Host: X.X.X.X () Status: Up -Host: X.X.X.X () Ports: 10000/open/tcp//snet-sensor-mgmt?/// +Host: X.X.X.X () Status: Up +Host: X.X.X.X () Ports: 47808/closed/udp//bacnet/// +Host: X.X.X.X () Status: Up +Host: X.X.X.X () Ports: 10000/open/tcp//snet-sensor-mgmt?/// Redacted docs diff No report diff 9a02571e8f01: ['9a02571e8f01:ping:Exception'] diff --git a/testing/test_preamble.sh b/testing/test_preamble.sh index 247822623c..f2028d089d 100644 --- a/testing/test_preamble.sh +++ b/testing/test_preamble.sh @@ -65,7 +65,11 @@ function redact { -e 's/Seq Index.*//' \ -e 's/Ignored State.*//' \ -e 's/Not shown: .* ports//' \ + -e 's/[ \t]*$//' \ + -e 's/\t/ /g' \ -e 's/([0-9]{1,3}\.){3}[0-9]{1,3}/X.X.X.X/' + + # NOTE: Whitespace redaction (\t) is because many IDEs automatically strip/convert tabs to spaces. } function monitor_log { From 3f855f3fcf1d2f2492e1fd6e19732eae9c013577 Mon Sep 17 00:00:00 2001 From: henry54809 Date: Sat, 22 Aug 2020 20:25:29 -0700 Subject: [PATCH 114/212] usi logs gcp and local capture (#613) --- cmd/exrun | 2 +- cmd/usi | 9 ++++++++- usi/start | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/cmd/exrun b/cmd/exrun index da52e80451..c93bdf9d51 100755 --- a/cmd/exrun +++ b/cmd/exrun @@ -123,7 +123,7 @@ docker rm -f daq-usi || true docker0_ip=`sudo ifconfig docker0 | grep 'inet ' | awk '{print $2}'` if [ -z "$usi_setup_url" -o "$usi_setup_url" == "localhost:5000" -o "$usi_setup_url" == "$docker0_ip:5000" ]; then sudo iptables -C INPUT -i docker0 -j ACCEPT || sudo iptables -A INPUT -i docker0 -j ACCEPT - autostart cmd/usi + autostart gcp_cred=$gcp_cred cmd/usi docker0_ip=`sudo ifconfig docker0 | grep 'inet ' | awk '{print $2}'` uri_url_override="usi_setup.url=$docker0_ip:5000" fi diff --git a/cmd/usi b/cmd/usi index d69f387f52..1e98973f5b 100755 --- a/cmd/usi +++ b/cmd/usi @@ -3,6 +3,8 @@ ROOT=$(realpath $(dirname $0)/..) USI_DIR=$ROOT/inst/network DEBUG="" +log_driver="" +debug_mode="true" #Always in debug mode for now if [ -n $debug_mode ]; then DEBUG="debug" echo Starting USI in debug mode @@ -10,9 +12,14 @@ else echo Starting USI fi +if [ -f "$gcp_cred" ]; then + origin=`jq -r '.client_email' $gcp_cred | sed 's/@.*//'` + log_driver="--log-driver=gcplogs --log-opt labels=origin --label origin=$origin" +fi rm -rf $USI_DIR mkdir -p $USI_DIR -docker run -d -v $USI_DIR:/ovs --privileged --network=host -e DEBUG=$DEBUG --name daq-usi daqf/usi +GOOGLE_APPLICATION_CREDENTIALS=$gcp_cred docker run -d $log_driver -v $USI_DIR:/ovs --privileged --network=host -e DEBUG=$DEBUG --name daq-usi daqf/usi +echo DAQ autoclean docker cp daq-usi:/root/logs.txt inst/usi-logs.txt echo DAQ autoclean docker kill daq-usi diff --git a/usi/start b/usi/start index 7e1837a619..7e25c0035f 100755 --- a/usi/start +++ b/usi/start @@ -1,2 +1,2 @@ #!/bin/bash -e -java -cp /ovs:usi/target/usi-0.0.1-jar-with-dependencies.jar daq.usi.UsiServer $DEBUG +java -cp /ovs:usi/target/usi-0.0.1-jar-with-dependencies.jar daq.usi.UsiServer $DEBUG 2>&1 | tee logs.txt From f7da97332192e0a58e472230a06cb8857bef9efa Mon Sep 17 00:00:00 2001 From: Trevor Date: Sat, 22 Aug 2020 21:02:00 -0700 Subject: [PATCH 115/212] Add usi to build check path (#614) --- bin/build_hash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/build_hash b/bin/build_hash index ef31e8ecca..4dcaa8e9a6 100755 --- a/bin/build_hash +++ b/bin/build_hash @@ -10,7 +10,7 @@ build_built=.build_built faucet_version=$(cd faucet; git rev-list -n 1 HEAD) echo "$faucet_version faucet/HEAD" > $build_files -find docker/ subset/ -type f | sort | xargs sha1sum >> $build_files +find docker/ subset/ usi/ -type f | sort | xargs sha1sum >> $build_files build_hash=`cat $build_files | sha256sum | awk '{print $1}'` if [ "$1" == check ]; then From ce3bf1b47c075086b6bf4c5184d69c59457edf06 Mon Sep 17 00:00:00 2001 From: Trevor Pering Date: Sun, 23 Aug 2020 06:50:18 -0700 Subject: [PATCH 116/212] Removing usi gcp log driver setup --- cmd/usi | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/cmd/usi b/cmd/usi index 1e98973f5b..586ab8468b 100755 --- a/cmd/usi +++ b/cmd/usi @@ -3,7 +3,7 @@ ROOT=$(realpath $(dirname $0)/..) USI_DIR=$ROOT/inst/network DEBUG="" -log_driver="" + debug_mode="true" #Always in debug mode for now if [ -n $debug_mode ]; then DEBUG="debug" @@ -12,14 +12,9 @@ else echo Starting USI fi -if [ -f "$gcp_cred" ]; then - origin=`jq -r '.client_email' $gcp_cred | sed 's/@.*//'` - log_driver="--log-driver=gcplogs --log-opt labels=origin --label origin=$origin" -fi - rm -rf $USI_DIR mkdir -p $USI_DIR -GOOGLE_APPLICATION_CREDENTIALS=$gcp_cred docker run -d $log_driver -v $USI_DIR:/ovs --privileged --network=host -e DEBUG=$DEBUG --name daq-usi daqf/usi +GOOGLE_APPLICATION_CREDENTIALS=$gcp_cred docker run -d -v $USI_DIR:/ovs --privileged --network=host -e DEBUG=$DEBUG --name daq-usi daqf/usi echo DAQ autoclean docker cp daq-usi:/root/logs.txt inst/usi-logs.txt echo DAQ autoclean docker kill daq-usi From 702baad9472403a49c029e461bf2edd6b0e15259 Mon Sep 17 00:00:00 2001 From: Trevor Date: Mon, 24 Aug 2020 13:49:38 -0700 Subject: [PATCH 117/212] Use daq_run_id for gcp combine_results (#616) --- bin/combine_reports | 9 +------ ..._from_date_range.py => combine_reports.py} | 26 ++++++++++++------- cmd/usi | 2 +- daq/gcp.py | 12 ++++++--- daq/host.py | 1 + daq/runner.py | 14 +++++++--- firebase/functions/index.js | 3 ++- testing/test_many.sh | 15 ++++++----- .../report_1.json | 0 .../report_2.json | 0 ..._date_range.py => test_combine_reports.py} | 14 +++++----- 11 files changed, 56 insertions(+), 40 deletions(-) rename bin/python/{combine_reports_from_date_range.py => combine_reports.py} (89%) rename testing/unit/mock/{test_combine_reports_from_date_range => test_combine_reports}/report_1.json (100%) rename testing/unit/mock/{test_combine_reports_from_date_range => test_combine_reports}/report_2.json (100%) rename testing/unit/{test_combine_reports_from_date_range.py => test_combine_reports.py} (91%) diff --git a/bin/combine_reports b/bin/combine_reports index e7ac571799..9d18b334b0 100755 --- a/bin/combine_reports +++ b/bin/combine_reports @@ -5,11 +5,4 @@ cd $ROOT source etc/config_base.sh -FAILED= -PYTHONPATH=daq python3 bin/python/combine_reports_from_date_range.py $conf_file $@ || FAILED=true - -if [ -n "$FAILED" ]; then - echo - echo Usage: $0 [from_time] [to_time] [from_gcp] - false -fi +PYTHONPATH=daq python3 bin/python/combine_reports.py $conf_file $@ diff --git a/bin/python/combine_reports_from_date_range.py b/bin/python/combine_reports.py similarity index 89% rename from bin/python/combine_reports_from_date_range.py rename to bin/python/combine_reports.py index ea3de4d17a..824099dbdf 100644 --- a/bin/python/combine_reports_from_date_range.py +++ b/bin/python/combine_reports.py @@ -11,7 +11,7 @@ from gcp import GcpManager from report import MdTable -LOGGER = logger.get_logger('combine_reports_from_date_range') +LOGGER = logger.get_logger('combine') DEFAULT_REPORTS_DIR = os.path.join('inst', 'reports') @@ -76,7 +76,8 @@ def _get_local_reports(device, reports_dir, start, end, count): yield json.loads(json_file_handler.read()) -def main(device, start=None, end=None, gcp=None, reports_dir=DEFAULT_REPORTS_DIR, count=0): +def main(device, start=None, end=None, gcp=None, reports_dir=DEFAULT_REPORTS_DIR, + count=0, daq_run_id=None): # pylint: disable=too-many-arguments # pylint: disable=too-many-locals """Main script function""" @@ -85,9 +86,10 @@ def main(device, start=None, end=None, gcp=None, reports_dir=DEFAULT_REPORTS_DIR report_source = 'gcp' if gcp else 'local' if gcp: device_full = ":".join([device[i:i + 2] for i in range(0, len(device), 2)]) - json_reports = gcp.get_reports_from_date_range(device_full, start=start, end=end, - count=count) + json_reports = gcp.get_reports(device_full, start=start, end=end, + count=count, daq_run_id=daq_run_id) else: + assert not daq_run_id, 'daq_run_id not supported for local queries' json_reports = _get_local_reports(device, reports_dir, start, end, count) json_reports = list(json_reports) @@ -132,17 +134,23 @@ def _convert_iso(timestamp): GCP = None if CONFIG.get('gcp_cred') and CONFIG.get('from_gcp'): GCP = GcpManager(CONFIG, None) - assert all([attr in CONFIG for attr in ('from_time', 'to_time', 'device')]), """ + else: + assert not CONFIG.get('from_gcp'), 'missing gcp_cred definition' + + assert 'device' in CONFIG, """ Combines reports under inst/reports(default) or from GCP -Usage: combine_reports_from_date_range.py +Usage: combine_reports.py [local/system.yaml] device=xx:xx:xx:xx:xx:xx - from_time='YYYY-MM-DDThh:mm:ss' - to_time='YYYY-MM-DDThh:mm:ss' + [from_time='YYYY-MM-DDThh:mm:ss'] + [to_time='YYYY-MM-DDThh:mm:ss'] + [daq_run_id=] [count=N] [from_gcp='true'] """ FROM_TIME = _convert_iso(CONFIG.get('from_time')) TO_TIME = _convert_iso(CONFIG.get('to_time')) COUNT = int(CONFIG.get('count', 0)) - main(CONFIG.get('device'), start=FROM_TIME, end=TO_TIME, gcp=GCP, count=COUNT) + DAQ_RUN_ID = CONFIG.get('daq_run_id') + main(CONFIG.get('device'), start=FROM_TIME, end=TO_TIME, gcp=GCP, + count=COUNT, daq_run_id=DAQ_RUN_ID) diff --git a/cmd/usi b/cmd/usi index 586ab8468b..4965cf2d64 100755 --- a/cmd/usi +++ b/cmd/usi @@ -16,5 +16,5 @@ rm -rf $USI_DIR mkdir -p $USI_DIR GOOGLE_APPLICATION_CREDENTIALS=$gcp_cred docker run -d -v $USI_DIR:/ovs --privileged --network=host -e DEBUG=$DEBUG --name daq-usi daqf/usi -echo DAQ autoclean docker cp daq-usi:/root/logs.txt inst/usi-logs.txt +echo DAQ autoclean docker cp daq-usi:/root/logs.txt inst/cmdusi.log echo DAQ autoclean docker kill daq-usi diff --git a/daq/gcp.py b/daq/gcp.py index 67db631e0b..0dea14d14f 100644 --- a/daq/gcp.py +++ b/daq/gcp.py @@ -264,19 +264,25 @@ def _get_json_report(self, runid): blob = self._bucket.blob(report_blob) return json.loads(str(blob.download_as_string(), 'utf-8')) - def get_reports_from_date_range(self, device: str, start=None, end=None, count=None): - """Combine test results from reports within a date range""" + # pylint: disable=too-many-arguments + def get_reports(self, device: str, start=None, end=None, count=None, daq_run_id=None): + """Get filtered list of reports""" if not self._firestore: LOGGER.error('Firestore not initialized.') return - LOGGER.info('Looking for reports...') + LOGGER.info('Looking for reports from GCP...') limit_count = count if count else DEFAULT_LIMIT origin = self._firestore.collection(u'origin').document(self._client_name).get() query = origin.reference.collection('runid').where('deviceId', '==', device) if start: + LOGGER.info('Limiting to start time %s', to_timestamp(start)) query = query.where('updated', '>=', to_timestamp(start)) if end: + LOGGER.info('Limiting to end time %s', to_timestamp(end)) query = query.where('updated', '<=', to_timestamp(end)) + if daq_run_id: + LOGGER.info('Limiting to DAQ run id %s', daq_run_id) + query = query.where('daq_run_id', '==', daq_run_id) runids = query.order_by(u'updated', direction=DESCENDING).limit(limit_count).stream() for runid in runids: json_report = self._get_json_report(runid) diff --git a/daq/host.py b/daq/host.py index 5afce889a6..c600cb3835 100644 --- a/daq/host.py +++ b/daq/host.py @@ -776,6 +776,7 @@ def _record_result(self, name, run_info=True, current=None, **kwargs): result = { 'name': name, 'runid': (self.run_id if run_info else None), + 'daq_run_id': self.runner.daq_run_id, 'device_id': self.target_mac, 'started': self.test_start, 'timestamp': current if current else gcp.get_timestamp(), diff --git a/daq/runner.py b/daq/runner.py index ad3f18a82d..26b5ab3c54 100644 --- a/daq/runner.py +++ b/daq/runner.py @@ -158,16 +158,16 @@ def __init__(self, config): self.result_log = self._open_result_log() self._system_active = False logging_client = self.gcp.get_logging_client() - self._daq_run_id = uuid.uuid4() + self.daq_run_id = self._init_daq_run_id() if logging_client: logger.set_stackdriver_client(logging_client, - labels={"daq_run_id": str(self._daq_run_id)}) + labels={"daq_run_id": self.daq_run_id}) test_list = self._get_test_list(config.get('host_tests', self._DEFAULT_TESTS_FILE), []) if self.config.get('keep_hold'): LOGGER.info('Appending test_hold to master test list') test_list.append('hold') config['test_list'] = test_list - LOGGER.info('DAQ RUN id: %s' % self._daq_run_id) + LOGGER.info('DAQ RUN id: %s' % self.daq_run_id) LOGGER.info('Configured with tests %s' % ', '.join(config['test_list'])) LOGGER.info('DAQ version %s' % self._daq_version) LOGGER.info('LSB release %s' % self._lsb_release) @@ -180,6 +180,12 @@ def _get_states(self): states = connected_host.pre_states() + self.config['test_list'] return states + connected_host.post_states() + def _init_daq_run_id(self): + daq_run_id = str(uuid.uuid4()) + with open('inst/daq_run_id.txt', 'w') as output_stream: + output_stream.write(daq_run_id + '\n') + return daq_run_id + def _send_heartbeat(self): message = { 'name': 'status', @@ -197,7 +203,7 @@ def get_run_info(self): 'version': self._daq_version, 'lsb': self._lsb_release, 'uname': self._sys_uname, - 'daq_run_id': str(self._daq_run_id) + 'daq_run_id': self.daq_run_id } data_retention_days = self.config.get('run_data_retention_days', self._DEFAULT_RETENTION_DAYS) diff --git a/firebase/functions/index.js b/firebase/functions/index.js index 12b6a11875..4db0fd5e53 100644 --- a/firebase/functions/index.js +++ b/firebase/functions/index.js @@ -147,7 +147,7 @@ function handleTestResult(origin, siteName, message) { } console.log('Test Result: ', timestamp, origin, siteName, message.port, - message.runid, message.name, message.device_id, message.state); + message.runid, message.daq_run_id, message.name, message.device_id, message.state); const runDoc = originDoc.collection('runid').doc(message.runid); const lastDoc = originDoc.collection('last').doc(message.name); const resultDoc = runDoc.collection('test').doc(message.name); @@ -168,6 +168,7 @@ function handleTestResult(origin, siteName, message) { } return Promise.all([ runDoc.set({ 'updated': timestamp, + 'daq_run_id': message.daq_run_id, 'last_name': message.name }, { merge: true }), resultDoc.set(message), diff --git a/testing/test_many.sh b/testing/test_many.sh index 86c86fc299..e0699857e1 100755 --- a/testing/test_many.sh +++ b/testing/test_many.sh @@ -112,8 +112,9 @@ echo Enough ipaddr tests: $((ip_notifications >= (NUM_IPADDR_TEST_DEVICES - NUM_ echo Enough alternate subnet ips: $((alternate_subnet_ip >= (NUM_IPADDR_TEST_DEVICES - NUM_IPADDR_TEST_TIMEOUT_DEVICES) )) | tee -a $TEST_RESULTS echo Enough ipaddr timeouts: $((ipaddr_timeouts >= NUM_IPADDR_TEST_TIMEOUT_DEVICES)) | tee -a $TEST_RESULTS -echo bin/combine_reports device=9a:02:57:1e:8f:05 from_time=$start_time to_time=$end_time count=2 -bin/combine_reports device=9a:02:57:1e:8f:05 from_time=$start_time to_time=$end_time count=2 +combine_cmd="bin/combine_reports device=9a:02:57:1e:8f:05 from_time=$start_time to_time=$end_time count=2" +echo $combine_cmd +$combine_cmd cat inst/reports/combo_*.md @@ -129,11 +130,11 @@ if [ -f "$gcp_cred" ]; then ls -l inst/reports/report_9a02571e8f05*.md echo '*************************' - echo Pulling reports from gcp... from $start_time to $end_time - cmd="bin/combine_reports device=9a:02:57:1e:8f:05 from_time=$start_time to_time=$end_time" - cmd="$cmd count=2 from_gcp=true" - echo $cmd - $cmd + daq_run_id=$(< inst/daq_run_id.txt) + echo Pulling reports from gcp for daq RUN id $daq_run_id + gcp_extras="daq_run_id=$daq_run_id from_gcp=true" + echo $combine_cmd $gcp_extras + $combine_cmd $gcp_extras echo GCP results diff | tee -a $GCP_RESULTS diff inst/reports/combo_*.md out/report_local.md | tee -a $GCP_RESULTS fi diff --git a/testing/unit/mock/test_combine_reports_from_date_range/report_1.json b/testing/unit/mock/test_combine_reports/report_1.json similarity index 100% rename from testing/unit/mock/test_combine_reports_from_date_range/report_1.json rename to testing/unit/mock/test_combine_reports/report_1.json diff --git a/testing/unit/mock/test_combine_reports_from_date_range/report_2.json b/testing/unit/mock/test_combine_reports/report_2.json similarity index 100% rename from testing/unit/mock/test_combine_reports_from_date_range/report_2.json rename to testing/unit/mock/test_combine_reports/report_2.json diff --git a/testing/unit/test_combine_reports_from_date_range.py b/testing/unit/test_combine_reports.py similarity index 91% rename from testing/unit/test_combine_reports_from_date_range.py rename to testing/unit/test_combine_reports.py index 4f62f6a872..d7b944de40 100644 --- a/testing/unit/test_combine_reports_from_date_range.py +++ b/testing/unit/test_combine_reports.py @@ -1,4 +1,4 @@ -"""Unit tests for combine_reports_from_date_range""" +"""Unit tests for combine_reports""" import unittest import sys @@ -8,8 +8,8 @@ from unittest.mock import MagicMock, mock_open, patch import daq -import combine_reports_from_date_range -from combine_reports_from_date_range import _render_results, main, os +import combine_reports +from combine_reports import _render_results, main, os from daq.report import MdTable @@ -18,7 +18,7 @@ class TestCombineReportsFromDateRange(unittest.TestCase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.script_path = os.path.dirname(os.path.realpath(__file__)) - mock_path = os.path.join(self.script_path, 'mock', 'test_combine_reports_from_date_range') + mock_path = os.path.join(self.script_path, 'mock', 'test_combine_reports') self.mocks = {'empty': ''} for filename in os.listdir(mock_path): with open(os.path.join(mock_path, filename)) as f: @@ -93,7 +93,7 @@ def custom_open(report, mode=None): raise Exception(report + ' is not expected') return mock_open(read_data=self.mocks[mock_name]).return_value - combine_reports_from_date_range._render_results = MagicMock(return_value="fake results") + combine_reports._render_results = MagicMock(return_value="fake results") with patch("builtins.open", new=custom_open): main('device1', start=datetime.fromisoformat('2020-05-29')) expected_results = { @@ -110,8 +110,8 @@ def custom_open(report, mode=None): 'report_1_timestamp': True, 'report_2_timestamp': True }} - combine_reports_from_date_range._render_results.assert_called() - call_args = combine_reports_from_date_range._render_results.call_args[0][0] + combine_reports._render_results.assert_called() + call_args = combine_reports._render_results.call_args[0][0] assert self._dict_compare(call_args, expected_results) From 0986517a2bf064ae7d18b9699866f2b30d5f7682 Mon Sep 17 00:00:00 2001 From: henry54809 Date: Tue, 25 Aug 2020 16:12:18 -0700 Subject: [PATCH 118/212] USI docker gcplogs config (#615) --- cmd/usi | 16 +++++++++++++++- .../java/daq/usi/allied/AlliedTelesisX230.java | 5 ++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/cmd/usi b/cmd/usi index 4965cf2d64..44067356c1 100755 --- a/cmd/usi +++ b/cmd/usi @@ -12,9 +12,23 @@ else echo Starting USI fi +if [ -f "$gcp_cred" ]; then + origin=`jq -r '.client_email' $gcp_cred | sed 's/@.*//'` + project=`jq -r '.project_id' $gcp_cred | sed 's/@.*//'` + log_driver="--log-driver=gcplogs --log-opt gcp-project=$project --log-opt labels=origin --label origin=$origin" + sudo mkdir -p /etc/systemd/system/docker.service.d +cat < /etc/systemd/system/docker.service.d/docker-override.conf +[Service] +Environment="GOOGLE_APPLICATION_CREDENTIALS=`realpath $gcp_cred`" +EOF + sudo systemctl daemon-reload + sudo systemctl restart docker +fi + rm -rf $USI_DIR mkdir -p $USI_DIR -GOOGLE_APPLICATION_CREDENTIALS=$gcp_cred docker run -d -v $USI_DIR:/ovs --privileged --network=host -e DEBUG=$DEBUG --name daq-usi daqf/usi +args="-d -v $USI_DIR:/ovs --privileged --network=host -e DEBUG=$DEBUG --name daq-usi daqf/usi" +docker run $log_driver $args || docker run $args echo DAQ autoclean docker cp daq-usi:/root/logs.txt inst/cmdusi.log echo DAQ autoclean docker kill daq-usi diff --git a/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java b/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java index f9ab852b33..affc02d2da 100644 --- a/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java +++ b/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java @@ -209,7 +209,10 @@ private PowerResponse buildPowerResponse(Map powerMap) { float maxPower = 0; float currentPower = 0; try { - maxPower = Float.parseFloat(powerMap.getOrDefault("max", "")); + // AT switch may add trailing "[C]" in power output. + String maxPowerString = powerMap.getOrDefault("max", "") + .replaceAll("\\[.*\\]", ""); + maxPower = Float.parseFloat(maxPowerString); currentPower = Float.parseFloat(powerMap.getOrDefault("power", "")); } catch (NumberFormatException e) { System.out.println( From 55c879f350001fafbd138a800de3d4555032eaf7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 25 Aug 2020 16:24:44 -0700 Subject: [PATCH 119/212] Update dependency gradle to v6.6.1 (#617) --- .../bacnet/bacnetFaux/gradle/wrapper/gradle-wrapper.properties | 2 +- .../network/NTPClient/gradle/wrapper/gradle-wrapper.properties | 2 +- mudacl/gradle/wrapper/gradle-wrapper.properties | 2 +- .../bacnet/bacnetTests/gradle/wrapper/gradle-wrapper.properties | 2 +- subset/network/mac_oui/gradle/wrapper/gradle-wrapper.properties | 2 +- .../security/tlstest/gradle/wrapper/gradle-wrapper.properties | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docker/include/bacnet/bacnetFaux/gradle/wrapper/gradle-wrapper.properties b/docker/include/bacnet/bacnetFaux/gradle/wrapper/gradle-wrapper.properties index 6c9a224775..12d38de6a4 100644 --- a/docker/include/bacnet/bacnetFaux/gradle/wrapper/gradle-wrapper.properties +++ b/docker/include/bacnet/bacnetFaux/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/docker/include/network/NTPClient/gradle/wrapper/gradle-wrapper.properties b/docker/include/network/NTPClient/gradle/wrapper/gradle-wrapper.properties index 6c9a224775..12d38de6a4 100644 --- a/docker/include/network/NTPClient/gradle/wrapper/gradle-wrapper.properties +++ b/docker/include/network/NTPClient/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/mudacl/gradle/wrapper/gradle-wrapper.properties b/mudacl/gradle/wrapper/gradle-wrapper.properties index e15393d384..567aa53d89 100644 --- a/mudacl/gradle/wrapper/gradle-wrapper.properties +++ b/mudacl/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-all.zip diff --git a/subset/bacnet/bacnetTests/gradle/wrapper/gradle-wrapper.properties b/subset/bacnet/bacnetTests/gradle/wrapper/gradle-wrapper.properties index 6c9a224775..12d38de6a4 100644 --- a/subset/bacnet/bacnetTests/gradle/wrapper/gradle-wrapper.properties +++ b/subset/bacnet/bacnetTests/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/subset/network/mac_oui/gradle/wrapper/gradle-wrapper.properties b/subset/network/mac_oui/gradle/wrapper/gradle-wrapper.properties index fa55e31a18..8d8e8abe86 100644 --- a/subset/network/mac_oui/gradle/wrapper/gradle-wrapper.properties +++ b/subset/network/mac_oui/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip diff --git a/subset/security/tlstest/gradle/wrapper/gradle-wrapper.properties b/subset/security/tlstest/gradle/wrapper/gradle-wrapper.properties index 6c9a224775..12d38de6a4 100644 --- a/subset/security/tlstest/gradle/wrapper/gradle-wrapper.properties +++ b/subset/security/tlstest/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From b4528109c2a79bd8e547b827620825c180d9d488 Mon Sep 17 00:00:00 2001 From: henry54809 Date: Tue, 1 Sep 2020 15:00:26 -0700 Subject: [PATCH 120/212] Cisco Switches parsing fix (#623) --- .../java/daq/usi/BaseSwitchController.java | 18 +- .../main/java/daq/usi/cisco/Cisco9300.java | 624 +++++++++--------- .../daq/usi/BaseSwitchControllerTest.java | 34 +- usi/src/test/java/daq/usi/Cisco9300Test.java | 69 ++ 4 files changed, 427 insertions(+), 318 deletions(-) create mode 100644 usi/src/test/java/daq/usi/Cisco9300Test.java diff --git a/usi/src/main/java/daq/usi/BaseSwitchController.java b/usi/src/main/java/daq/usi/BaseSwitchController.java index 5d1c3ef8f1..dc2f736d37 100644 --- a/usi/src/main/java/daq/usi/BaseSwitchController.java +++ b/usi/src/main/java/daq/usi/BaseSwitchController.java @@ -62,9 +62,10 @@ protected static HashMap mapSimpleTable( String rawPacket, String[] colNames, String[] mapNames) { HashMap colMap = new HashMap<>(); String[] lines = rawPacket.split("\n"); - if (lines.length >= 2) { - String header = lines[0].trim(); - String values = lines[1].trim(); + int headerLine = 0; + if (lines.length >= headerLine + 2) { + String header = lines[headerLine].trim(); + String values = lines[headerLine + 1].trim(); int lastSectionEnd = 0; for (int i = 0; i < colNames.length; i++) { int secStart = lastSectionEnd; @@ -77,11 +78,20 @@ protected static HashMap mapSimpleTable( // correct values based off of the sections in between white spaces int firstWhiteSpace = getFirstWhiteSpace(values.substring(lastSectionEnd)) + lastSectionEnd; + // Wrong table header line + if (firstWhiteSpace < 0) { + headerLine++; + break; + } int lastWhiteSpace = getIndexOfNonWhitespaceAfterWhitespace(values.substring(firstWhiteSpace)) + firstWhiteSpace; int nextHeaderStart = header.indexOf(colNames[i + 1]); - secEnd = Math.max(lastWhiteSpace, nextHeaderStart); + if (nextHeaderStart >= firstWhiteSpace) { + secEnd = nextHeaderStart; + } else { + secEnd = Math.max(lastWhiteSpace, nextHeaderStart); + } } lastSectionEnd = secEnd; // \u00A0 is non-breaking space which trim ignores. diff --git a/usi/src/main/java/daq/usi/cisco/Cisco9300.java b/usi/src/main/java/daq/usi/cisco/Cisco9300.java index 4d226b0c31..20142c6e7a 100644 --- a/usi/src/main/java/daq/usi/cisco/Cisco9300.java +++ b/usi/src/main/java/daq/usi/cisco/Cisco9300.java @@ -1,312 +1,312 @@ -package daq.usi.cisco; - -import daq.usi.BaseSwitchController; -import daq.usi.ResponseHandler; -import grpc.InterfaceResponse; -import grpc.LinkStatus; -import grpc.POENegotiation; -import grpc.POEStatus; -import grpc.POESupport; -import grpc.PowerResponse; -import grpc.SwitchActionResponse; -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Map; -import java.util.Queue; -import java.util.stream.Collectors; - - -public class Cisco9300 extends BaseSwitchController { - - private static final String[] interfaceExpected = - {"interface", "name", "status", "vlan", "duplex", "speed", "type"}; - private static final String[] showInterfaceExpected = - {"Port", "Name", "Status", "Vlan", "Duplex", "Speed", "Type"}; - private static final Map powerInlineMap = Map.of("Interface", "dev_interface", - "Inline Power Mode", "admin", - "Operational status", "oper", - "Measured at the port", "power", - "Device Type", "device", - "IEEE Class", "dev_class", - "Power available to the device", "max"); - private static final Map poeStatusMap = Map.of("on", - POEStatus.State.ON, "off", POEStatus.State.OFF, "fault", POEStatus.State.FAULT, - "power-deny", POEStatus.State.DENY); - private static final Map poeSupportMap = Map.of("auto", - POESupport.State.ENABLED, "off", POESupport.State.DISABLED); - private static final Map poeNegotiationtMap = Map.of("auto", - POENegotiation.State.ENABLED, "off", POENegotiation.State.DISABLED); - private static final int WAIT_MS = 100; - private ResponseHandler responseHandler; - - /** - * Cisco 9300 Switch Controller. - * - * @param remoteIpAddress switch ip - * @param user switch username - * @param password switch password - */ - public Cisco9300( - String remoteIpAddress, - String user, - String password) { - this(remoteIpAddress, user, password, false); - } - - /** - * Cisco 9300 Switch Controller. - * - * @param remoteIpAddress switch ip - * @param user switch username - * @param password switch password - * @param debug for verbose output - */ - public Cisco9300( - String remoteIpAddress, - String user, - String password, boolean debug) { - super(remoteIpAddress, user, password, debug); - this.username = user == null ? "admin" : user; - this.password = password == null ? "password" : password; - commandPending = true; - } - - /** - * Generic Cisco Switch command to retrieve the Status of an interface. - */ - private String showIfaceStatusCommand(int interfacePort) { - return "show interface gigabitethernet1/0/" + interfacePort + " status"; - } - - /** - * Generic Cisco Switch command to retrieve the Power Status of an interface. Replace asterisk - * with actual port number for complete message - */ - private String showIfacePowerStatusCommand(int interfacePort) { - return "show power inline gigabitethernet1/0/" + interfacePort + " detail"; - } - - /** - * Get port toggle commands. - * - * @param interfacePort port number - * @param enabled for bringing up/down interfacePort - * @return commands - */ - private String[] portManagementCommand(int interfacePort, boolean enabled) { - return new String[] { - "configure terminal", - "interface gigabitethernet1/0/" + interfacePort, - (enabled ? "no " : "") + "shutdown", - "end" - }; - } - - /** - * Handles the process when using the enter command. Enable is a required step before commands can - * be sent to the switch. - * - * @param consoleData Raw console data received the the telnet connection. - */ - @Override - public void handleEnableMessage(String consoleData) throws Exception { - if (consoleData.contains("Password:")) { - telnetClientSocket.writeData(password + "\n"); - } else if (containsPrompt(consoleData)) { - userEnabled = true; - commandPending = false; - } else if (consoleData.contains("% Bad passwords")) { - telnetClientSocket.disposeConnection(); - throw new Exception("Could not Enable the User, Bad Password"); - } - } - - /** - * Handles the process when logging into the switch. - * - * @param consoleData Raw console data received the the telnet connection. - */ - @Override - public void handleLoginMessage(String consoleData) throws Exception { - if (consoleData.contains("Username:")) { - telnetClientSocket.writeData(username + "\n"); - } else if (consoleData.contains("Password:")) { - telnetClientSocket.writeData(password + "\n"); - } else if (consoleData.endsWith(CONSOLE_PROMPT_ENDING_LOGIN)) { - userAuthorised = true; - hostname = consoleData.split(CONSOLE_PROMPT_ENDING_LOGIN)[0]; - telnetClientSocket.writeData("enable\n"); - } else if (consoleData.contains("% Login invalid")) { - telnetClientSocket.disposeConnection(); - throw new Exception("Failed to Login, Login Invalid"); - } else if (consoleData.contains("% Bad passwords")) { - telnetClientSocket.disposeConnection(); - throw new Exception("Failed to Login, Bad Password"); - } - } - - /** - * Handles current data in the buffer read from the telnet console InputStream and sends it to the - * appropriate process. - * - * @param consoleData Current unhandled data in the buffered reader - */ - @Override - public void parseData(String consoleData) throws Exception { - if (commandPending) { - responseHandler.receiveData(consoleData); - } - } - - @Override - public void getPower(int devicePort, ResponseHandler powerResponseHandler) - throws Exception { - while (commandPending) { - Thread.sleep(WAIT_MS); - } - String command = showIfacePowerStatusCommand(devicePort); - synchronized (this) { - commandPending = true; - responseHandler = data -> { - synchronized (this) { - commandPending = false; - } - Map powerMap = processPowerStatusInline(data); - powerResponseHandler.receiveData(buildPowerResponse(powerMap)); - }; - telnetClientSocket.writeData(command + "\n"); - } - } - - @Override - public void getInterface(int devicePort, ResponseHandler handler) - throws Exception { - while (commandPending) { - Thread.sleep(WAIT_MS); - } - String command = showIfaceStatusCommand(devicePort); - synchronized (this) { - commandPending = true; - responseHandler = data -> { - synchronized (this) { - commandPending = false; - } - Map interfaceMap = processInterfaceStatus(data); - handler.receiveData(buildInterfaceResponse(interfaceMap)); - }; - telnetClientSocket.writeData(command + "\n"); - } - } - - private void managePort(int devicePort, ResponseHandler handler, - boolean enabled) throws Exception { - while (commandPending) { - Thread.sleep(WAIT_MS); - } - Queue commands = - new LinkedList<>(Arrays.asList(portManagementCommand(devicePort, enabled))); - SwitchActionResponse.Builder response = SwitchActionResponse.newBuilder(); - synchronized (this) { - commandPending = true; - responseHandler = data -> { - if (!commands.isEmpty()) { - telnetClientSocket.writeData(commands.poll() + "\n"); - return; - } - synchronized (this) { - commandPending = false; - handler.receiveData(response.setSuccess(true).build()); - } - }; - telnetClientSocket.writeData(commands.poll() + "\n"); - } - } - - @Override - public void connect(int devicePort, ResponseHandler handler) - throws Exception { - managePort(devicePort, handler, true); - } - - @Override - public void disconnect(int devicePort, ResponseHandler handler) - throws Exception { - managePort(devicePort, handler, false); - } - - private InterfaceResponse buildInterfaceResponse(Map interfaceMap) { - InterfaceResponse.Builder response = InterfaceResponse.newBuilder(); - String duplex = interfaceMap.getOrDefault("duplex", ""); - if (duplex.startsWith("a-")) { // Interface in Auto Duplex - duplex = duplex.replaceFirst("a-", ""); - } - - String speed = interfaceMap.getOrDefault("speed", ""); - if (speed.startsWith("a-")) { // Interface in Auto Speed - speed = speed.replaceFirst("a-", ""); - } - int speedNum = 0; - try { - speedNum = Integer.parseInt(speed); - } catch (NumberFormatException e) { - System.out.println("Could not parse int for interface speed: " + speed); - return response.build(); - } - - String linkStatus = interfaceMap.getOrDefault("status", ""); - return response - .setLinkStatus(linkStatus.equals("connected") ? LinkStatus.State.UP : LinkStatus.State.DOWN) - .setDuplex(duplex) - .setLinkSpeed(speedNum) - .build(); - } - - private PowerResponse buildPowerResponse(Map powerMap) { - PowerResponse.Builder response = PowerResponse.newBuilder(); - float maxPower = 0; - float currentPower = 0; - try { - maxPower = Float.parseFloat(powerMap.getOrDefault("max", "")); - currentPower = Float.parseFloat(powerMap.getOrDefault("power", "")); - } catch (NumberFormatException e) { - System.out.println( - "Could not parse float: " + powerMap.get("max") + " or " + powerMap.get("power")); - } - - String poeSupport = powerMap.getOrDefault("admin", ""); - String poeStatus = powerMap.getOrDefault("oper", ""); - return response - .setPoeStatus(poeStatusMap.getOrDefault(poeStatus, POEStatus.State.UNKNOWN)) - .setPoeSupport(poeSupportMap.getOrDefault(poeSupport, POESupport.State.UNKNOWN)) - .setPoeNegotiation( - poeNegotiationtMap.getOrDefault(poeStatus, POENegotiation.State.UNKNOWN)) - .setMaxPowerConsumption(maxPower) - .setCurrentPowerConsumption(currentPower).build(); - } - - private Map processInterfaceStatus(String response) { - String filtered = Arrays.stream(response.split("\n")) - .filter(s -> !containsPrompt(s)) - .collect(Collectors.joining("\n")); - return mapSimpleTable(filtered, showInterfaceExpected, interfaceExpected); - } - - private Map processPowerStatusInline(String response) { - Map powerMap = new HashMap<>(); - Arrays.stream(response.split("\n")) - .forEach( - line -> { - String[] lineParts = line.trim().split(":"); - if (lineParts.length > 1) { - String powerMapKey = powerInlineMap.getOrDefault(lineParts[0], null); - if (powerMapKey != null) { - powerMap.put(powerMapKey, lineParts[1].trim()); - } - } - }); - return powerMap; - } - - -} +package daq.usi.cisco; + +import daq.usi.BaseSwitchController; +import daq.usi.ResponseHandler; +import grpc.InterfaceResponse; +import grpc.LinkStatus; +import grpc.POENegotiation; +import grpc.POEStatus; +import grpc.POESupport; +import grpc.PowerResponse; +import grpc.SwitchActionResponse; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.Queue; +import java.util.stream.Collectors; + + +public class Cisco9300 extends BaseSwitchController { + + private static final String[] interfaceExpected = + {"interface", "name", "status", "vlan", "duplex", "speed", "type"}; + private static final String[] showInterfaceExpected = + {"Port", "Name", "Status", "Vlan", "Duplex", "Speed", "Type"}; + private static final Map powerInlineMap = Map.of("Interface", "dev_interface", + "Inline Power Mode", "admin", + "Operational status", "oper", + "Measured at the port", "power", + "Device Type", "device", + "IEEE Class", "dev_class", + "Power available to the device", "max"); + private static final Map poeStatusMap = Map.of("on", + POEStatus.State.ON, "off", POEStatus.State.OFF, "fault", POEStatus.State.FAULT, + "power-deny", POEStatus.State.DENY); + private static final Map poeSupportMap = Map.of("auto", + POESupport.State.ENABLED, "off", POESupport.State.DISABLED); + private static final Map poeNegotiationtMap = Map.of("auto", + POENegotiation.State.ENABLED, "off", POENegotiation.State.DISABLED); + private static final int WAIT_MS = 100; + private ResponseHandler responseHandler; + + /** + * Cisco 9300 Switch Controller. + * + * @param remoteIpAddress switch ip + * @param user switch username + * @param password switch password + */ + public Cisco9300( + String remoteIpAddress, + String user, + String password) { + this(remoteIpAddress, user, password, false); + } + + /** + * Cisco 9300 Switch Controller. + * + * @param remoteIpAddress switch ip + * @param user switch username + * @param password switch password + * @param debug for verbose output + */ + public Cisco9300( + String remoteIpAddress, + String user, + String password, boolean debug) { + super(remoteIpAddress, user, password, debug); + this.username = user == null ? "admin" : user; + this.password = password == null ? "password" : password; + commandPending = true; + } + + /** + * Generic Cisco Switch command to retrieve the Status of an interface. + */ + private String showIfaceStatusCommand(int interfacePort) { + return "show interface gigabitethernet1/0/" + interfacePort + " status"; + } + + /** + * Generic Cisco Switch command to retrieve the Power Status of an interface. Replace asterisk + * with actual port number for complete message + */ + private String showIfacePowerStatusCommand(int interfacePort) { + return "show power inline gigabitethernet1/0/" + interfacePort + " detail"; + } + + /** + * Get port toggle commands. + * + * @param interfacePort port number + * @param enabled for bringing up/down interfacePort + * @return commands + */ + private String[] portManagementCommand(int interfacePort, boolean enabled) { + return new String[] { + "configure terminal", + "interface gigabitethernet1/0/" + interfacePort, + (enabled ? "no " : "") + "shutdown", + "end" + }; + } + + /** + * Handles the process when using the enter command. Enable is a required step before commands can + * be sent to the switch. + * + * @param consoleData Raw console data received the the telnet connection. + */ + @Override + public void handleEnableMessage(String consoleData) throws Exception { + if (consoleData.contains("Password:")) { + telnetClientSocket.writeData(password + "\n"); + } else if (containsPrompt(consoleData)) { + userEnabled = true; + commandPending = false; + } else if (consoleData.contains("% Bad passwords")) { + telnetClientSocket.disposeConnection(); + throw new Exception("Could not Enable the User, Bad Password"); + } + } + + /** + * Handles the process when logging into the switch. + * + * @param consoleData Raw console data received the the telnet connection. + */ + @Override + public void handleLoginMessage(String consoleData) throws Exception { + if (consoleData.contains("Username:")) { + telnetClientSocket.writeData(username + "\n"); + } else if (consoleData.contains("Password:")) { + telnetClientSocket.writeData(password + "\n"); + } else if (consoleData.endsWith(CONSOLE_PROMPT_ENDING_LOGIN)) { + userAuthorised = true; + hostname = consoleData.split(CONSOLE_PROMPT_ENDING_LOGIN)[0]; + telnetClientSocket.writeData("enable\n"); + } else if (consoleData.contains("% Login invalid")) { + telnetClientSocket.disposeConnection(); + throw new Exception("Failed to Login, Login Invalid"); + } else if (consoleData.contains("% Bad passwords")) { + telnetClientSocket.disposeConnection(); + throw new Exception("Failed to Login, Bad Password"); + } + } + + /** + * Handles current data in the buffer read from the telnet console InputStream and sends it to the + * appropriate process. + * + * @param consoleData Current unhandled data in the buffered reader + */ + @Override + public void parseData(String consoleData) throws Exception { + if (commandPending) { + responseHandler.receiveData(consoleData); + } + } + + @Override + public void getPower(int devicePort, ResponseHandler powerResponseHandler) + throws Exception { + while (commandPending) { + Thread.sleep(WAIT_MS); + } + String command = showIfacePowerStatusCommand(devicePort); + synchronized (this) { + commandPending = true; + responseHandler = data -> { + synchronized (this) { + commandPending = false; + } + Map powerMap = processPowerStatusInline(data); + powerResponseHandler.receiveData(buildPowerResponse(powerMap)); + }; + telnetClientSocket.writeData(command + "\n"); + } + } + + @Override + public void getInterface(int devicePort, ResponseHandler handler) + throws Exception { + while (commandPending) { + Thread.sleep(WAIT_MS); + } + String command = showIfaceStatusCommand(devicePort); + synchronized (this) { + commandPending = true; + responseHandler = data -> { + synchronized (this) { + commandPending = false; + } + Map interfaceMap = processInterfaceStatus(data); + handler.receiveData(buildInterfaceResponse(interfaceMap)); + }; + telnetClientSocket.writeData(command + "\n"); + } + } + + private void managePort(int devicePort, ResponseHandler handler, + boolean enabled) throws Exception { + while (commandPending) { + Thread.sleep(WAIT_MS); + } + Queue commands = + new LinkedList<>(Arrays.asList(portManagementCommand(devicePort, enabled))); + SwitchActionResponse.Builder response = SwitchActionResponse.newBuilder(); + synchronized (this) { + commandPending = true; + responseHandler = data -> { + if (!commands.isEmpty()) { + telnetClientSocket.writeData(commands.poll() + "\n"); + return; + } + synchronized (this) { + commandPending = false; + handler.receiveData(response.setSuccess(true).build()); + } + }; + telnetClientSocket.writeData(commands.poll() + "\n"); + } + } + + @Override + public void connect(int devicePort, ResponseHandler handler) + throws Exception { + managePort(devicePort, handler, true); + } + + @Override + public void disconnect(int devicePort, ResponseHandler handler) + throws Exception { + managePort(devicePort, handler, false); + } + + private InterfaceResponse buildInterfaceResponse(Map interfaceMap) { + InterfaceResponse.Builder response = InterfaceResponse.newBuilder(); + String duplex = interfaceMap.getOrDefault("duplex", ""); + if (duplex.startsWith("a-")) { // Interface in Auto Duplex + duplex = duplex.replaceFirst("a-", ""); + } + + String speed = interfaceMap.getOrDefault("speed", ""); + if (speed.startsWith("a-")) { // Interface in Auto Speed + speed = speed.replaceFirst("a-", ""); + } + int speedNum = 0; + try { + speedNum = Integer.parseInt(speed); + } catch (NumberFormatException e) { + System.out.println("Could not parse int for interface speed: " + speed); + return response.build(); + } + + String linkStatus = interfaceMap.getOrDefault("status", ""); + return response + .setLinkStatus(linkStatus.equals("connected") ? LinkStatus.State.UP : LinkStatus.State.DOWN) + .setDuplex(duplex) + .setLinkSpeed(speedNum) + .build(); + } + + private PowerResponse buildPowerResponse(Map powerMap) { + PowerResponse.Builder response = PowerResponse.newBuilder(); + float maxPower = 0; + float currentPower = 0; + try { + maxPower = Float.parseFloat(powerMap.getOrDefault("max", "")); + currentPower = Float.parseFloat(powerMap.getOrDefault("power", "")); + } catch (NumberFormatException e) { + System.out.println( + "Could not parse float: " + powerMap.get("max") + " or " + powerMap.get("power")); + } + + String poeSupport = powerMap.getOrDefault("admin", ""); + String poeStatus = powerMap.getOrDefault("oper", ""); + return response + .setPoeStatus(poeStatusMap.getOrDefault(poeStatus, POEStatus.State.UNKNOWN)) + .setPoeSupport(poeSupportMap.getOrDefault(poeSupport, POESupport.State.UNKNOWN)) + .setPoeNegotiation( + poeNegotiationtMap.getOrDefault(poeSupport, POENegotiation.State.UNKNOWN)) + .setMaxPowerConsumption(maxPower) + .setCurrentPowerConsumption(currentPower).build(); + } + + private Map processInterfaceStatus(String response) { + String filtered = Arrays.stream(response.split("\n")) + .filter(s -> !containsPrompt(s) && !s.contains("show interface") && s.length() > 0) + .collect(Collectors.joining("\n")); + return mapSimpleTable(filtered, showInterfaceExpected, interfaceExpected); + } + + private Map processPowerStatusInline(String response) { + Map powerMap = new HashMap<>(); + Arrays.stream(response.split("\n")) + .forEach( + line -> { + String[] lineParts = line.trim().split(":"); + if (lineParts.length > 1) { + String powerMapKey = powerInlineMap.getOrDefault(lineParts[0], null); + if (powerMapKey != null) { + powerMap.put(powerMapKey, lineParts[1].trim()); + } + } + }); + return powerMap; + } + + +} diff --git a/usi/src/test/java/daq/usi/BaseSwitchControllerTest.java b/usi/src/test/java/daq/usi/BaseSwitchControllerTest.java index 97e92c6403..7fea888b3b 100644 --- a/usi/src/test/java/daq/usi/BaseSwitchControllerTest.java +++ b/usi/src/test/java/daq/usi/BaseSwitchControllerTest.java @@ -49,7 +49,7 @@ void mapSimpleTableSampleInputCisco9300() { String raw = "Port         Name               Status       Vlan       Duplex  Speed Type\n" + "Gi1/0/1                         connected    routed     a-full  a-100 10/100/1000BaseTX"; String[] colNames = {"Port", "Name", "Status", "Vlan", "Duplex", "Speed", "Type"}; - String[] mapNames = {"interface", "name", "status", "vlan", "duplex", "speed", "type"}; + String[] mapNames = {"interface", "name", "status", "vlan", "duplex", "speed", "type"}; Map expected = Map.of("interface", "Gi1/0/1", "name", "", "status", "connected", "vlan", "routed", "duplex", "a-full", "speed", "a-100", "type", "10/100/1000BaseTX"); @@ -58,4 +58,34 @@ void mapSimpleTableSampleInputCisco9300() { assertEquals(expected.get(key), response.get(key)); } } -} \ No newline at end of file + + @Test + void mapSimpleTableMissingValues() { + String raw = "Port         Name               Status       Vlan       Duplex  Speed Type\n" + + "Gi1/0/1                             routed     a-full  a-100 10/100/1000BaseTX"; + String[] colNames = {"Port", "Name", "Status", "Vlan", "Duplex", "Speed", "Type"}; + String[] mapNames = {"interface", "name", "status", "vlan", "duplex", "speed", "type"}; + Map expected = Map.of("interface", "Gi1/0/1", "name", "", "status", + "", "vlan", "routed", "duplex", "a-full", "speed", "a-100", + "type", "10/100/1000BaseTX"); + Map response = BaseSwitchController.mapSimpleTable(raw, colNames, mapNames); + for (String key : response.keySet()) { + assertEquals(expected.get(key), response.get(key)); + } + } + + @Test + void mapSimpleTableMissingValuesInFront() { + String raw = "Port         Name               Status       Vlan       Duplex  Speed Type\n" + + "                        connected routed     a-full  a-100 10/100/1000BaseTX"; + String[] colNames = {"Port", "Name", "Status", "Vlan", "Duplex", "Speed", "Type"}; + String[] mapNames = {"interface", "name", "status", "vlan", "duplex", "speed", "type"}; + Map expected = Map.of("interface", "", "name", "", "status", + "connected", "vlan", "routed", "duplex", "a-full", "speed", "a-100", + "type", "10/100/1000BaseTX"); + Map response = BaseSwitchController.mapSimpleTable(raw, colNames, mapNames); + for (String key : response.keySet()) { + assertEquals(expected.get(key), response.get(key)); + } + } +} diff --git a/usi/src/test/java/daq/usi/Cisco9300Test.java b/usi/src/test/java/daq/usi/Cisco9300Test.java new file mode 100644 index 0000000000..333e9658c6 --- /dev/null +++ b/usi/src/test/java/daq/usi/Cisco9300Test.java @@ -0,0 +1,69 @@ +package daq.usi; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import daq.usi.cisco.Cisco9300; +import grpc.InterfaceResponse; +import grpc.LinkStatus; +import grpc.POENegotiation; +import grpc.POEStatus; +import grpc.POESupport; +import grpc.PowerResponse; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class Cisco9300Test { + + private Cisco9300 at; + + @BeforeEach + void setUp() { + at = new Cisco9300(null, null, null); + at.telnetClientSocket = new FakeSwitchTelnetClientSocket(null, 0, null, false); + } + + @AfterEach + void tearDown() { + } + + private void fakeLogin() { + at.userAuthorised = true; + at.userEnabled = true; + at.commandPending = false; + } + + @Test + void testEmptyPower() throws Exception { + fakeLogin(); + at.getPower(1, new ResponseHandler() { + @Override + public void receiveData(PowerResponse data) throws Exception { + assertEquals(data.getPoeSupport(), POESupport.State.UNKNOWN); + assertEquals(data.getPoeNegotiation(), POENegotiation.State.UNKNOWN); + assertEquals(data.getPoeStatus(), POEStatus.State.UNKNOWN); + assertEquals(data.getCurrentPowerConsumption(), 0); + assertEquals(data.getMaxPowerConsumption(), 0); + } + }); + at.receiveData(""); + } + + @Test + void testSampleInterfaceResponse() throws Exception { + final String output = "show interface gigabitethernet1/0/2 status\n\n\n" + + "Port Name Status Vlan Duplex Speed Type\n" + + "Gi1/0/4 connected trunk a-full a-100 10/100/1000BaseTX\n" + + "daq#\n"; + fakeLogin(); + at.getInterface(1, new ResponseHandler() { + @Override + public void receiveData(InterfaceResponse data) throws Exception { + assertEquals(data.getDuplex(), "full"); + assertEquals(data.getLinkSpeed(), 100); + assertEquals(data.getLinkStatus(), LinkStatus.State.UP); + } + }); + at.receiveData(output); + } +} From 9ce0f14c1ba3fcbcc320fe759a6129a8b75778da Mon Sep 17 00:00:00 2001 From: jhughesbiot <50999916+jhughesbiot@users.noreply.github.com> Date: Fri, 4 Sep 2020 10:51:03 -0700 Subject: [PATCH 121/212] Switch poe updates (#605) Alignment of PoE test to test plan. --- docs/device_report.md | 28 +++-------------- subset/switches/module_manifest.json | 9 ++---- subset/switches/readme.md | 9 ------ .../src/main/java/switchtest/SwitchTest.java | 30 +++++-------------- subset/switches/test_switch | 18 ++--------- 5 files changed, 16 insertions(+), 78 deletions(-) diff --git a/docs/device_report.md b/docs/device_report.md index 2ea1fb5032..a461268da2 100644 --- a/docs/device_report.md +++ b/docs/device_report.md @@ -56,7 +56,7 @@ Overall device result FAIL |---|---|---|---|---|---| |Required|1|0|0|0|0| |Recommended|1|0|0|0|1| -|Other|6|2|22|1|2| +|Other|6|2|20|1|2| |Result|Test|Category|Expectation|Notes| |---|---|---|---|---| @@ -75,9 +75,7 @@ Overall device result FAIL |skip|connection.port_link|Other|Other|No local IP has been set, check system config| |skip|connection.port_speed|Other|Other|No local IP has been set, check system config| |pass|manual.test.name|Security|Recommended|Manual test - for testing| -|skip|poe.negotiation|Other|Other|No local IP has been set, check system config| -|skip|poe.power|Other|Other|No local IP has been set, check system config| -|skip|poe.support|Other|Other|No local IP has been set, check system config| +|skip|poe.switch.power|Other|Other|No local IP has been set, check system config| |fail|protocol.bacnet.pic|Other|Other|PICS file defined however a BACnet device was not found.| |skip|protocol.bacnet.version|Other|Other|Bacnet device not found.| |skip|security.firmware|Other|Other|Could not retrieve a firmware version with nmap. Check bacnet port.| @@ -251,31 +249,13 @@ LOCAL_IP not configured, assuming no network switch. RESULT skip connection.port_duplex No local IP has been set, check system config -------------------- -poe.power +poe.switch.power -------------------- Verify that the device draws less than the maximum power allocated by the port. This is 15.4W for 802.3af and 30W for 802.3at -------------------- LOCAL_IP not configured, assuming no network switch. -------------------- -RESULT skip poe.power No local IP has been set, check system config - --------------------- -poe.negotiation --------------------- -Verify the device autonegotiates power requirements --------------------- -LOCAL_IP not configured, assuming no network switch. --------------------- -RESULT skip poe.negotiation No local IP has been set, check system config - --------------------- -poe.support --------------------- -Verify if the device supports PoE --------------------- -LOCAL_IP not configured, assuming no network switch. --------------------- -RESULT skip poe.support No local IP has been set, check system config +RESULT skip poe.switch.power No local IP has been set, check system config ``` diff --git a/subset/switches/module_manifest.json b/subset/switches/module_manifest.json index 25fe268a28..2794ab49e1 100644 --- a/subset/switches/module_manifest.json +++ b/subset/switches/module_manifest.json @@ -8,13 +8,8 @@ "connection.port_duplex" : { "description" : "Verify the device supports full duplex" }, - "poe.power" : { + "poe.switch.power" : { "description" : "Verify that the device draws less than the maximum power allocated by the port. This is 15.4W for 802.3af and 30W for 802.3at" - }, - "poe.negotiation" : { - "description" : "Verify the device autonegotiates power requirements" - }, - "poe.support" : { - "description" : "Verify if the device supports PoE" } } + diff --git a/subset/switches/readme.md b/subset/switches/readme.md index b2e970aee1..af54891a89 100644 --- a/subset/switches/readme.md +++ b/subset/switches/readme.md @@ -85,17 +85,8 @@ Example of all necessary parameters in the system.conf related to physical switc - pass -> If the speed of the port is auto-negotiated and determiend to be higher than 10 MBPS - fail ->If the speed of the port is determined to be <= 10MBPS -## Conditions for poe.negotiation - - pass -> If the PoE is able to be auto-negotiated with the device and PoE is enabled for the device. - - fail ->If the PoE fails to be auto-negotiated with the device and is enabled for the device. This can also fail if associated power data fails to resolve correctly during switch interrogation. - - skip -> If the PoE option is disabled in the device module_config.json or if the switch reports no PoE support. - ## Conditions for poe.power - pass -> If the a PoE device is connected and power has been detected and supplied to the device. - fail -> If the a PoE device is connected and *NO* power has been detected and supplied to the device. Failure also occurs if the switch reports either a faulty PoE state or is denying power to the device. This can also fail if associated power data fails to resolve correctly during switch interrogation. - skip -> If the PoE option is disabled in the device module_config.json or if the switch reports no PoE support. - ## Conditions for poe.support - - pass -> If the port the device is connected to supports PoE and it is enabled on that port. - - fail -> If the a PoE device is connected to does not support PoE or it is disabled on that port. - - skip -> If the PoE option is disabled in the device module_config.json or if the switch reports no PoE support. diff --git a/subset/switches/src/main/java/switchtest/SwitchTest.java b/subset/switches/src/main/java/switchtest/SwitchTest.java index 16dd960fca..991027026f 100644 --- a/subset/switches/src/main/java/switchtest/SwitchTest.java +++ b/subset/switches/src/main/java/switchtest/SwitchTest.java @@ -92,9 +92,7 @@ protected void testDuplex(InterfaceResponse interfaceResponse) { protected void testPower(PowerResponse powerResponse) { if (!deviceConfigPoeEnabled) { - captureResult("poe.power", Result.SKIP, "This test is disabled"); - captureResult("poe.negotiation", Result.SKIP, "This test is disabled"); - captureResult("poe.support", Result.SKIP, "This test is disabled"); + captureResult("poe.switch.power", Result.SKIP, "This test is disabled"); return; } @@ -102,35 +100,20 @@ protected void testPower(PowerResponse powerResponse) { // Determine PoE power test result if (poeStatus == POEStatus.State.ON) { if (powerResponse.getMaxPowerConsumption() >= powerResponse.getCurrentPowerConsumption()) { - captureResult("poe.power", Result.PASS, "PoE is applied to device"); + captureResult("poe.switch.power", Result.PASS, "PoE is applied to device"); } else { - captureResult("poe.power", Result.FAIL, "device wattage exceeds the max wattage"); + captureResult("poe.switch.power", Result.FAIL, "device wattage exceeds the max wattage"); } } else if (poeStatus == POEStatus.State.OFF) { - captureResult("poe.power", Result.FAIL, "No poE is applied"); + captureResult("poe.switch.power", Result.FAIL, "No PoE is applied"); } else if (poeStatus == POEStatus.State.FAULT) { - captureResult("poe.power", Result.FAIL, + captureResult("poe.switch.power", Result.FAIL, "Device detection or a powered device is in a faulty state"); } else { - captureResult("poe.power", Result.FAIL, "A powered device is detected, " + captureResult("poe.switch.power", Result.FAIL, "A powered device is detected, " + "but no PoE is available, or the maximum wattage exceeds the " + "detected powered-device maximum."); } - - // Determine PoE auto negotiation result - if (powerResponse.getPoeNegotiation() == POENegotiation.State.ENABLED) { - captureResult("poe.negotiation", Result.PASS, "PoE auto-negotiated successfully"); - } else { - captureResult("poe.negotiation", Result.FAIL, "Incorrect privilege for negotiation"); - } - - // Determine PoE support result - if (powerResponse.getPoeSupport() == POESupport.State.ENABLED) { - captureResult("poe.support", Result.PASS, "PoE is supported and enabled"); - } else { - captureResult("poe.support", Result.FAIL, - "The switch does not support PoE or it is disabled"); - } } protected void writeReport() { @@ -169,3 +152,4 @@ public void test(SwitchInfo switchInfo) { writeReport(); } } + diff --git a/subset/switches/test_switch b/subset/switches/test_switch index d3ed57350c..e20ff5728b 100755 --- a/subset/switches/test_switch +++ b/subset/switches/test_switch @@ -63,21 +63,9 @@ else "RESULT $RESULT connection.port_duplex $SUMMARY" write_out_result $REPORT \ - "poe.power" \ - "$(jq -r '.["poe.power"].description' $MANIFEST)" \ + "poe.switch.power" \ + "$(jq -r '.["poe.switch.power"].description' $MANIFEST)" \ "$SKIP_REASON" \ - "RESULT $RESULT poe.power $SUMMARY" - - write_out_result $REPORT \ - "poe.negotiation" \ - "$(jq -r '.["poe.negotiation"].description' $MANIFEST)" \ - "$SKIP_REASON" \ - "RESULT $RESULT poe.negotiation $SUMMARY" - - write_out_result $REPORT \ - "poe.support" \ - "$(jq -r '.["poe.support"].description' $MANIFEST)" \ - "$SKIP_REASON" \ - "RESULT $RESULT poe.support $SUMMARY" + "RESULT $RESULT poe.switch.power $SUMMARY" fi From d6d442ab82ed9e96781ef83ff148f57e82236b03 Mon Sep 17 00:00:00 2001 From: Haoli Du Date: Tue, 8 Sep 2020 16:18:15 +0000 Subject: [PATCH 122/212] 1.9.6 release --- docs/changelog.md | 4 ++++ etc/docker_images.txt | 54 +++++++++++++++++++++---------------------- etc/docker_images.ver | 2 +- 3 files changed, 31 insertions(+), 29 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index bedd5c2366..c89e4488db 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,4 +1,8 @@ # Changelog +* 1.9.6 + * Switch poe updates (#605) - Alignment of PoE test to test plan. + * Cisco Switches parsing fix (#623) + * usi logs gcp and local capture (#613) * 1.9.5 * Increase nmap module timeout (#611) * Improvements for test development debugging (#609) diff --git a/etc/docker_images.txt b/etc/docker_images.txt index f8a184f0ab..588b6828a6 100644 --- a/etc/docker_images.txt +++ b/etc/docker_images.txt @@ -1,28 +1,26 @@ -daqf/aardvark 6fb0f6c52222 -daqf/default f8652a12fdd8 -daqf/faucet 1ec12d632685 -daqf/faux1 3d8f075bf6de -daqf/faux2 58b756b90505 -daqf/gauge ace0ffe33b8f -daqf/networking 4f25f942b538 -daqf/switch b2113d0aa5d9 -daqf/test_bacext daa0a06c718e -daqf/test_bacnet 6a3c93c4decc -daqf/test_brute aa76b01d5eed -daqf/test_discover 0ca76d766349 -daqf/test_fail 8ef4103069a5 -daqf/test_hold 5c923cd1a464 -daqf/test_macoui a605473e0f8d -daqf/test_manual 8026fdd99a5b -daqf/test_mudgee 189aa0b635fd -daqf/test_network 557df3ae19f9 -daqf/test_nmap 8ceb63e71c79 -daqf/test_ntp a5b21e0039e6 -daqf/test_pass 62dd10381336 -daqf/test_password d318555d2d3e -daqf/test_ping fe8e4dd5ddc2 -daqf/test_ssh 054efbf1b3c3 -daqf/test_switch e5bb16e85362 -daqf/test_tls 17de1ebf13ce -daqf/test_udmi b6d5381f32f0 -daqf/usi 348d54ddbb7c +daqf/aardvark 59b11e4809cf +daqf/default 784a86bc573f +daqf/faucet dca9d4fa2d90 +daqf/faux1 7962ab064630 +daqf/faux2 0a83fd163f62 +daqf/gauge d5724dd3c0a1 +daqf/networking c5de092a7471 +daqf/switch 225dc0542c1c +daqf/test_bacext e252d1b60c9e +daqf/test_bacnet 62522aca2f39 +daqf/test_brute 7700dcc75d0e +daqf/test_discover 1317ab4bdb67 +daqf/test_fail 289a7f90d24d +daqf/test_hold c3661ceeeff9 +daqf/test_manual c1a5eba7e164 +daqf/test_mudgee ac8f82de77c5 +daqf/test_network 30fd818cef6b +daqf/test_nmap 132eb91672c1 +daqf/test_pass 6dd331d8ca3f +daqf/test_password ba91ccab59b2 +daqf/test_ping 5cd777ab4180 +daqf/test_ssh 49b8200b3ffa +daqf/test_switch b47518a8e1d8 +daqf/test_tls fd4a5ffd4372 +daqf/test_udmi 4af41d1276d8 +daqf/usi d70f829f1050 diff --git a/etc/docker_images.ver b/etc/docker_images.ver index 158c747293..7bc1c40470 100644 --- a/etc/docker_images.ver +++ b/etc/docker_images.ver @@ -1 +1 @@ -1.9.5 +1.9.6 From 773434252f3f586fdc3eda8a8001febb9d8a4e52 Mon Sep 17 00:00:00 2001 From: henry54809 Date: Wed, 9 Sep 2020 10:18:54 -0700 Subject: [PATCH 123/212] Adding timestamps to ipaddr test log messages. (#627) --- daq/ipaddr_test.py | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/daq/ipaddr_test.py b/daq/ipaddr_test.py index f701404d90..ce03ff059f 100644 --- a/daq/ipaddr_test.py +++ b/daq/ipaddr_test.py @@ -1,16 +1,16 @@ """Test module encapsulating ip-address tests (including DHCP)""" from __future__ import absolute_import +import logging + import time import os import copy import logger - from base_module import HostModule -LOGGER = logger.get_logger('ipaddr') - +_LOG_FORMAT = "%(asctime)s %(levelname)-7s %(message)s" class IpAddrTest(HostModule): """Module for inline ipaddr tests""" @@ -18,8 +18,6 @@ class IpAddrTest(HostModule): def __init__(self, host, tmpdir, test_name, module_config): super().__init__(host, tmpdir, test_name, module_config) self.test_dhcp_ranges = copy.copy(self.test_config.get('dhcp_ranges', [])) - self.log_path = os.path.join(self.tmpdir, 'nodes', self.host_name, 'activate.log') - self.log_file = None self._ip_callback = None self.tests = [ ('dhcp port_toggle test', self._dhcp_port_toggle_test), @@ -27,28 +25,30 @@ def __init__(self, host, tmpdir, test_name, module_config): ('ip change test', self._ip_change_test), ('finalize', self._finalize) ] + self._logger = logger.get_logger('ipaddr_%s' % self.host_name) + log_folder = os.path.join(self.tmpdir, 'nodes', self.host_name) + os.makedirs(log_folder) + log_path = os.path.join(log_folder, 'activate.log') + self._file_handler = logging.FileHandler(log_path) + formatter = logging.Formatter(_LOG_FORMAT) + self._file_handler.setFormatter(formatter) + self._logger.addHandler(self._file_handler) def start(self, port, params, callback, finish_hook): """Start the ip-addr tests""" super().start(port, params, callback, finish_hook) - LOGGER.debug('Target device %s starting ipaddr test %s', self.device, self.test_name) - self.log_file = open(self.log_path, 'w') + self._logger.debug('Target device %s starting ipaddr test %s', self.device, self.test_name) self._next_test() def _next_test(self): try: name, func = self.tests.pop(0) - self.log('Running ' + name) + self._logger.info('Running ' + name) func() except Exception as e: - self.log(str(e)) + self._logger.error(str(e)) self._finalize(exception=e) - def log(self, message): - """Log an activation message""" - LOGGER.info(message) - self.log_file.write(message + '\n') - def _dhcp_port_toggle_test(self): if not self.host.connect_port(False): self.log('disconnect port not enabled') @@ -62,7 +62,7 @@ def _multi_subnet_test(self): self._next_test() return dhcp_range = self.test_dhcp_ranges.pop(0) - self.log('Testing dhcp range: ' + str(dhcp_range)) + self._logger.info('Testing dhcp range: ' + str(dhcp_range)) args = (dhcp_range["start"], dhcp_range["end"], dhcp_range["prefix_length"]) self.host.gateway.change_dhcp_range(*args) self._ip_callback = self._multi_subnet_test if self.test_dhcp_ranges else self._next_test @@ -77,12 +77,11 @@ def _finalize(self, exception=None): def terminate(self): """Terminate this set of tests""" - self.log('Module terminating') - self.log_file.close() - self.log_file = None + self._logger.info('Module terminating') + self._file_handler.close() def ip_listener(self, target_ip): """Respond to a ip notification event""" - self.log('ip notification %s' % target_ip) + self._logger.info('ip notification %s' % target_ip) if self._ip_callback: self._ip_callback() From 8588cbb2524590278db004693fbc993c2956bdaa Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 10 Sep 2020 08:20:46 -0700 Subject: [PATCH 124/212] Update dependency jsoneditor to v9.0.5 (#628) --- firebase/public/config.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firebase/public/config.html b/firebase/public/config.html index 438013214b..6298a6af4e 100644 --- a/firebase/public/config.html +++ b/firebase/public/config.html @@ -11,8 +11,8 @@ - - + +
      From 90badf2c6e5180bd8367f1c01b8ecef3e8cecc75 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 10 Sep 2020 08:21:16 -0700 Subject: [PATCH 125/212] Update dependency io.grpc:grpc-netty-shaded to v1.32.1 (#629) --- subset/switches/pom.xml | 2 +- usi/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subset/switches/pom.xml b/subset/switches/pom.xml index 93ac0b31ee..117215001f 100644 --- a/subset/switches/pom.xml +++ b/subset/switches/pom.xml @@ -38,7 +38,7 @@ io.grpc grpc-netty-shaded - 1.31.0 + 1.32.1 io.grpc diff --git a/usi/pom.xml b/usi/pom.xml index 0b3ff43238..6f92029831 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -38,7 +38,7 @@ io.grpc grpc-netty-shaded - 1.31.1 + 1.32.1 io.grpc From 44fb11bda550abd7de2bef1ec0598bff5446c2c8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 10 Sep 2020 08:21:47 -0700 Subject: [PATCH 126/212] Update dependency io.grpc:grpc-stub to v1.32.1 (#632) --- subset/switches/pom.xml | 2 +- usi/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subset/switches/pom.xml b/subset/switches/pom.xml index 117215001f..99d83c9ae3 100644 --- a/subset/switches/pom.xml +++ b/subset/switches/pom.xml @@ -48,7 +48,7 @@ io.grpc grpc-stub - 1.31.0 + 1.32.1 org.apache.tomcat diff --git a/usi/pom.xml b/usi/pom.xml index 6f92029831..d4e143122f 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -48,7 +48,7 @@ io.grpc grpc-stub - 1.31.1 + 1.32.1 org.apache.tomcat From 70ce553219bb6430e120070a8ff2c3749ce163e3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 10 Sep 2020 08:22:18 -0700 Subject: [PATCH 127/212] Update dependency io.grpc:grpc-bom to v1.32.1 (#631) --- subset/switches/pom.xml | 2 +- usi/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subset/switches/pom.xml b/subset/switches/pom.xml index 99d83c9ae3..b3ca5c00b2 100644 --- a/subset/switches/pom.xml +++ b/subset/switches/pom.xml @@ -16,7 +16,7 @@ io.grpc grpc-bom - 1.31.0 + 1.32.1 pom import diff --git a/usi/pom.xml b/usi/pom.xml index d4e143122f..4aabe94db9 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -16,7 +16,7 @@ io.grpc grpc-bom - 1.31.1 + 1.32.1 pom import From 11fc06d780415a38baf2c81db7d8b2fd953b375a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 10 Sep 2020 08:23:13 -0700 Subject: [PATCH 128/212] Update dependency io.grpc:grpc-protobuf to v1.32.1 (#630) --- subset/switches/pom.xml | 2 +- usi/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subset/switches/pom.xml b/subset/switches/pom.xml index b3ca5c00b2..963ae2db30 100644 --- a/subset/switches/pom.xml +++ b/subset/switches/pom.xml @@ -43,7 +43,7 @@ io.grpc grpc-protobuf - 1.31.0 + 1.32.1 io.grpc diff --git a/usi/pom.xml b/usi/pom.xml index 4aabe94db9..386c132c39 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -43,7 +43,7 @@ io.grpc grpc-protobuf - 1.31.1 + 1.32.1 io.grpc From 23449a7c1944d867ae6c113a371cb2f7c084a1d6 Mon Sep 17 00:00:00 2001 From: henry54809 Date: Fri, 11 Sep 2020 11:16:06 -0700 Subject: [PATCH 129/212] Merging ipaddr and dhcp (#634) With dummy dhcp module to be replaced by other DHCP PRs(#580 #579 ). --- config/modules/host.conf | 2 +- daq/base_module.py | 4 +++ daq/ipaddr_test.py | 26 ++++++++++++---- subset/ipaddr/Dockerfile.test_ipaddr | 8 +++++ subset/ipaddr/build.conf | 2 ++ subset/ipaddr/dhcp_tests.py | 45 ++++++++++++++++++++++++++++ subset/ipaddr/test_dhcp | 7 +++++ testing/test_dhcp.sh | 6 ++-- testing/test_many.sh | 6 ++-- 9 files changed, 93 insertions(+), 13 deletions(-) create mode 100644 subset/ipaddr/Dockerfile.test_ipaddr create mode 100644 subset/ipaddr/build.conf create mode 100644 subset/ipaddr/dhcp_tests.py create mode 100755 subset/ipaddr/test_dhcp diff --git a/config/modules/host.conf b/config/modules/host.conf index cd9e9421b4..00e934780a 100644 --- a/config/modules/host.conf +++ b/config/modules/host.conf @@ -15,7 +15,7 @@ include subset/pentests/build.conf include usi/build.conf # Extended dhcp tests -add ipaddr +include subset/ipaddr/build.conf # Example of how to remove something. remove unused diff --git a/daq/base_module.py b/daq/base_module.py index f8062e4dd8..fcc5232320 100644 --- a/daq/base_module.py +++ b/daq/base_module.py @@ -25,11 +25,15 @@ def __init__(self, host, tmpdir, test_name, module_config): assert len(self.host_name) <= 10, 'Hostname %s too long' self.callback = None self._finish_hook = None + self.port = None + self.params = None self.start_time = None def start(self, port, params, callback, finish_hook): """Start a test module""" LOGGER.debug('Starting test module %s', self) + self.port = port + self.params = params self.callback = callback self._finish_hook = finish_hook self.start_time = datetime.datetime.now() diff --git a/daq/ipaddr_test.py b/daq/ipaddr_test.py index ce03ff059f..76327441a2 100644 --- a/daq/ipaddr_test.py +++ b/daq/ipaddr_test.py @@ -7,6 +7,7 @@ import os import copy import logger +import docker_test from base_module import HostModule @@ -17,22 +18,24 @@ class IpAddrTest(HostModule): def __init__(self, host, tmpdir, test_name, module_config): super().__init__(host, tmpdir, test_name, module_config) + self.docker_host = docker_test.DockerTest(host, tmpdir, test_name, module_config) self.test_dhcp_ranges = copy.copy(self.test_config.get('dhcp_ranges', [])) self._ip_callback = None self.tests = [ ('dhcp port_toggle test', self._dhcp_port_toggle_test), ('dhcp multi subnet test', self._multi_subnet_test), ('ip change test', self._ip_change_test), - ('finalize', self._finalize) + ('analyze results', self._analyze) ] self._logger = logger.get_logger('ipaddr_%s' % self.host_name) - log_folder = os.path.join(self.tmpdir, 'nodes', self.host_name) + log_folder = os.path.join(self.tmpdir, 'nodes', self.host_name, 'tmp') os.makedirs(log_folder) log_path = os.path.join(log_folder, 'activate.log') self._file_handler = logging.FileHandler(log_path) formatter = logging.Formatter(_LOG_FORMAT) self._file_handler.setFormatter(formatter) self._logger.addHandler(self._file_handler) + self._force_terminated = False def start(self, port, params, callback, finish_hook): """Start the ip-addr tests""" @@ -71,14 +74,25 @@ def _ip_change_test(self): self.host.gateway.request_new_ip(self.host.target_mac) self._ip_callback = self._next_test - def _finalize(self, exception=None): - self.terminate() - self.callback(exception=exception) + def _analyze(self): + self._ip_callback = None + self.docker_host.start(self.port, self.params, + self._finalize, self._finish_hook) + + def _finalize(self, return_code=None, exception=None): + self._logger.info('Module finalizing') + self._ip_callback = None + self._file_handler.close() + if not self._force_terminated: + self.callback(return_code=None, exception=exception) def terminate(self): """Terminate this set of tests""" self._logger.info('Module terminating') - self._file_handler.close() + self._force_terminated = True + if self.docker_host.start_time: + self.docker_host.terminate() + self._finalize() def ip_listener(self, target_ip): """Respond to a ip notification event""" diff --git a/subset/ipaddr/Dockerfile.test_ipaddr b/subset/ipaddr/Dockerfile.test_ipaddr new file mode 100644 index 0000000000..8c0efd6620 --- /dev/null +++ b/subset/ipaddr/Dockerfile.test_ipaddr @@ -0,0 +1,8 @@ +FROM daqf/aardvark:latest + +RUN $AG update && $AG install python python-setuptools python-pip netcat + +COPY subset/ipaddr/dhcp_tests.py . +COPY subset/ipaddr/test_dhcp . + +CMD ["./test_dhcp"] diff --git a/subset/ipaddr/build.conf b/subset/ipaddr/build.conf new file mode 100644 index 0000000000..42b759fff5 --- /dev/null +++ b/subset/ipaddr/build.conf @@ -0,0 +1,2 @@ +build subset/ipaddr +add ipaddr diff --git a/subset/ipaddr/dhcp_tests.py b/subset/ipaddr/dhcp_tests.py new file mode 100644 index 0000000000..50102f9824 --- /dev/null +++ b/subset/ipaddr/dhcp_tests.py @@ -0,0 +1,45 @@ +"""Dummy ipaddr accompanying docker module""" + +from __future__ import absolute_import +import sys + +TEST_REQUEST = str(sys.argv[1]) + + +def main(): + """main""" + ipaddr_log = '/tmp/activate.log' + report_filename = 'report.txt' + dash_break_line = '--------------------\n' + description_dhcp_short = 'Reconnect device and check for DHCP request.' + description_dhcp_long = 'Wait for lease expiry and check for DHCP request.' + result = None + + def _write_report(string_to_append): + with open(report_filename, 'a+') as file_open: + file_open.write(string_to_append) + + def _test_dhcp_short(): + return 'fail' + + def _test_dhcp_long(): + return 'fail' + + _write_report("{b}{t}\n{b}".format(b=dash_break_line, t=TEST_REQUEST)) + summary = "" + with open(ipaddr_log, 'r') as fd: + summary = fd.read() + if TEST_REQUEST == 'connection.network.dhcp_short': + _write_report("{d}\n{b} \n {s}".format(b=dash_break_line, d=description_dhcp_short, + s=summary)) + result = _test_dhcp_short() + + elif TEST_REQUEST == 'connection.network.dhcp_long': + _write_report("{d}\n{b}".format(b=dash_break_line, d=description_dhcp_long)) + result = _test_dhcp_long() + + _write_report("RESULT {r} {t} \n".format(r=result, t=TEST_REQUEST)) + + +if __name__ == "__main__": + main() diff --git a/subset/ipaddr/test_dhcp b/subset/ipaddr/test_dhcp new file mode 100755 index 0000000000..2f16fbb3bd --- /dev/null +++ b/subset/ipaddr/test_dhcp @@ -0,0 +1,7 @@ +#!/bin/bash -e +source reporting.sh +REPORT=/tmp/report.txt + +python dhcp_tests.py connection.network.dhcp_short + +cat report.txt >> $REPORT diff --git a/testing/test_dhcp.sh b/testing/test_dhcp.sh index 30f15ec103..5fd721546c 100755 --- a/testing/test_dhcp.sh +++ b/testing/test_dhcp.sh @@ -80,9 +80,9 @@ for iface in $(seq 1 5); do echo "Device $iface num of ips: $num_ips" | tee -a $TEST_RESULTS elif [ $iface == 4 ]; then echo "Device $iface ip triggers: $(((ip_triggers + long_triggers) >= 4))" | tee -a $TEST_RESULTS - subnet_ip=$(fgrep "ip notification 192.168" inst/run-*/nodes/ipaddr*/activate.log | wc -l) - subnet2_ip=$(fgrep "ip notification 10.255.255" inst/run-*/nodes/ipaddr*/activate.log | wc -l) - subnet3_ip=$(fgrep "ip notification 172.16.0" inst/run-*/nodes/ipaddr*/activate.log | wc -l) + subnet_ip=$(fgrep "ip notification 192.168" inst/run-*/nodes/ipaddr*/tmp/activate.log | wc -l) + subnet2_ip=$(fgrep "ip notification 10.255.255" inst/run-*/nodes/ipaddr*/tmp/activate.log | wc -l) + subnet3_ip=$(fgrep "ip notification 172.16.0" inst/run-*/nodes/ipaddr*/tmp/activate.log | wc -l) echo "Device $iface subnet 1 ip: $subnet_ip subnet 2 ip: $subnet2_ip subnet 3 ip: $subnet3_ip" | tee -a $TEST_RESULTS elif [ $iface == 3 ]; then echo "Device $iface long ip triggers: $((long_triggers > 0))" | tee -a $TEST_RESULTS diff --git a/testing/test_many.sh b/testing/test_many.sh index e0699857e1..0d27fc1821 100755 --- a/testing/test_many.sh +++ b/testing/test_many.sh @@ -86,8 +86,8 @@ cat inst/result.log results=$(fgrep [] inst/result.log | wc -l) timeouts=$(fgrep "ipaddr:TimeoutError" inst/result.log | wc -l) ipaddr_timeouts=$(fgrep "ipaddr:TimeoutError" inst/result.log | wc -l) -ip_notifications=$(fgrep "ip notification" inst/run-*/nodes/ipaddr*/activate.log | wc -l) -alternate_subnet_ip=$(fgrep "ip notification 192.168" inst/run-*/nodes/ipaddr*/activate.log | wc -l) +ip_notifications=$(fgrep "ip notification" inst/run-*/nodes/ipaddr*/tmp/activate.log | wc -l) +alternate_subnet_ip=$(fgrep "ip notification 192.168" inst/run-*/nodes/ipaddr*/tmp/activate.log | wc -l) cat inst/run-*/scans/ip_triggers.txt static_ips=$(fgrep nope inst/run-*/scans/ip_triggers.txt | wc -l) @@ -95,7 +95,7 @@ ntp_traffic=$(fgrep "RESULT fail base.startup.ntp" inst/run-*/nodes/ping*/tmp/re dns_traffic=$(fgrep "RESULT fail base.startup.dns" inst/run-*/nodes/ping*/tmp/result_lines.txt | wc -l) more inst/run-*/nodes/ping*/activate.log | cat -more inst/run-*/nodes/ipaddr*/activate.log | cat +more inst/run-*/nodes/ipaddr*/tmp/activate.log | cat echo Found $results clean runs, $timeouts timeouts, and $static_ips static_ips. echo ipaddr had $ip_notifications notifications and $ipaddr_timeouts timeouts. From 5538aff23111836c055942cc2e652de0d9f73b58 Mon Sep 17 00:00:00 2001 From: henry54809 Date: Fri, 11 Sep 2020 12:07:34 -0700 Subject: [PATCH 130/212] add raw output from usi. (#636) --- .../src/main/java/switchtest/SwitchTest.java | 2 ++ .../java/daq/usi/allied/AlliedTelesisX230.java | 14 ++++++++++---- usi/src/main/java/daq/usi/cisco/Cisco9300.java | 14 ++++++++++---- usi/src/main/proto/usi.proto | 2 ++ 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/subset/switches/src/main/java/switchtest/SwitchTest.java b/subset/switches/src/main/java/switchtest/SwitchTest.java index 991027026f..79597081c3 100644 --- a/subset/switches/src/main/java/switchtest/SwitchTest.java +++ b/subset/switches/src/main/java/switchtest/SwitchTest.java @@ -145,6 +145,8 @@ public void test(SwitchInfo switchInfo) { .withDeadlineAfter(rpcTimeoutSec, TimeUnit.SECONDS).getPower(switchInfo); final InterfaceResponse interfaceResponse = blockingStub .withDeadlineAfter(rpcTimeoutSec, TimeUnit.SECONDS).getInterface(switchInfo); + results.add(interfaceResponse.getRawOutput()); + results.add(powerResponse.getRawOutput()); testLink(interfaceResponse); testSpeed(interfaceResponse); testDuplex(interfaceResponse); diff --git a/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java b/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java index affc02d2da..e0ec44a0df 100644 --- a/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java +++ b/usi/src/main/java/daq/usi/allied/AlliedTelesisX230.java @@ -124,7 +124,7 @@ public void getPower(int devicePort, ResponseHandler handler) thr commandPending = false; } Map powerMap = processPowerStatusInline(data); - handler.receiveData(buildPowerResponse(powerMap)); + handler.receiveData(buildPowerResponse(powerMap, data)); }; telnetClientSocket.writeData(command + "\n"); } @@ -144,7 +144,7 @@ public void getInterface(int devicePort, ResponseHandler hand commandPending = false; } Map interfaceMap = processInterfaceStatus(data); - handler.receiveData(buildInterfaceResponse(interfaceMap)); + handler.receiveData(buildInterfaceResponse(interfaceMap, data)); }; telnetClientSocket.writeData(command + "\n"); } @@ -186,8 +186,11 @@ public void disconnect(int devicePort, ResponseHandler han managePort(devicePort, handler, false); } - private InterfaceResponse buildInterfaceResponse(Map interfaceMap) { + private InterfaceResponse buildInterfaceResponse(Map interfaceMap, String raw) { InterfaceResponse.Builder response = InterfaceResponse.newBuilder(); + if (raw != null) { + response.setRawOutput(raw); + } String duplex = interfaceMap.getOrDefault("duplex", ""); int speed = 0; try { @@ -204,8 +207,11 @@ private InterfaceResponse buildInterfaceResponse(Map interfaceMa .build(); } - private PowerResponse buildPowerResponse(Map powerMap) { + private PowerResponse buildPowerResponse(Map powerMap, String raw) { PowerResponse.Builder response = PowerResponse.newBuilder(); + if (raw != null) { + response.setRawOutput(raw); + } float maxPower = 0; float currentPower = 0; try { diff --git a/usi/src/main/java/daq/usi/cisco/Cisco9300.java b/usi/src/main/java/daq/usi/cisco/Cisco9300.java index 20142c6e7a..f37e475bd9 100644 --- a/usi/src/main/java/daq/usi/cisco/Cisco9300.java +++ b/usi/src/main/java/daq/usi/cisco/Cisco9300.java @@ -173,7 +173,7 @@ public void getPower(int devicePort, ResponseHandler powerRespons commandPending = false; } Map powerMap = processPowerStatusInline(data); - powerResponseHandler.receiveData(buildPowerResponse(powerMap)); + powerResponseHandler.receiveData(buildPowerResponse(powerMap, data)); }; telnetClientSocket.writeData(command + "\n"); } @@ -193,7 +193,7 @@ public void getInterface(int devicePort, ResponseHandler hand commandPending = false; } Map interfaceMap = processInterfaceStatus(data); - handler.receiveData(buildInterfaceResponse(interfaceMap)); + handler.receiveData(buildInterfaceResponse(interfaceMap, data)); }; telnetClientSocket.writeData(command + "\n"); } @@ -235,8 +235,11 @@ public void disconnect(int devicePort, ResponseHandler han managePort(devicePort, handler, false); } - private InterfaceResponse buildInterfaceResponse(Map interfaceMap) { + private InterfaceResponse buildInterfaceResponse(Map interfaceMap, String raw) { InterfaceResponse.Builder response = InterfaceResponse.newBuilder(); + if (raw != null) { + response.setRawOutput(raw); + } String duplex = interfaceMap.getOrDefault("duplex", ""); if (duplex.startsWith("a-")) { // Interface in Auto Duplex duplex = duplex.replaceFirst("a-", ""); @@ -262,8 +265,11 @@ private InterfaceResponse buildInterfaceResponse(Map interfaceMa .build(); } - private PowerResponse buildPowerResponse(Map powerMap) { + private PowerResponse buildPowerResponse(Map powerMap, String raw) { PowerResponse.Builder response = PowerResponse.newBuilder(); + if (raw != null) { + response.setRawOutput(raw); + } float maxPower = 0; float currentPower = 0; try { diff --git a/usi/src/main/proto/usi.proto b/usi/src/main/proto/usi.proto index 156df5eaca..a09ead0f9c 100644 --- a/usi/src/main/proto/usi.proto +++ b/usi/src/main/proto/usi.proto @@ -25,12 +25,14 @@ message PowerResponse { POESupport.State poe_support = 3; POEStatus.State poe_status = 4; POENegotiation.State poe_negotiation = 5; + string raw_output = 6; } message InterfaceResponse { LinkStatus.State link_status = 1; int32 link_speed = 2; string duplex = 3; + string raw_output = 4; } enum SwitchModel { From c2b5350488c23158e48723177952b5bbab91deeb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 11 Sep 2020 22:43:05 -0700 Subject: [PATCH 131/212] Bump node-fetch from 2.6.0 to 2.6.1 in /firebase/functions (#635) --- firebase/functions/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/firebase/functions/package-lock.json b/firebase/functions/package-lock.json index d39919d4fe..a5341277f0 100644 --- a/firebase/functions/package-lock.json +++ b/firebase/functions/package-lock.json @@ -1888,9 +1888,9 @@ "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, "node-fetch": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", - "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" }, "node-forge": { "version": "0.9.1", From 664407394eb0501a5677ba3d2fdfeca52cd1e643 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 13 Sep 2020 09:28:09 -0700 Subject: [PATCH 132/212] Update dependency org.junit.jupiter:junit-jupiter to v5.7.0 (#639) --- subset/switches/pom.xml | 2 +- usi/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subset/switches/pom.xml b/subset/switches/pom.xml index 963ae2db30..4783c41d5a 100644 --- a/subset/switches/pom.xml +++ b/subset/switches/pom.xml @@ -59,7 +59,7 @@ org.junit.jupiter junit-jupiter - 5.6.2 + 5.7.0 compile diff --git a/usi/pom.xml b/usi/pom.xml index 386c132c39..7f58f48325 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -59,7 +59,7 @@ org.junit.jupiter junit-jupiter - 5.6.2 + 5.7.0 compile From 381755050b86d529e570f1892cde296eed7ee01d Mon Sep 17 00:00:00 2001 From: Noureddine Date: Mon, 14 Sep 2020 11:48:36 +0100 Subject: [PATCH 133/212] Add DNS hostname resolution test (#638) * Add connection.dns.hostname_connect tests --- docs/device_report.md | 9 +- subset/network/README.md | 9 ++ subset/network/dns_tests.py | 183 ++++++++++++++++++++++++++++++++++++ subset/network/test_network | 4 + testing/test_aux.out | 3 + testing/test_aux.sh | 7 +- 6 files changed, 210 insertions(+), 5 deletions(-) create mode 100644 subset/network/dns_tests.py diff --git a/docs/device_report.md b/docs/device_report.md index a461268da2..83c4ff8fa4 100644 --- a/docs/device_report.md +++ b/docs/device_report.md @@ -56,7 +56,7 @@ Overall device result FAIL |---|---|---|---|---|---| |Required|1|0|0|0|0| |Recommended|1|0|0|0|1| -|Other|6|2|20|1|2| +|Other|6|2|21|1|2| |Result|Test|Category|Expectation|Notes| |---|---|---|---|---| @@ -67,6 +67,7 @@ Overall device result FAIL |skip|cloud.udmi.state|Other|Other|No device id| |skip|cloud.udmi.system|Other|Other|No device id| |info|communication.type.broadcast|Other|Other|Broadcast packets received. Unicast packets received.| +|skip|connection.dns.hostname_connect|Other|Other|Device did not send any DNS requests| |fail|connection.mac_oui|Other|Other|Manufacturer prefix not found!| |pass|connection.min_send|Other|Other|ARP packets received. Data packets were sent at a frequency of less than 5 minutes| |pass|connection.network.ntp_support|Other|Other|Using NTPv4.| @@ -577,6 +578,12 @@ Mac OUI Test -------------------- RESULT fail connection.mac_oui Manufacturer prefix not found! +-------------------- +connection.dns.hostname_connect +-------------------- +Check device uses the DNS server from DHCP and resolves hostnames +-------------------- +RESULT skip connection.dns.hostname_connect Device did not send any DNS requests ``` #### Module Config diff --git a/subset/network/README.md b/subset/network/README.md index d4868e113d..677a519931 100644 --- a/subset/network/README.md +++ b/subset/network/README.md @@ -65,3 +65,12 @@ static resource on the source code repo. ### Conditions for mac_oui - pass -> if the MAC OUI matches the mac prefix IEEE registration. - fail -> if the MAC OUI does not match with any of the mac prefixes. + + +## DNS Tests +Check Device uses the DNS server from DHCP and resolves hostnames + +### Conditions for connection.dns.hostname_connect + - pass -> if the device uses the DNS server from DHCP, and resolves a hostname + - fail -> device uses a DNS serveer other than the server fron DHCP + - skip -> device did not send any DNS requests \ No newline at end of file diff --git a/subset/network/dns_tests.py b/subset/network/dns_tests.py new file mode 100644 index 0000000000..f8ebfde258 --- /dev/null +++ b/subset/network/dns_tests.py @@ -0,0 +1,183 @@ +""" + This script can be called to run DNS related test. + +""" +from __future__ import absolute_import +import subprocess +import sys + +import re +import datetime + +arguments = sys.argv + +test_request = str(arguments[1]) +cap_pcap_file = str(arguments[2]) +device_address = str(arguments[3]) + +report_filename = 'dns_tests.txt' +min_packet_length_bytes = 20 +max_packets_in_report = 10 +port_list = [] +ignore = '%%' +summary_text = '' +result = 'fail' +dash_break_line = '--------------------\n' + +DESCRIPTION_HOSTNAME_CONNECT = 'Check device uses the DNS server from DHCP and resolves hostnames' + +TCPDUMP_DATE_FORMAT = "%Y-%m-%d %H:%M:%S.%f" + +IP_REGEX = r'(([0-9]{1,3}\.){3}[0-9]{1,3})' +RDATA_REGEX = r'' + +DNS_SERVER_HOST = '.2' + + +def write_report(string_to_append): + print(string_to_append.strip()) + with open(report_filename, 'a+') as file_open: + file_open.write(string_to_append) + + +def exec_tcpdump(tcpdump_filter, capture_file=None): + """ + Args + tcpdump_filter: Filter to pass onto tcpdump file + capture_file: Optional capture file to look + + Returns + List of packets matching the filter + """ + + capture_file = cap_pcap_file if capture_file is None else capture_file + command = 'tcpdump -tttt -n -r {} {}'.format(capture_file, tcpdump_filter) + + process = subprocess.Popen(command, + universal_newlines=True, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + text = str(process.stdout.read()).rstrip() + + if text: + return text.split("\n") + + return [] + + +def add_summary(text): + global summary_text + summary_text = summary_text + " " + text if summary_text else text + + +def get_dns_server_from_ip(ip_address): + """ + Returns the IP address of the DNS server provided by DAQ + + Args + ip_address: IP address of the device under test + + Returns + IP address of DNS server + """ + + return re.sub(r'\.\d+$', DNS_SERVER_HOST, ip_address) + + +def check_communication_for_response(response_line): + """ + Given a line from the TCPdump output for DNS responses + Look through the packet capture to see if any communitication to the + IP addresses from the DNS + + Args + tcpdump_line: Line from tcpdump filtered to DNS resposnes + + Returns + True/False if the device has communicated with an IP from the + DNS response after it has recieved it + """ + + response_time = datetime.datetime.strptime(response_line[:26], TCPDUMP_DATE_FORMAT) + + # Use regex to extract all IP addresses in the response + matches = re.findall(IP_REGEX, response_line) + + # The first two IP addresses are the source/destination + ip_addresses = matches[2:] + + for address in ip_addresses: + packets = exec_tcpdump('dst host {}'.format(address[0])) + for packet in packets: + packet_time = datetime.datetime.strptime(packet[:26], TCPDUMP_DATE_FORMAT) + if packet_time > response_time: + return True + + return False + + +def test_dns(target_ip): + """ Runs the connection.dns.hostname_connect test + + Checks that: + i) the device sends DNS requests + ii) the device uses the DNS server from DHCP + iii) the device uses an IP address recieved from the DNS server + + Args + target_ip: IP address of the device + """ + + # Get server IP of the DHCP server + dhcp_dns_ip = get_dns_server_from_ip(target_ip) + + # Check if the device has sent any DNS requests + filter_to_dns = 'dst port 53 and src host {}'.format(target_ip) + to_dns = exec_tcpdump(filter_to_dns) + num_query_dns = len(to_dns) + + if num_query_dns == 0: + add_summary('Device did not send any DNS requests') + return 'skip' + + # Check if the device only sent DNS requests to the DHCP Server + filter_to_dhcp_dns = 'dst port 53 and src host {} and dst host {}' \ + .format(target_ip, dhcp_dns_ip) + + to_dhcp_dns = exec_tcpdump(filter_to_dhcp_dns) + num_query_dhcp_dns = len(to_dhcp_dns) + + if num_query_dns > num_query_dhcp_dns: + add_summary('Device sent DNS requests to servers other than the DHCP provided server') + return 'fail' + + # Retrieve responses from DNS + filter_dns_response = 'src port 53 and src host {}'.format(dhcp_dns_ip) + dns_responses = exec_tcpdump(filter_dns_response) + + num_dns_responses = len(dns_responses) + + if num_dns_responses == 0: + add_summary('No results recieved from DNS server') + return 'fail' + + # Check that the device has sent data packets to any of the IP addresses it has recieved + # it has recieved from the DNS requests + + for response in dns_responses: + if check_communication_for_response(response): + add_summary('Device sends DNS requests and resolves host names') + return 'pass' + + add_summary('Device did not send data to IP addresses retrieved from the DNS server') + return 'fail' + + +write_report("{b}{t}\n{b}".format(b=dash_break_line, t=test_request)) + +if test_request == 'connection.dns.hostname_connect': + write_report("{d}\n{b}".format(b=dash_break_line, d=DESCRIPTION_HOSTNAME_CONNECT)) + result = test_dns(device_address) + +write_report("RESULT {r} {t} {s}\n".format(r=result, t=test_request, s=summary_text.strip())) diff --git a/subset/network/test_network b/subset/network/test_network index e3a9344ffb..15b642f456 100755 --- a/subset/network/test_network +++ b/subset/network/test_network @@ -20,3 +20,7 @@ cat ntp_tests.txt >> $REPORT # MACOUI Test ./run_macoui_test $TARGET_MAC $REPORT +# DNS Tests +python dns_tests.py connection.dns.hostname_connect $MONITOR $TARGET_IP + +cat dns_tests.txt >> $REPORT diff --git a/testing/test_aux.out b/testing/test_aux.out index 36df1a799f..8a6bd9e9cf 100644 --- a/testing/test_aux.out +++ b/testing/test_aux.out @@ -58,16 +58,19 @@ RESULT info communication.type.broadcast Broadcast packets received. Unicast pac RESULT pass connection.network.ntp_support Using NTPv4. RESULT pass connection.network.ntp_update Device clock synchronized. RESULT fail connection.mac_oui Manufacturer prefix not found! +RESULT skip connection.dns.hostname_connect Device did not send any DNS requests RESULT pass connection.min_send ARP packets received. Data packets were sent at a frequency of less than 5 minutes RESULT info communication.type.broadcast Broadcast packets received. Unicast packets received. RESULT fail connection.network.ntp_support Not using NTPv4. RESULT fail connection.network.ntp_update Device clock not synchronized with local NTP server. RESULT pass connection.mac_oui Manufacturer: Google found for address 3c:5a:b4:1e:8f:0b +RESULT fail connection.dns.hostname_connect Device sent DNS requests to servers other than the DHCP provided server RESULT pass connection.min_send ARP packets received. Data packets were sent at a frequency of less than 5 minutes RESULT info communication.type.broadcast Broadcast packets received. Unicast packets received. RESULT skip connection.network.ntp_support No NTP packets received. RESULT skip connection.network.ntp_update Not enough NTP packets received. RESULT pass connection.mac_oui Manufacturer: Google found for address 3c:5a:b4:1e:8f:0a +RESULT pass connection.dns.hostname_connect Device sends DNS requests and resolves host names dhcp requests 1 1 1 1 3c5ab41e8f0a: [] 3c5ab41e8f0b: ['3c5ab41e8f0b:ping:TimeoutError'] diff --git a/testing/test_aux.sh b/testing/test_aux.sh index afddb3ae3c..d00e8267aa 100755 --- a/testing/test_aux.sh +++ b/testing/test_aux.sh @@ -67,9 +67,9 @@ interfaces: faux-1: opts: brute broadcast_client ntpv4 faux-2: - opts: nobrute expiredtls bacnetfail pubber passwordfail ntpv3 opendns ssh + opts: nobrute expiredtls bacnetfail pubber passwordfail ntpv3 opendns ssh curl faux-3: - opts: tls macoui passwordpass bacnet pubber broadcast_client ssh + opts: tls macoui passwordpass bacnet pubber broadcast_client ssh curl long_dhcp_response_sec: 0 monitor_scan_sec: 20 EOF @@ -117,8 +117,7 @@ capture_test_results macoui capture_test_results tls capture_test_results password capture_test_results discover -capture_test_results networ -capture_test_results ntp +capture_test_results network # Capture peripheral logs more inst/run-*/scans/ip_triggers.txt | cat From ff0675ff61cd98c44f606300eef44b4c143487d4 Mon Sep 17 00:00:00 2001 From: Francesco Anselmo Date: Mon, 14 Sep 2020 13:47:34 +0100 Subject: [PATCH 134/212] switch config files (#633) * switch config files for Cisco 9300 and ATx230 --- bin/setup_switch | 4 +- docs/quickstart.md | 2 +- etc/switch_configs/at_16ports.cfg | 35 ++++ etc/switch_configs/{at.cfg => at_8ports.cfg} | 0 etc/switch_configs/cisco_24ports.cfg | 197 +++++++++++++++++++ 5 files changed, 235 insertions(+), 3 deletions(-) create mode 100644 etc/switch_configs/at_16ports.cfg rename etc/switch_configs/{at.cfg => at_8ports.cfg} (100%) create mode 100644 etc/switch_configs/cisco_24ports.cfg diff --git a/bin/setup_switch b/bin/setup_switch index 63d70c9bc2..9aa22f96d8 100755 --- a/bin/setup_switch +++ b/bin/setup_switch @@ -45,9 +45,9 @@ EOM } interface_setup -curl -u manager:friend "https://$switch_ip/fs/flash/af.cfg" -k -X PUT -H 'Content-Type: ' --data-binary @etc/switch_configs/at.cfg +curl -u manager:friend "https://$switch_ip/fs/flash/at_8ports.cfg" -k -X PUT -H 'Content-Type: ' --data-binary @etc/switch_configs/at_8ports.cfg -curl -u manager:friend "https://$switch_ip/api/boot/config" -k -H 'content-type: application/json' --data '{"name":"flash:/af.cfg"}' +curl -u manager:friend "https://$switch_ip/api/boot/config" -k -H 'content-type: application/json' --data '{"name":"flash:/at_8ports.cfg"}' curl -u manager:friend "https://$switch_ip/api/system" -k -H 'content-type: application/json' --data '{"reboot":"1"}' diff --git a/docs/quickstart.md b/docs/quickstart.md index b2fc648889..7e4a48ede8 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -22,7 +22,7 @@ $ cmd/build ## (Optional) Physical Switch Setup ### AT x230 series with factory setting 1. Plug one ethernet cable into the last port of the switch. -2. If the switch has more than 8 ethernet ports, change **interface port1.0.1-1.0.7** in **etc/switch_configs/at.cfg** to **interface port1.0.1-1.0.(number of ports - 1)**. Everything else can stay the same. +2. If the switch has more than 8 ethernet ports, change **interface port1.0.1-1.0.7** in **etc/switch_configs/at_8ports.cfg** to **interface port1.0.1-1.0.(number of ports - 1)**. Everything else can stay the same. 3. Find interface name that's connected to switch e.g. enx00e04c68036b 4. run
      $ sudo bin/setup_switch enx00e04c68036b 
      replace enx00e04c68036b with your interface name. After about 2 mins, the switch is ready to be used by DAQ. 5. Confirm you can ping switch at 192.168.1.1 diff --git a/etc/switch_configs/at_16ports.cfg b/etc/switch_configs/at_16ports.cfg new file mode 100644 index 0000000000..3b0946c281 --- /dev/null +++ b/etc/switch_configs/at_16ports.cfg @@ -0,0 +1,35 @@ +vlan database +vlan 4090 +! +interface vlan1 +ip address 192.168.1.1/24 +! +openflow controller tcp 192.168.1.10 6654 +! +openflow controller faucet tcp 192.168.1.10 6653 +! +openflow native vlan 4090 +! +interface port1.0.1-1.0.15 +openflow +! +openflow datapath-id 12345 +! +no loop-protection loop-detect +! +interface vlan4090 +no ip igmp snooping tcn query solicit +! +service password-encryption +! +username manager privilege 15 password 8 $1$bJoVec4D$JwOJGPr7YqoExA0GVasdE0 +! +ssh server allow-users manager +service ssh +! +platform hwfilter-size ipv4-full-ipv6 +! +service telnet +! +service http +! diff --git a/etc/switch_configs/at.cfg b/etc/switch_configs/at_8ports.cfg similarity index 100% rename from etc/switch_configs/at.cfg rename to etc/switch_configs/at_8ports.cfg diff --git a/etc/switch_configs/cisco_24ports.cfg b/etc/switch_configs/cisco_24ports.cfg new file mode 100644 index 0000000000..cb0fa4c1ed --- /dev/null +++ b/etc/switch_configs/cisco_24ports.cfg @@ -0,0 +1,197 @@ +vrf definition Mgmt-vrf + ! + address-family ipv4 + exit-address-family + ! + address-family ipv6 + exit-address-family +! +enable secret 9 $9$1l2L3/QH3V.H2.$wq7QzPpZGUwDt1hF.iE9n/ux.0rA2gpVMgph5JqM3aQ +! +no aaa new-model +switch 1 provision c9300-24p +! +! +feature openflow +! +spanning-tree mode rapid-pvst +spanning-tree extend system-id +! +username admin privilege 15 secret 9 $9$1l2L3/QH3V.H2.$wq7QzPpZGUwDt1hF.iE9n/ux.0rA2gpVMgph5JqM3aQ +! +! the GigabitEthernet0/0 interface refers to the network port at the back of the switch +interface GigabitEthernet0/0 + vrf forwarding Mgmt-vrf + ip address 192.168.10.10 255.255.255.0 + negotiation auto +! +interface GigabitEthernet1/0/1 + no keepalive + spanning-tree bpdufilter enable +! +interface GigabitEthernet1/0/2 + no keepalive + spanning-tree bpdufilter enable +! +interface GigabitEthernet1/0/3 + no keepalive + spanning-tree bpdufilter enable +! +interface GigabitEthernet1/0/4 + no keepalive + spanning-tree bpdufilter enable +! +interface GigabitEthernet1/0/5 + no keepalive + spanning-tree bpdufilter enable +! +interface GigabitEthernet1/0/6 + no keepalive + spanning-tree bpdufilter enable +! +interface GigabitEthernet1/0/7 + no keepalive + spanning-tree bpdufilter enable +! +interface GigabitEthernet1/0/8 + no keepalive + spanning-tree bpdufilter enable +! +interface GigabitEthernet1/0/9 + no keepalive + spanning-tree bpdufilter enable +! +interface GigabitEthernet1/0/10 + no keepalive + spanning-tree bpdufilter enable +! +interface GigabitEthernet1/0/11 + no keepalive + spanning-tree bpdufilter enable +! +interface GigabitEthernet1/0/12 + no keepalive + spanning-tree bpdufilter enable +! +interface GigabitEthernet1/0/13 + no keepalive + spanning-tree bpdufilter enable +! +interface GigabitEthernet1/0/14 + no keepalive + spanning-tree bpdufilter enable +! +interface GigabitEthernet1/0/15 + no keepalive + spanning-tree bpdufilter enable +! +interface GigabitEthernet1/0/16 + no keepalive + spanning-tree bpdufilter enable +! +interface GigabitEthernet1/0/17 + no keepalive + spanning-tree bpdufilter enable +! +interface GigabitEthernet1/0/18 + no keepalive + spanning-tree bpdufilter enable +! +interface GigabitEthernet1/0/19 + no keepalive + spanning-tree bpdufilter enable +! +interface GigabitEthernet1/0/20 + no keepalive + spanning-tree bpdufilter enable +! +interface GigabitEthernet1/0/21 + no keepalive + spanning-tree bpdufilter enable +! +interface GigabitEthernet1/0/22 + no keepalive + spanning-tree bpdufilter enable +! +interface GigabitEthernet1/0/23 + no keepalive + spanning-tree bpdufilter enable +! +interface GigabitEthernet1/0/24 + no keepalive + spanning-tree bpdufilter enable +! +interface GigabitEthernet1/1/1 +! +interface GigabitEthernet1/1/2 +! +interface GigabitEthernet1/1/3 +! +interface GigabitEthernet1/1/4 +! +interface TenGigabitEthernet1/1/1 +! +interface TenGigabitEthernet1/1/2 +! +interface TenGigabitEthernet1/1/3 +! +interface TenGigabitEthernet1/1/4 +! +interface TenGigabitEthernet1/1/5 +! +interface TenGigabitEthernet1/1/6 +! +interface TenGigabitEthernet1/1/7 +! +interface TenGigabitEthernet1/1/8 +! +interface FortyGigabitEthernet1/1/1 +! +interface FortyGigabitEthernet1/1/2 +! +interface TwentyFiveGigE1/1/1 +! +interface TwentyFiveGigE1/1/2 +! +interface AppGigabitEthernet1/0/1 +! +ip default-gateway 192.168.10.1 +ip forward-protocol nd +ip http server +ip http authentication local +ip http secure-server +ip http client source-interface GigabitEthernet0/0 +ip route 0.0.0.0 0.0.0.0 192.168.10.1 +! +! change the last IP address with the IP address of the local internet gateway +ip route 0.0.0.0 0.0.0.0 192.168.10.254 +ip route 192.168.10.0 255.255.255.255 192.168.10.1 +! +! change the last IP address with the IP address of the local internet gateway +ip route vrf Mgmt-vrf 0.0.0.0 0.0.0.0 192.168.10.254 +! +ip dhcp pool home + dns-server 8.8.8.8 +! +control-plane + service-policy input system-cpp-policy +! +openflow + switch 1 pipeline 1 + controller ipv4 192.168.10.11 port 6653 vrf Mgmt-vrf security none + controller ipv4 192.168.10.11 port 6654 vrf Mgmt-vrf security none + datapath-id 0xABCDEF1234 +! +! configure telnet access +line con 0 + stopbits 1 +line vty 0 4 + password password + login + length 0 + transport input telnet +line vty 5 15 + password password + login + transport input telnet +! \ No newline at end of file From 28c75d08ceeb953d3b3c93dabc4c99bf8e44e3e5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 15 Sep 2020 15:00:57 -0700 Subject: [PATCH 135/212] Update dependency firebase-admin to v9.2.0 (#641) --- firebase/functions/package-lock.json | 206 ++++++++++++++------------- firebase/functions/package.json | 2 +- 2 files changed, 105 insertions(+), 103 deletions(-) diff --git a/firebase/functions/package-lock.json b/firebase/functions/package-lock.json index a5341277f0..3a1f4f2679 100644 --- a/firebase/functions/package-lock.json +++ b/firebase/functions/package-lock.json @@ -14,24 +14,24 @@ "integrity": "sha512-88h74TMQ6wXChPA6h9Q3E1Jg6TkTHep2+k63OWg3s0ozyGVMeY+TTOti7PFPzq5RhszQPQOoCi59es4MaRvgCw==" }, "@firebase/component": { - "version": "0.1.18", - "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.1.18.tgz", - "integrity": "sha512-c8gd1k/e0sbBTR0xkLIYUN8nVkA0zWxcXGIvdfYtGEsNw6n7kh5HkcxKXOPB8S7bcPpqZkGgBIfvd94IyG2gaQ==", + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.1.19.tgz", + "integrity": "sha512-L0S3g8eqaerg8y0zox3oOHSTwn/FE8RbcRHiurnbESvDViZtP5S5WnhuAPd7FnFxa8ElWK0z1Tr3ikzWDv1xdQ==", "requires": { - "@firebase/util": "0.3.1", + "@firebase/util": "0.3.2", "tslib": "^1.11.1" } }, "@firebase/database": { - "version": "0.6.11", - "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.6.11.tgz", - "integrity": "sha512-QOHhB7+CdjVhEXG9CyX0roA9ARJcEuwbozz0Bix+ULuZqjQ58KUFHMH1apW6EEiUP22d/mYD7dNXsUGshjL9PA==", + "version": "0.6.12", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.6.12.tgz", + "integrity": "sha512-OLUxp8TkXiML4X5LWM5IACsSDvo3fcf4mTbTe5RF+N6TRFv0Svzlet5OgGIa3ET1dQvNiisrMX7zzRa0OTLs7Q==", "requires": { "@firebase/auth-interop-types": "0.1.5", - "@firebase/component": "0.1.18", + "@firebase/component": "0.1.19", "@firebase/database-types": "0.5.2", "@firebase/logger": "0.2.6", - "@firebase/util": "0.3.1", + "@firebase/util": "0.3.2", "faye-websocket": "0.11.3", "tslib": "^1.11.1" } @@ -50,17 +50,17 @@ "integrity": "sha512-KIxcUvW/cRGWlzK9Vd2KB864HlUnCfdTH0taHE0sXW5Xl7+W68suaeau1oKNEqmc3l45azkd4NzXTCWZRZdXrw==" }, "@firebase/util": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.3.1.tgz", - "integrity": "sha512-zjVd9rfL08dRRdZILFn1RZTHb1euCcnD9N/9P56gdBcm2bvT5XsCC4G6t5toQBpE/H/jYe5h6MZMqfLu3EQLXw==", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.3.2.tgz", + "integrity": "sha512-Dqs00++c8rwKky6KCKLLY2T1qYO4Q+X5t+lF7DInXDNF4ae1Oau35bkD+OpJ9u7l1pEv7KHowP6CUKuySCOc8g==", "requires": { "tslib": "^1.11.1" } }, "@google-cloud/common": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-3.3.2.tgz", - "integrity": "sha512-W7JRLBEJWYtZQQuGQX06U6GBOSLrSrlvZxv6kGNwJtFrusu6AVgZltQ9Pajuz9Dh9aSXy9aTnBcyxn2/O0EGUw==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-3.4.0.tgz", + "integrity": "sha512-bVMQlK4aZEeopo2oJwDUJiBhPVjRRQHfFCCv9JowmKS3L//PBHNDJzC/LxJixGZEU3fh3YXkUwm67JZ5TBCCNQ==", "optional": true, "requires": { "@google-cloud/projectify": "^2.0.0", @@ -93,9 +93,9 @@ } }, "gaxios": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.1.0.tgz", - "integrity": "sha512-DDTn3KXVJJigtz+g0J3vhcfbDbKtAroSTxauWsdnP57sM5KZ3d2c/3D9RKFJ86s43hfw6WULg6TXYw/AYiBlpA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.2.0.tgz", + "integrity": "sha512-+6WPeVzPvOshftpxJwRi2Ozez80tn/hdtOUag7+gajDHRJvAblKxTFSSMPtr2hmnLy7p0mvYz0rMXLBl8pSO7Q==", "optional": true, "requires": { "abort-controller": "^3.0.0", @@ -106,9 +106,9 @@ } }, "gcp-metadata": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.1.4.tgz", - "integrity": "sha512-5J/GIH0yWt/56R3dNaNWPGQ/zXsZOddYECfJaqxFWgrZ9HC2Kvc5vl9upOgUUHKzURjAVf2N+f6tEJiojqXUuA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.2.0.tgz", + "integrity": "sha512-vQZD57cQkqIA6YPGXM/zc+PIZfNRFdukWGsGZ5+LcJzesi5xp6Gn7a02wRJi4eXPyArNMIYpPET4QMxGqtlk6Q==", "optional": true, "requires": { "gaxios": "^3.0.0", @@ -133,12 +133,12 @@ } }, "google-p12-pem": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.2.tgz", - "integrity": "sha512-tbjzndQvSIHGBLzHnhDs3cL4RBjLbLXc2pYvGH+imGVu5b4RMAttUTdnmW2UH0t11QeBTXZ7wlXPS7hrypO/tg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.3.tgz", + "integrity": "sha512-wS0ek4ZtFx/ACKYF3JhyGe5kzH7pgiQ7J5otlumqR9psmWMYc+U9cErKlCYVYHoUaidXHdZ2xbo34kB+S+24hA==", "optional": true, "requires": { - "node-forge": "^0.9.0" + "node-forge": "^0.10.0" } }, "gtoken": { @@ -171,6 +171,12 @@ "yallist": "^4.0.0" } }, + "node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", + "optional": true + }, "readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -202,9 +208,9 @@ }, "dependencies": { "@grpc/grpc-js": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.1.5.tgz", - "integrity": "sha512-2huf5z85TdZI4nLmJQ9Zdfd+6vmIyBDs7B4L71bTaHKA9pRsGKAH24XaktMk/xneKJIqAgeIZtg1cyivVZtvrg==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.1.6.tgz", + "integrity": "sha512-bUeaMN/dHTkt9AqU0Tc1xdHMB3jVLyPNfg8gZ5cMyhFyMeCwoJbFcJrNBgYqRCbvYhvtaEgzQwkw91NnY4Oktg==", "optional": true, "requires": { "@grpc/proto-loader": "^0.6.0-pre14", @@ -229,9 +235,9 @@ } }, "@types/node": { - "version": "12.12.54", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.54.tgz", - "integrity": "sha512-ge4xZ3vSBornVYlDnk7yZ0gK6ChHf/CHB7Gl1I0Jhah8DDnEQqBzgohYG4FX4p81TNirSETOiSyn+y1r9/IR6w==", + "version": "12.12.58", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.58.tgz", + "integrity": "sha512-Be46CNIHWAagEfINOjmriSxuv7IVcqbGe+sDSg2SYCEz/0CRBy7LRASGfRbD8KZkqoePU73Wsx3UvOSFcq/9hA==", "optional": true }, "bignumber.js": { @@ -241,9 +247,9 @@ "optional": true }, "gaxios": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.1.0.tgz", - "integrity": "sha512-DDTn3KXVJJigtz+g0J3vhcfbDbKtAroSTxauWsdnP57sM5KZ3d2c/3D9RKFJ86s43hfw6WULg6TXYw/AYiBlpA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.2.0.tgz", + "integrity": "sha512-+6WPeVzPvOshftpxJwRi2Ozez80tn/hdtOUag7+gajDHRJvAblKxTFSSMPtr2hmnLy7p0mvYz0rMXLBl8pSO7Q==", "optional": true, "requires": { "abort-controller": "^3.0.0", @@ -254,9 +260,9 @@ } }, "gcp-metadata": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.1.4.tgz", - "integrity": "sha512-5J/GIH0yWt/56R3dNaNWPGQ/zXsZOddYECfJaqxFWgrZ9HC2Kvc5vl9upOgUUHKzURjAVf2N+f6tEJiojqXUuA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.2.0.tgz", + "integrity": "sha512-vQZD57cQkqIA6YPGXM/zc+PIZfNRFdukWGsGZ5+LcJzesi5xp6Gn7a02wRJi4eXPyArNMIYpPET4QMxGqtlk6Q==", "optional": true, "requires": { "gaxios": "^3.0.0", @@ -281,9 +287,9 @@ } }, "google-gax": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-2.7.0.tgz", - "integrity": "sha512-0dBATy8mMVlfOBrT85Q+NzBpZ4OJZUMrPI9wJULpiIDq2w1zlN30Duor+fQUcMEjanYEc72G58M4iUVve0jfXw==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-2.8.0.tgz", + "integrity": "sha512-MPaADY/FHittX5xfOUU2EVqIoE850e+OZ1ys8aO2GnUMaP4U0Bde2wop6kw5sp4fIOjKNlan4GATKAURsYbxSw==", "optional": true, "requires": { "@grpc/grpc-js": "~1.1.1", @@ -303,12 +309,12 @@ } }, "google-p12-pem": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.2.tgz", - "integrity": "sha512-tbjzndQvSIHGBLzHnhDs3cL4RBjLbLXc2pYvGH+imGVu5b4RMAttUTdnmW2UH0t11QeBTXZ7wlXPS7hrypO/tg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.3.tgz", + "integrity": "sha512-wS0ek4ZtFx/ACKYF3JhyGe5kzH7pgiQ7J5otlumqR9psmWMYc+U9cErKlCYVYHoUaidXHdZ2xbo34kB+S+24hA==", "optional": true, "requires": { - "node-forge": "^0.9.0" + "node-forge": "^0.10.0" } }, "gtoken": { @@ -341,6 +347,12 @@ "yallist": "^4.0.0" } }, + "node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", + "optional": true + }, "protobufjs": { "version": "6.10.1", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.10.1.tgz", @@ -363,9 +375,9 @@ }, "dependencies": { "@types/node": { - "version": "13.13.15", - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.15.tgz", - "integrity": "sha512-kwbcs0jySLxzLsa2nWUAGOd/s21WU1jebrEdtzhsj1D4Yps1EOuyI1Qcu+FD56dL7NRNIJtDDjcqIG22NwkgLw==", + "version": "13.13.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.19.tgz", + "integrity": "sha512-IVsULCpTdafcHhBDLYEPnV5l15xV0q065zvOHC1ZmzFYaBCMzku078eXnazoSG8907vZjRgEN/EQjku7GwwFyQ==", "optional": true } } @@ -566,9 +578,9 @@ } }, "@google-cloud/storage": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-5.2.0.tgz", - "integrity": "sha512-zxHXZajtVA0Qx9IOnDUDb76mtKn5M20LKV/phmnVos7foozG9YZ6yYod90pRC/GgP3eOgxNYdt6KQcapssPsFw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-5.3.0.tgz", + "integrity": "sha512-3t5UF3SZ14Bw2kcBHubCai6EIugU2GnQOstYWVSFuoO8IJ94RAaIOPq/dtexvQbUTpBTAGpd5smVR9WPL1mJVw==", "optional": true, "requires": { "@google-cloud/common": "^3.3.0", @@ -594,9 +606,9 @@ }, "dependencies": { "gaxios": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.1.0.tgz", - "integrity": "sha512-DDTn3KXVJJigtz+g0J3vhcfbDbKtAroSTxauWsdnP57sM5KZ3d2c/3D9RKFJ86s43hfw6WULg6TXYw/AYiBlpA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.2.0.tgz", + "integrity": "sha512-+6WPeVzPvOshftpxJwRi2Ozez80tn/hdtOUag7+gajDHRJvAblKxTFSSMPtr2hmnLy7p0mvYz0rMXLBl8pSO7Q==", "optional": true, "requires": { "abort-controller": "^3.0.0", @@ -1078,9 +1090,9 @@ "optional": true }, "date-and-time": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-0.14.0.tgz", - "integrity": "sha512-0wY8b90XjQkRxv3XGT8k1ffyDQOf4+T+2hiWp7rwYgoEn8OyYDsHZdnVrPlzxbwjLUY66mVBXr59eKOwpSV7lw==", + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-0.14.1.tgz", + "integrity": "sha512-M4RggEH5OF2ZuCOxgOU67R6Z9ohjKbxGvAQz48vj53wLmL0bAgumkBvycR32f30pK+Og9pIR+RFDyChbaE4oLA==", "optional": true }, "debug": { @@ -1116,9 +1128,9 @@ } }, "dot-prop": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz", - "integrity": "sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", "optional": true, "requires": { "is-obj": "^2.0.0" @@ -1309,24 +1321,29 @@ } }, "firebase-admin": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-9.1.1.tgz", - "integrity": "sha512-HkzY9yN/kOe1EQgjheURAQ4pFBerI54TBL0+nj1fwzKnAnGCpcI73Bbwx99Pk3u2x4rj6bDcsZfz9bA8y7DWtQ==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-9.2.0.tgz", + "integrity": "sha512-LhnMYl71B4gP1FlTLfwaYlOWhBCAcNF+byb2CPTfaW/T4hkp4qlXOgo2bws/zbAv5X9GTFqGir3KexMslVGsIA==", "requires": { "@firebase/database": "^0.6.10", "@firebase/database-types": "^0.5.2", "@google-cloud/firestore": "^4.0.0", - "@google-cloud/storage": "^5.0.0", + "@google-cloud/storage": "^5.3.0", "@types/node": "^10.10.0", "dicer": "^0.3.0", "jsonwebtoken": "^8.5.1", - "node-forge": "^0.9.1" + "node-forge": "^0.10.0" }, "dependencies": { "@types/node": { - "version": "10.17.28", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.28.tgz", - "integrity": "sha512-dzjES1Egb4c1a89C7lKwQh8pwjYmlOAG9dW1pBgxEk57tMrLnssOfEthz8kdkNaBd7lIqQx7APm5+mZ619IiCQ==" + "version": "10.17.33", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.33.tgz", + "integrity": "sha512-Z761mij1nxISY1GhZv2Ie/6ofe0JQTcMtcyFCJ9ItZzRvCwLyktyoPKzpugFqW2T7lCwUCSqpQbDo8Eol9r2EA==" + }, + "node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" } } }, @@ -1400,9 +1417,9 @@ "optional": true }, "gaxios": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.1.0.tgz", - "integrity": "sha512-DDTn3KXVJJigtz+g0J3vhcfbDbKtAroSTxauWsdnP57sM5KZ3d2c/3D9RKFJ86s43hfw6WULg6TXYw/AYiBlpA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.2.0.tgz", + "integrity": "sha512-+6WPeVzPvOshftpxJwRi2Ozez80tn/hdtOUag7+gajDHRJvAblKxTFSSMPtr2hmnLy7p0mvYz0rMXLBl8pSO7Q==", "optional": true, "requires": { "abort-controller": "^3.0.0", @@ -1413,9 +1430,9 @@ } }, "gcp-metadata": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.1.4.tgz", - "integrity": "sha512-5J/GIH0yWt/56R3dNaNWPGQ/zXsZOddYECfJaqxFWgrZ9HC2Kvc5vl9upOgUUHKzURjAVf2N+f6tEJiojqXUuA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.2.0.tgz", + "integrity": "sha512-vQZD57cQkqIA6YPGXM/zc+PIZfNRFdukWGsGZ5+LcJzesi5xp6Gn7a02wRJi4eXPyArNMIYpPET4QMxGqtlk6Q==", "optional": true, "requires": { "gaxios": "^3.0.0", @@ -1440,12 +1457,12 @@ } }, "google-p12-pem": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.2.tgz", - "integrity": "sha512-tbjzndQvSIHGBLzHnhDs3cL4RBjLbLXc2pYvGH+imGVu5b4RMAttUTdnmW2UH0t11QeBTXZ7wlXPS7hrypO/tg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.3.tgz", + "integrity": "sha512-wS0ek4ZtFx/ACKYF3JhyGe5kzH7pgiQ7J5otlumqR9psmWMYc+U9cErKlCYVYHoUaidXHdZ2xbo34kB+S+24hA==", "optional": true, "requires": { - "node-forge": "^0.9.0" + "node-forge": "^0.10.0" } }, "gtoken": { @@ -1478,6 +1495,12 @@ "yallist": "^4.0.0" } }, + "node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", + "optional": true + }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -1556,25 +1579,10 @@ } }, "hash-stream-validation": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/hash-stream-validation/-/hash-stream-validation-0.2.3.tgz", - "integrity": "sha512-OEohGLoUOh+bwsIpHpdvhIXFyRGjeLqJbT8Yc5QTZPbRM7LKywagTQxnX/6mghLDOrD9YGz88hy5mLN2eKflYQ==", - "optional": true, - "requires": { - "through2": "^2.0.0" - }, - "dependencies": { - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "optional": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - } - } + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/hash-stream-validation/-/hash-stream-validation-0.2.4.tgz", + "integrity": "sha512-Gjzu0Xn7IagXVkSu9cSFuK1fqzwtLwFhNhVL8IFJijRNMgUttFbBSIAzKuSIrsFMO1+g1RlsoN49zPIbwPDMGQ==", + "optional": true }, "http-errors": { "version": "1.7.2", @@ -2433,12 +2441,6 @@ "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", "optional": true }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "optional": true - }, "y18n": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", diff --git a/firebase/functions/package.json b/firebase/functions/package.json index 3e506ecf77..5032f5b1ff 100644 --- a/firebase/functions/package.json +++ b/firebase/functions/package.json @@ -14,7 +14,7 @@ "dependencies": { "@google-cloud/pubsub": "2.5.0", "@google-cloud/iot": "1.8.0", - "firebase-admin": "9.1.1", + "firebase-admin": "9.2.0", "firebase-functions": "3.11.0", "extend": "3.0.2" }, From 0f9669aff0cfd0e22f4583dc3c08807d37b7e945 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 15 Sep 2020 15:01:27 -0700 Subject: [PATCH 136/212] Update dependency jsoneditor to v9.1.0 (#642) --- firebase/public/config.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firebase/public/config.html b/firebase/public/config.html index 6298a6af4e..2d9a8dc601 100644 --- a/firebase/public/config.html +++ b/firebase/public/config.html @@ -11,8 +11,8 @@ - - + +
      From 9d242d655de82a3cf768cf9b7e315b1a1dd2b8fa Mon Sep 17 00:00:00 2001 From: henry54809 Date: Tue, 15 Sep 2020 17:23:06 -0700 Subject: [PATCH 137/212] Feature/native tests (#625) --- .stickler.yml | 1 + bin/setup_dev | 2 +- cmd/exrun | 12 +- daq/docker_test.py | 167 ------------------ daq/host.py | 18 +- daq/runner.py | 19 ++ daq/test_modules/__init__.py | 4 + daq/{ => test_modules}/base_module.py | 6 +- daq/test_modules/docker_module.py | 50 ++++++ daq/test_modules/external_module.py | 155 ++++++++++++++++ .../ipaddr_module.py} | 10 +- daq/test_modules/native_host.py | 103 +++++++++++ daq/test_modules/native_module.py | 43 +++++ docker/modules/Dockerfile.test_fail | 4 - docker/modules/Dockerfile.test_pass | 4 - docker/modules/Dockerfile.test_ping | 8 - docs/device_report.md | 4 +- firebase/public/protos.hash | 2 +- firebase/public/protos.html | 7 + libs/proto/system_config_pb2.py | 35 ++-- proto/system_config.proto | 3 + .../discover/port-01/ping_runtime.sh | 2 +- .../discover/port-02/ping_runtime.sh | 2 +- .../long_wait/port-03/ping_runtime.sh | 4 +- .../setups/baseline/module_manifest.json | 11 -- subset/fail/fail.daqmodule | 4 + subset/pass/pass.daqmodule | 4 + .../pentests/{ => nmap}/Dockerfile.test_nmap | 0 subset/pentests/nmap/nmap.daqmodule | 4 + subset/pentests/{ => nmap}/test_nmap | 38 ++-- subset/ping/module_manifest.json | 11 ++ subset/ping/ping.daqmodule | 4 + {docker/include/bin => subset/ping}/test_ping | 41 ++--- subset/security/Dockerfile.test_tls | 1 - subset/security/test_tls | 3 +- ...manifest.json => tls.module_manifest.json} | 14 +- subset/switches/Dockerfile.test_switch | 1 - subset/switches/test_switch | 2 +- testing/test_base.out | 4 +- testing/test_base.sh | 4 + testing/test_modules.out | 16 -- testing/test_modules.sh | 9 +- testing/test_preamble.sh | 4 +- testing/test_topo.sh | 4 +- testing/test_utils.sh | 8 +- testing/unit/test_runner.py | 1 + usi/build.conf | 1 - 47 files changed, 539 insertions(+), 315 deletions(-) delete mode 100644 daq/docker_test.py create mode 100644 daq/test_modules/__init__.py rename daq/{ => test_modules}/base_module.py (90%) create mode 100644 daq/test_modules/docker_module.py create mode 100644 daq/test_modules/external_module.py rename daq/{ipaddr_test.py => test_modules/ipaddr_module.py} (93%) create mode 100644 daq/test_modules/native_host.py create mode 100644 daq/test_modules/native_module.py delete mode 100644 docker/modules/Dockerfile.test_fail delete mode 100644 docker/modules/Dockerfile.test_pass delete mode 100644 docker/modules/Dockerfile.test_ping delete mode 100644 resources/setups/baseline/module_manifest.json create mode 100644 subset/fail/fail.daqmodule create mode 100644 subset/pass/pass.daqmodule rename subset/pentests/{ => nmap}/Dockerfile.test_nmap (100%) create mode 100644 subset/pentests/nmap/nmap.daqmodule rename subset/pentests/{ => nmap}/test_nmap (86%) create mode 100644 subset/ping/module_manifest.json create mode 100644 subset/ping/ping.daqmodule rename {docker/include/bin => subset/ping}/test_ping (73%) rename subset/security/{module_manifest.json => tls.module_manifest.json} (63%) diff --git a/.stickler.yml b/.stickler.yml index e8a9144f47..3f44024abd 100644 --- a/.stickler.yml +++ b/.stickler.yml @@ -12,3 +12,4 @@ linters: files: ignore: - 'libs/proto/*' + - '*__init__.py' diff --git a/bin/setup_dev b/bin/setup_dev index 01aa1f620d..a7212ed1c3 100755 --- a/bin/setup_dev +++ b/bin/setup_dev @@ -76,7 +76,7 @@ $AG install \ ca-certificates sudo net-tools tcpdump build-essential pango-1.0 \ isc-dhcp-client network-manager netcat gnupg2 strace libffi-dev \ python$PVERSION python3-pkg-resources python3-setuptools \ - python$PVERSION-dev python3-pip python emacs-nox python$PVERSION-venv + python$PVERSION-dev python3-pip python emacs-nox python$PVERSION-venv nmap if [ -d mininet ]; then echo Checking mininet version matches $MININETV... diff --git a/cmd/exrun b/cmd/exrun index c93bdf9d51..7bfeaf39ce 100755 --- a/cmd/exrun +++ b/cmd/exrun @@ -100,10 +100,6 @@ function DAQ { $@ || true } -if [ -z `which ifconfig` ]; then - export PATH=/sbin:$PATH -fi - if [ -n "$switch_setup_ext_br" ]; then autostart bin/external_ovs fi @@ -160,6 +156,14 @@ if [ -d venv ]; then source venv/bin/activate fi +if [ -z `which ifconfig` ]; then + export PATH=/sbin:$PATH +fi + +if [ -z `which tcpdump` ]; then + export PATH=/usr/sbin:$PATH +fi + echo Using python3 at `which python3` echo Executing: $runcmd daq/daq.py $conf_file $@ diff --git a/daq/docker_test.py b/daq/docker_test.py deleted file mode 100644 index 9c678ee10d..0000000000 --- a/daq/docker_test.py +++ /dev/null @@ -1,167 +0,0 @@ -"""Module for running docker-container tests""" - -import datetime -import os -import subprocess -import string -import random - -from base_module import HostModule - -import logger -from clib import docker_host -import wrappers - -LOGGER = logger.get_logger('docker') - - -class DockerTest(HostModule): - """Class for running docker tests""" - - IMAGE_NAME_FORMAT = 'daqf/test_%s' - TAGGED_IMAGE_FORMAT = IMAGE_NAME_FORMAT + ':latest' - CONTAINER_PREFIX = 'daq' - - def __init__(self, host, tmpdir, test_name, module_config): - super().__init__(host, tmpdir, test_name, module_config) - self.docker_log = None - self.docker_host = None - self.pipe = None - - def start(self, port, params, callback, finish_hook): - """Start the docker test""" - super().start(port, params, callback, finish_hook) - - def opt_param(key): - return params.get(key) or '' # Substitute empty string for None - - env_vars = [ - "TARGET_NAME=" + self.host_name, - "TARGET_IP=" + params['target_ip'], - "TARGET_MAC=" + params['target_mac'], - "TARGET_PORT=" + opt_param('target_port'), - "GATEWAY_IP=" + params['gateway_ip'], - "GATEWAY_MAC=" + params['gateway_mac'], - "LOCAL_IP=" + opt_param('local_ip'), - ] - - vol_maps = [params['scan_base'] + ":/scans"] - self._map_if_exists(vol_maps, params, 'inst') - self._map_if_exists(vol_maps, params, 'port') - self._map_if_exists(vol_maps, params, 'device') - self._map_if_exists(vol_maps, params, 'type') - - image = self.IMAGE_NAME_FORMAT % self.test_name - LOGGER.debug("%s running docker test %s", self, image) - cls = docker_host.make_docker_host(image, prefix=self.CONTAINER_PREFIX) - # Work around an instability in the faucet/clib/docker library, b/152520627. - setattr(cls, 'pullImage', self._check_image) - try: - host = self.runner.add_host(self.host_name, port=port, cls=cls, env_vars=env_vars, - vol_maps=vol_maps, tmpdir=self.tmpdir) - self.docker_host = host - except Exception as e: - # pylint: disable=no-member - raise wrappers.DaqException(e) - - try: - LOGGER.debug("%s activating docker test %s", self, image) - pipe = host.activate(log_name=None) - # Docker tests don't use DHCP, so manually set up DNS. - host.cmd('echo nameserver $GATEWAY_IP > /etc/resolv.conf') - self.docker_log = host.open_log() - if self._should_raise_test_exception('initialize'): - LOGGER.error('%s inducing initialization failure', self) - raise Exception('induced initialization failure') - self.runner.monitor_stream(self.host_name, pipe.stdout, copy_to=self.docker_log, - hangup=self._docker_complete, - error=self._docker_error) - self.pipe = pipe - if self._should_raise_test_exception('callback'): - LOGGER.error('%s will induce callback failure', self) - # Closing this now will cause error when attempting to write output. - self.docker_log.close() - except Exception as e: - host.terminate() - self.runner.remove_host(host) - self.docker_host = None - if self.pipe: - self.runner.monitor_forget(self.pipe.stdout) - self.pipe = None - raise e - LOGGER.info("%s running", self) - - def _check_image(self): - lines = subprocess.check_output(["docker", "images", "--format", - "{{ .Repository }}:{{ .Tag }}"]) - expected = self.TAGGED_IMAGE_FORMAT % self.test_name - lines = str(lines, 'utf-8').splitlines() - assert expected in lines, 'Could not find image %s, maybe rebuild images.' % expected - - def terminate(self): - """Forcibly terminate this container""" - LOGGER.info("%s terminating", self) - return self._docker_finalize() - - def _map_if_exists(self, vol_maps, params, kind): - base = params.get('%s_base' % kind) - if base and os.path.exists(base): - abs_base = os.path.abspath(base) - vol_maps += ['%s:/config/%s' % (abs_base, kind)] - LOGGER.info('%s mapping %s to /config/%s', self, abs_base, kind) - - def _docker_error(self, exception): - LOGGER.error('%s docker error: %s', self, str(exception)) - if self._docker_finalize() is None: - LOGGER.warning('%s docker already terminated.', self) - else: - self.callback(exception=exception) - - def _docker_finalize(self): - assert self.docker_host, 'docker host %s already finalized' % self - if self._finish_hook: - self._finish_hook() - self.runner.remove_host(self.docker_host) - if self.pipe: - self.runner.monitor_forget(self.pipe.stdout) - self.pipe = None - return_code = self.docker_host.terminate() - LOGGER.info('%s docker finalize %d', self, return_code) - self.docker_host = None - self.docker_log.close() - self.docker_log = None - if self._should_raise_test_exception('finalize'): - LOGGER.error('%s inducing finalize failure', self) - raise Exception('induced finalize failure') - return return_code - - def _should_raise_test_exception(self, trigger_value): - key = "%s_%s" % (self.test_name, self.device.mac.replace(':', '')) - return self.runner.config.get('fail_module', {}).get(key) == trigger_value - - def _docker_complete(self): - try: - assert self.pipe, 'complete without active pipe' - self.pipe = None - return_code = self._docker_finalize() - exception = None - except Exception as e: - return_code = -1 - exception = e - LOGGER.exception(e) - delay = (datetime.datetime.now() - self.start_time).total_seconds() - LOGGER.debug("%s docker complete, return=%d (%s)", - self, return_code, exception) - if return_code: - LOGGER.info("%s failed %ss: %s %s", - self, delay, return_code, exception) - else: - LOGGER.info("%s passed %ss", - self, delay) - self.callback(return_code=return_code, exception=exception) - - def _get_random_string(self, length): - return ''.join(random.choice(string.ascii_letters) for _ in range(length)) - - def ip_listener(self, target_ip): - """Do nothing b/c docker tests don't care about ip notifications""" diff --git a/daq/host.py b/daq/host.py index c600cb3835..9e8684a5cf 100644 --- a/daq/host.py +++ b/daq/host.py @@ -14,9 +14,8 @@ from proto import usi_pb2_grpc as usi_service import configurator -import docker_test +from test_modules import DockerModule, IpAddrModule, NativeModule import gcp -import ipaddr_test import logger @@ -618,7 +617,20 @@ def _device_aux_path(self): return path def _new_test(self, test_name): - clazz = ipaddr_test.IpAddrTest if test_name == 'ipaddr' else docker_test.DockerTest + if test_name in self.config['test_metadata']: + metadatum = self.config['test_metadata'][test_name] + startup_script = metadatum['startup_script'] + basedir = os.path.abspath(metadatum['basedir']) + new_root = os.path.abspath(os.path.join(self.devdir, 'test_root')) + if os.path.isdir(new_root): + shutil.rmtree(new_root) + os.makedirs(new_root) + for src_file in os.listdir(basedir): + src_full = os.path.join(basedir, src_file) + os.symlink(src_full, os.path.join(new_root, src_file)) + return NativeModule(self, self.devdir, test_name, self._loaded_config, new_root, + startup_script) + clazz = IpAddrModule if test_name == 'ipaddr' else DockerModule return clazz(self, self.devdir, test_name, self._loaded_config) def _run_test(self, test_name): diff --git a/daq/runner.py b/daq/runner.py index 26b5ab3c54..bf7669d4fc 100644 --- a/daq/runner.py +++ b/daq/runner.py @@ -7,6 +7,8 @@ import time import traceback import uuid +import json +import pathlib from datetime import datetime, timedelta, timezone import configurator @@ -167,6 +169,7 @@ def __init__(self, config): LOGGER.info('Appending test_hold to master test list') test_list.append('hold') config['test_list'] = test_list + config['test_metadata'] = self._get_test_metadata() LOGGER.info('DAQ RUN id: %s' % self.daq_run_id) LOGGER.info('Configured with tests %s' % ', '.join(config['test_list'])) LOGGER.info('DAQ version %s' % self._daq_version) @@ -527,6 +530,22 @@ def _get_test_list(self, test_file, test_list): line = file.readline() return test_list + def _get_test_metadata(self, extension=".daqmodule", root="."): + metadata = {} + for meta_file in pathlib.Path(root).glob('**/*%s' % extension): + if str(meta_file).startswith('inst') or str(meta_file).startswith('local'): + continue + with open(meta_file) as fd: + metadatum = json.loads(fd.read()) + assert "name" in metadatum and "startup_script" in metadatum + module = metadatum["name"] + assert module not in metadata, "Duplicate module definition for %s" % module + metadata[module] = { + "startup_script": metadatum["startup_script"], + "basedir": meta_file.parent + } + return metadata + def _activate_device_group(self, device): group_name = device.group group_devices = self._devices.get_by_group(group_name) diff --git a/daq/test_modules/__init__.py b/daq/test_modules/__init__.py new file mode 100644 index 0000000000..7e2f353561 --- /dev/null +++ b/daq/test_modules/__init__.py @@ -0,0 +1,4 @@ +"""Device Automated Qualification test module""" +from .ipaddr_module import IpAddrModule +from .docker_module import DockerModule +from .native_module import NativeModule diff --git a/daq/base_module.py b/daq/test_modules/base_module.py similarity index 90% rename from daq/base_module.py rename to daq/test_modules/base_module.py index fcc5232320..7a68efef09 100644 --- a/daq/base_module.py +++ b/daq/test_modules/base_module.py @@ -3,13 +3,14 @@ from __future__ import absolute_import import datetime +from abc import ABC import logger LOGGER = logger.get_logger('module') -class HostModule: +class HostModule(ABC): """Base class for host test modules""" def __init__(self, host, tmpdir, test_name, module_config): @@ -38,5 +39,8 @@ def start(self, port, params, callback, finish_hook): self._finish_hook = finish_hook self.start_time = datetime.datetime.now() + def ip_listener(self, target_ip): + """Defaults to do nothing about ip notifications""" + def __repr__(self): return "Target device %s test %s" % (self.device, self.test_name) diff --git a/daq/test_modules/docker_module.py b/daq/test_modules/docker_module.py new file mode 100644 index 0000000000..99b1f36717 --- /dev/null +++ b/daq/test_modules/docker_module.py @@ -0,0 +1,50 @@ +"""Module for running docker-container modules""" +from __future__ import absolute_import + +import subprocess +import logger +from clib import docker_host + +from .external_module import ExternalModule + + +LOGGER = logger.get_logger('docker') + + +class DockerModule(ExternalModule): + """Class for running docker modules""" + + IMAGE_NAME_FORMAT = 'daqf/test_%s' + TAGGED_IMAGE_FORMAT = IMAGE_NAME_FORMAT + ':latest' + CONTAINER_PREFIX = 'daq' + + def start(self, port, params, callback, finish_hook): + """Start the docker module""" + super().start(port, params, callback, finish_hook) + LOGGER.debug("%s activating docker test %s", self) + # Docker modules don't use DHCP, so manually set up DNS. + if self.host: + self.host.cmd('echo nameserver $GATEWAY_IP > /etc/resolv.conf') + + def _get_env_vars(self, params): + env_vars = super()._get_env_vars(params) + return ["%s=%s" % var for var in env_vars] + + def _get_vol_maps(self, params): + vol_maps = super()._get_vol_maps(params) + return ["%s:%s" % vol_map for vol_map in vol_maps] + + def _get_module_class(self): + image = self.IMAGE_NAME_FORMAT % self.test_name + LOGGER.debug("%s running docker test %s", self, image) + cls = docker_host.make_docker_host(image, prefix=self.CONTAINER_PREFIX) + # Work around an instability in the faucet/clib/docker library, b/152520627. + setattr(cls, 'pullImage', self._check_image) + return cls + + def _check_image(self): + lines = subprocess.check_output(["docker", "images", "--format", + "{{ .Repository }}:{{ .Tag }}"]) + expected = self.TAGGED_IMAGE_FORMAT % self.test_name + lines = str(lines, 'utf-8').splitlines() + assert expected in lines, 'Could not find image %s, maybe rebuild images.' % expected diff --git a/daq/test_modules/external_module.py b/daq/test_modules/external_module.py new file mode 100644 index 0000000000..d7789a41eb --- /dev/null +++ b/daq/test_modules/external_module.py @@ -0,0 +1,155 @@ +"""Class for running non inline modules""" +from __future__ import absolute_import + +import datetime +import abc +import os + +import logger +import wrappers + +from .base_module import HostModule + + +LOGGER = logger.get_logger('external_module') + + +class ExternalModule(HostModule): + """Class for running non inline modules""" + + # pylint: disable=too-many-arguments + def __init__(self, host, tmpdir, test_name, module_config, basedir="/"): + super().__init__(host, tmpdir, test_name, module_config) + self.log = None + self.host = None + self.pipe = None + self.basedir = basedir + + @abc.abstractmethod + def _get_module_class(self): + pass + + def start(self, port, params, callback, finish_hook): + """Start the external module""" + super().start(port, params, callback, finish_hook) + cls = self._get_module_class() + env_vars = self._get_env_vars(params) + vol_maps = self._get_vol_maps(params) + + try: + host = self.runner.add_host(self.host_name, port=port, cls=cls, env_vars=env_vars, + vol_maps=vol_maps, tmpdir=self.tmpdir) + self.host = host + except Exception as e: + # pylint: disable=no-member + raise wrappers.DaqException(e) + + try: + pipe = host.activate(log_name=None) + self.log = host.open_log() + if self._should_raise_test_exception('initialize'): + LOGGER.error('%s inducing initialization failure', self) + raise Exception('induced initialization failure') + self.runner.monitor_stream(self.host_name, pipe.stdout, copy_to=self.log, + hangup=self._complete, + error=self._error) + self.pipe = pipe + if self._should_raise_test_exception('callback'): + LOGGER.error('%s will induce callback failure', self) + # Closing this now will cause error when attempting to write output. + self.log.close() + except Exception as e: + host.terminate() + self.runner.remove_host(host) + self.host = None + if self.pipe: + self.runner.monitor_forget(self.pipe.stdout) + self.pipe = None + raise e + LOGGER.info("%s running", self) + + def terminate(self): + """Forcibly terminate this module""" + LOGGER.info("%s terminating", self) + return self._finalize() + + def _get_env_vars(self, params): + def opt_param(key): + return params.get(key) or '' # Substitute empty string for None + + env_vars = [ + ("TARGET_NAME", self.host_name), + ("TARGET_IP", params['target_ip']), + ("TARGET_MAC", params['target_mac']), + ("TARGET_PORT", opt_param('target_port')), + ("GATEWAY_IP", params['gateway_ip']), + ("GATEWAY_MAC", params['gateway_mac']), + ("LOCAL_IP", opt_param('local_ip')), + ] + return env_vars + + def _get_vol_maps(self, params): + vol_maps = [(params['scan_base'], os.path.join(self.basedir, "scans"))] + kinds = ('inst', 'port', 'device', 'type') + maps = list(map(lambda kind: self._map_if_exists(params, kind), kinds)) + vol_maps.extend(filter(lambda vol_map: vol_map, maps)) + return vol_maps + + def _map_if_exists(self, params, kind): + base = params.get('%s_base' % kind) + if base and os.path.exists(base): + abs_base = os.path.abspath(base) + dst = os.path.join(self.basedir, 'config', kind) + LOGGER.info('%s mapping %s to %s', self, abs_base, dst) + return (abs_base, dst) + return None + + def _error(self, exception): + LOGGER.error('%s test host error: %s', self, str(exception)) + if self._finalize() is None: + LOGGER.warning('%s already terminated.', self) + else: + self.callback(exception=exception) + + def _finalize(self): + assert self.host, 'test host %s already finalized' % self + if self._finish_hook: + self._finish_hook() + self.runner.remove_host(self.host) + if self.pipe: + self.runner.monitor_forget(self.pipe.stdout) + self.pipe = None + return_code = self.host.terminate() + LOGGER.info('%s test host finalize %s', self, return_code) + self.host = None + self.log.close() + self.log = None + if self._should_raise_test_exception('finalize'): + LOGGER.error('%s inducing finalize failure', self) + raise Exception('induced finalize failure') + return return_code + + def _should_raise_test_exception(self, trigger_value): + key = "%s_%s" % (self.test_name, self.device.mac.replace(':', '')) + return self.runner.config.get('fail_module', {}).get(key) == trigger_value + + def _complete(self): + try: + assert self.pipe, 'complete without active pipe' + self.pipe = None + return_code = self._finalize() + exception = None + except Exception as e: + return_code = -1 + exception = e + LOGGER.exception(e) + delay = (datetime.datetime.now() - self.start_time).total_seconds() + LOGGER.debug("%s test host complete, return=%d (%s)", + self, return_code, exception) + if return_code: + LOGGER.info("%s failed %ss: %s %s", + self, delay, return_code, exception) + else: + LOGGER.info("%s passed %ss", + self, delay) + self.callback(return_code=return_code, exception=exception) diff --git a/daq/ipaddr_test.py b/daq/test_modules/ipaddr_module.py similarity index 93% rename from daq/ipaddr_test.py rename to daq/test_modules/ipaddr_module.py index 76327441a2..04369a311c 100644 --- a/daq/ipaddr_test.py +++ b/daq/test_modules/ipaddr_module.py @@ -7,18 +7,18 @@ import os import copy import logger -import docker_test +from .docker_module import DockerModule -from base_module import HostModule +from .base_module import HostModule _LOG_FORMAT = "%(asctime)s %(levelname)-7s %(message)s" -class IpAddrTest(HostModule): +class IpAddrModule(HostModule): """Module for inline ipaddr tests""" def __init__(self, host, tmpdir, test_name, module_config): super().__init__(host, tmpdir, test_name, module_config) - self.docker_host = docker_test.DockerTest(host, tmpdir, test_name, module_config) + self.docker_host = DockerModule(host, tmpdir, test_name, module_config) self.test_dhcp_ranges = copy.copy(self.test_config.get('dhcp_ranges', [])) self._ip_callback = None self.tests = [ @@ -54,7 +54,7 @@ def _next_test(self): def _dhcp_port_toggle_test(self): if not self.host.connect_port(False): - self.log('disconnect port not enabled') + self._logger('disconnect port not enabled') return time.sleep(self.host.config.get("port_debounce_sec", 0) + 1) self.host.connect_port(True) diff --git a/daq/test_modules/native_host.py b/daq/test_modules/native_host.py new file mode 100644 index 0000000000..1d3b5203bc --- /dev/null +++ b/daq/test_modules/native_host.py @@ -0,0 +1,103 @@ +"""A native module mininet host""" +from __future__ import absolute_import + +import os +from subprocess import PIPE, STDOUT + +# pylint: disable=import-error +# pylint: disable=no-name-in-module +from mininet.log import debug +from mininet.node import Host + +from clib.mininet_test_util import DEVNULL + +STARTUP_TIMEOUT_MS = 20000 + + +class NativeHost(Host): + """Mininet host that encapsulates a shell""" + + # pylint: disable=too-many-arguments + def __init__(self, name, basedir=None, tmpdir=None, env_vars=None, vol_maps=None, + startup_script='entrypoint', **kwargs): + self.basedir = basedir + self.tmpdir = tmpdir + self.env_vars = env_vars if env_vars is not None else [] + self.vol_maps = vol_maps if vol_maps is not None else [] + self.vol_maps.append((os.path.abspath(os.path.join(self.tmpdir, 'tmp')), + os.path.join(self.basedir, 'tmp'))) + self.name = name + script_full_path = os.path.join(self.basedir, startup_script) + self.startup_script = startup_script if startup_script.startswith('/') else script_full_path + self.active_pipe = None + self.active_log = None + Host.__init__(self, name, **kwargs) + + def open_log(self, log_name='activate.log'): + """Open a log file for writing and return it.""" + return open(os.path.join(self.tmpdir, log_name), 'w') + + def activate(self, log_name='activate.log'): + """Active a container and return STDOUT to it.""" + assert not self.active_pipe, '%s already activated' % self.name + + env = dict(self.env_vars) + self.cmd('mkdir %s' % os.path.join(self.basedir, "config")) + + for vol_map in self.vol_maps: + self.cmd('ln -s %s %s' % vol_map) + if log_name: + stdout = self.open_log(log_name) + self.active_log = stdout + else: + stdout = PIPE + self.active_log = None + + self.active_pipe = self.popen(self.startup_script, stdin=DEVNULL, stdout=stdout, + stderr=STDOUT, env=env) + pipe_out = self.active_pipe.stdout + out_fd = pipe_out.fileno() if pipe_out else None + debug('Active_pipe container pid %s fd %s' % + (self.active_pipe.pid, out_fd)) + return self.active_pipe + + def terminate(self): + """Override Mininet terminate() to partially avoid pty leak.""" + for vol_map in self.vol_maps: + self.cmd('rm -f %s' % vol_map[1]) + self.cmd('rm -r %s' % os.path.join(self.basedir, 'config')) + + debug('Terminating container shell %s, pipe %s' % ( + self.shell, self.active_pipe)) + active_pipe_returncode = None + if self.active_pipe: + if self.active_pipe.stdout: + self.active_pipe.stdout.close() + if self.active_pipe.returncode is None: + self.active_pipe.kill() + self.active_pipe.poll() + # return code can still be None here + active_pipe_returncode = self.active_pipe.returncode or 0 + self.active_pipe = None + if self.active_log: + self.active_log.close() + self.active_log = None + super().terminate() + return active_pipe_returncode + + +def make_native_host(basedir, startup_script): + """Utility function to create a native-host class that can be passed to mininet""" + + class _NativeHost(NativeHost): + """Internal class that represents a native host""" + + def __init__(self, *args, **kwargs): + host_name = args[0] + assert kwargs['tmpdir'], 'tmpdir required for native host' + kwargs['tmpdir'] = os.path.join(kwargs['tmpdir'], host_name) + kwargs['basedir'] = basedir + kwargs['startup_script'] = startup_script + super(_NativeHost, self).__init__(*args, **kwargs) + + return _NativeHost diff --git a/daq/test_modules/native_module.py b/daq/test_modules/native_module.py new file mode 100644 index 0000000000..892e5a5431 --- /dev/null +++ b/daq/test_modules/native_module.py @@ -0,0 +1,43 @@ +"""Module for running docker-container tests""" +from __future__ import absolute_import + +import os +import logger + +from .native_host import make_native_host +from .external_module import ExternalModule + + +LOGGER = logger.get_logger('docker') + + +class NativeModule(ExternalModule): + """Class for running native tests""" + + # pylint: disable=too-many-arguments + def __init__(self, host, tmpdir, test_name, module_config, basedir, startup_script): + super().__init__(host, tmpdir, test_name, module_config, basedir=basedir) + self.startup_script = startup_script + + def start(self, port, params, callback, finish_hook): + """Start the native test""" + super().start(port, params, callback, finish_hook) + LOGGER.debug("activating native test %s", self) + + def _get_env_vars(self, params): + env_vars = super()._get_env_vars(params) + env_vars.append(('TEST_ROOT', self.basedir)) + return env_vars + + def _get_vol_maps(self, params): + vol_maps = super()._get_vol_maps(params) + + # Common testing tools + vol_maps.append((os.path.abspath('bin/retry_cmd'), '/bin/retry_cmd')) + vol_maps.append((os.path.abspath('docker/include/utils/reporting.sh'), + os.path.join(self.basedir, 'reporting.sh'))) + return vol_maps + + def _get_module_class(self): + LOGGER.debug("%s running native test %s", self, self.test_name) + return make_native_host(self.basedir, self.startup_script) diff --git a/docker/modules/Dockerfile.test_fail b/docker/modules/Dockerfile.test_fail deleted file mode 100644 index 17cf4e6bd5..0000000000 --- a/docker/modules/Dockerfile.test_fail +++ /dev/null @@ -1,4 +0,0 @@ -FROM daqf/aardvark:latest - -CMD false - diff --git a/docker/modules/Dockerfile.test_pass b/docker/modules/Dockerfile.test_pass deleted file mode 100644 index 7e1bf80235..0000000000 --- a/docker/modules/Dockerfile.test_pass +++ /dev/null @@ -1,4 +0,0 @@ -FROM daqf/aardvark:latest - -CMD true - diff --git a/docker/modules/Dockerfile.test_ping b/docker/modules/Dockerfile.test_ping deleted file mode 100644 index 3baf9a10aa..0000000000 --- a/docker/modules/Dockerfile.test_ping +++ /dev/null @@ -1,8 +0,0 @@ -FROM daqf/aardvark:latest - -RUN $AG update && $AG install netcat - -COPY resources/setups/baseline/module_manifest.json . -COPY docker/include/bin/test_ping . - -CMD ./test_ping diff --git a/docs/device_report.md b/docs/device_report.md index 83c4ff8fa4..91b32d6ed0 100644 --- a/docs/device_report.md +++ b/docs/device_report.md @@ -159,7 +159,7 @@ security.nmap.ports -------------------- Automatic TCP/UDP port scan using nmap -------------------- -# Nmap 7.60 scan initiated XXX as: nmap -v -n -T5 -sT -sU --host-timeout=4m --open -pU:47808,T:23,443,80, -oG /tmp/nmap.log X.X.X.X +# Nmap XXX scan initiated XXX as: nmap -v -n -T5 -sT -sU --host-timeout=4m --open -pU:47808,T:23,443,80, -oG XXX/tmp/nmap.log X.X.X.X # Ports scanned: TCP(3;23,80,443) UDP(1;47808) SCTP(0;) PROTOCOLS(0;) Host: X.X.X.X () Status: Up Host: X.X.X.X () Ports: 47808/closed/udp//bacnet/// @@ -173,7 +173,7 @@ security.nmap.http -------------------- Check that the device does not have open ports exposing an unencrypted web interface using HTTP -------------------- -# Nmap 7.60 scan initiated XXX as: nmap -v -n -T5 -A --script http-methods --host-timeout=4m --open -p- -oG /tmp/http.log X.X.X.X +# Nmap XXX scan initiated XXX as: nmap -v -n -T5 -A --script http-methods --host-timeout=4m --open -p- -oG XXX/tmp/http.log X.X.X.X # Ports scanned: TCP(65535;1-65535) UDP(0;) SCTP(0;) PROTOCOLS(0;) Host: X.X.X.X () Status: Up Host: X.X.X.X () Ports: 10000/open/tcp//snet-sensor-mgmt?/// diff --git a/firebase/public/protos.hash b/firebase/public/protos.hash index 4ddf9485f8..b3f399d5be 100644 --- a/firebase/public/protos.hash +++ b/firebase/public/protos.hash @@ -1 +1 @@ -f76de649c75ed722febfc0750c53672f22af5ab1 proto/system_config.proto +12f895d37a4ea85e15100a3edfcad250bdb001bd proto/system_config.proto diff --git a/firebase/public/protos.html b/firebase/public/protos.html index f4cf44b2e7..9b254ac69c 100644 --- a/firebase/public/protos.html +++ b/firebase/public/protos.html @@ -507,6 +507,13 @@

      DaqConfig

      verbose output

      + + use_console + bool + +

      Drop into console mode after test

      + + diff --git a/libs/proto/system_config_pb2.py b/libs/proto/system_config_pb2.py index f2784ab726..c8e7206997 100644 --- a/libs/proto/system_config_pb2.py +++ b/libs/proto/system_config_pb2.py @@ -20,7 +20,7 @@ package='', syntax='proto3', serialized_options=None, - serialized_pb=_b('\n\x1d\x64\x61q/proto/system_config.proto\"\xdc\x08\n\tDaqConfig\x12\x18\n\x10site_description\x18\x01 \x01(\t\x12\x18\n\x10monitor_scan_sec\x18\x02 \x01(\x05\x12\x1b\n\x13\x64\x65\x66\x61ult_timeout_sec\x18\x03 \x01(\x05\x12\x12\n\nsettle_sec\x18& \x01(\x05\x12\x11\n\tbase_conf\x18\x04 \x01(\t\x12\x11\n\tsite_path\x18\x05 \x01(\t\x12\x1f\n\x17initial_dhcp_lease_time\x18\x06 \x01(\t\x12\x17\n\x0f\x64hcp_lease_time\x18\x07 \x01(\t\x12\x19\n\x11\x64hcp_response_sec\x18\' \x01(\x05\x12\x1e\n\x16long_dhcp_response_sec\x18\x08 \x01(\x05\x12\"\n\x0cswitch_setup\x18\t \x01(\x0b\x32\x0c.SwitchSetup\x12\x12\n\nhost_tests\x18\x10 \x01(\t\x12\x13\n\x0b\x62uild_tests\x18$ \x01(\x08\x12\x11\n\trun_limit\x18\x11 \x01(\x05\x12\x11\n\tfail_mode\x18\x12 \x01(\x08\x12\x13\n\x0bsingle_shot\x18\" \x01(\x08\x12\x15\n\rresult_linger\x18\x13 \x01(\x08\x12\x0f\n\x07no_test\x18\x14 \x01(\x08\x12\x11\n\tkeep_hold\x18( \x01(\x08\x12\x14\n\x0c\x64\x61q_loglevel\x18\x15 \x01(\t\x12\x18\n\x10mininet_loglevel\x18\x16 \x01(\t\x12\x13\n\x0b\x66inish_hook\x18# \x01(\t\x12\x10\n\x08gcp_cred\x18\x17 \x01(\t\x12\x11\n\tgcp_topic\x18\x18 \x01(\t\x12\x13\n\x0bschema_path\x18\x19 \x01(\t\x12\x11\n\tmud_files\x18\x1a \x01(\t\x12\x14\n\x0c\x64\x65vice_specs\x18\x1b \x01(\t\x12\x13\n\x0btest_config\x18\x1c \x01(\t\x12\x19\n\x11port_debounce_sec\x18\x1d \x01(\x05\x12\x15\n\rtopology_hook\x18\x1e \x01(\t\x12\x17\n\x0f\x64\x65vice_template\x18\x1f \x01(\t\x12\x14\n\x0csite_reports\x18 \x01(\t\x12\x1f\n\x17run_data_retention_days\x18! \x01(\x02\x12.\n\ninterfaces\x18% \x03(\x0b\x32\x1a.DaqConfig.InterfacesEntry\x12/\n\x0b\x66\x61il_module\x18/ \x03(\x0b\x32\x1a.DaqConfig.FailModuleEntry\x12\x1d\n\x15port_flap_timeout_sec\x18\x30 \x01(\x05\x12\x1c\n\tusi_setup\x18\x31 \x01(\x0b\x32\t.USISetup\x12)\n\x10run_trigger_type\x18\x32 \x01(\x0e\x32\x0f.RunTriggerType\x12\x12\n\ndebug_mode\x18\x33 \x01(\x08\x1a=\n\x0fInterfacesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x19\n\x05value\x18\x02 \x01(\x0b\x32\n.Interface:\x02\x38\x01\x1a\x31\n\x0f\x46\x61ilModuleEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"0\n\x08USISetup\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x17\n\x0frpc_timeout_sec\x18\x02 \x01(\x05\"\xf4\x01\n\x0bSwitchSetup\x12\x11\n\tctrl_intf\x18\t \x01(\t\x12\x0f\n\x07ip_addr\x18\x0b \x01(\t\x12\x13\n\x0buplink_port\x18\r \x01(\x05\x12\x0f\n\x07lo_port\x18\x0e \x01(\x05\x12\x10\n\x08\x61lt_port\x18\x10 \x01(\x05\x12\x0f\n\x07lo_addr\x18\x12 \x01(\t\x12\x11\n\tmods_addr\x18\x14 \x01(\t\x12\x0f\n\x07of_dpid\x18) \x01(\t\x12\x11\n\tdata_intf\x18* \x01(\t\x12\x0e\n\x06\x65xt_br\x18+ \x01(\t\x12\r\n\x05model\x18, \x01(\t\x12\x10\n\x08username\x18- \x01(\t\x12\x10\n\x08password\x18. \x01(\t\"\'\n\tInterface\x12\x0c\n\x04opts\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05*$\n\x0eRunTriggerType\x12\x08\n\x04PORT\x10\x00\x12\x08\n\x04VLAN\x10\x01\x62\x06proto3') + serialized_pb=_b('\n\x1d\x64\x61q/proto/system_config.proto\"\xf1\x08\n\tDaqConfig\x12\x18\n\x10site_description\x18\x01 \x01(\t\x12\x18\n\x10monitor_scan_sec\x18\x02 \x01(\x05\x12\x1b\n\x13\x64\x65\x66\x61ult_timeout_sec\x18\x03 \x01(\x05\x12\x12\n\nsettle_sec\x18& \x01(\x05\x12\x11\n\tbase_conf\x18\x04 \x01(\t\x12\x11\n\tsite_path\x18\x05 \x01(\t\x12\x1f\n\x17initial_dhcp_lease_time\x18\x06 \x01(\t\x12\x17\n\x0f\x64hcp_lease_time\x18\x07 \x01(\t\x12\x19\n\x11\x64hcp_response_sec\x18\' \x01(\x05\x12\x1e\n\x16long_dhcp_response_sec\x18\x08 \x01(\x05\x12\"\n\x0cswitch_setup\x18\t \x01(\x0b\x32\x0c.SwitchSetup\x12\x12\n\nhost_tests\x18\x10 \x01(\t\x12\x13\n\x0b\x62uild_tests\x18$ \x01(\x08\x12\x11\n\trun_limit\x18\x11 \x01(\x05\x12\x11\n\tfail_mode\x18\x12 \x01(\x08\x12\x13\n\x0bsingle_shot\x18\" \x01(\x08\x12\x15\n\rresult_linger\x18\x13 \x01(\x08\x12\x0f\n\x07no_test\x18\x14 \x01(\x08\x12\x11\n\tkeep_hold\x18( \x01(\x08\x12\x14\n\x0c\x64\x61q_loglevel\x18\x15 \x01(\t\x12\x18\n\x10mininet_loglevel\x18\x16 \x01(\t\x12\x13\n\x0b\x66inish_hook\x18# \x01(\t\x12\x10\n\x08gcp_cred\x18\x17 \x01(\t\x12\x11\n\tgcp_topic\x18\x18 \x01(\t\x12\x13\n\x0bschema_path\x18\x19 \x01(\t\x12\x11\n\tmud_files\x18\x1a \x01(\t\x12\x14\n\x0c\x64\x65vice_specs\x18\x1b \x01(\t\x12\x13\n\x0btest_config\x18\x1c \x01(\t\x12\x19\n\x11port_debounce_sec\x18\x1d \x01(\x05\x12\x15\n\rtopology_hook\x18\x1e \x01(\t\x12\x17\n\x0f\x64\x65vice_template\x18\x1f \x01(\t\x12\x14\n\x0csite_reports\x18 \x01(\t\x12\x1f\n\x17run_data_retention_days\x18! \x01(\x02\x12.\n\ninterfaces\x18% \x03(\x0b\x32\x1a.DaqConfig.InterfacesEntry\x12/\n\x0b\x66\x61il_module\x18/ \x03(\x0b\x32\x1a.DaqConfig.FailModuleEntry\x12\x1d\n\x15port_flap_timeout_sec\x18\x30 \x01(\x05\x12\x1c\n\tusi_setup\x18\x31 \x01(\x0b\x32\t.USISetup\x12)\n\x10run_trigger_type\x18\x32 \x01(\x0e\x32\x0f.RunTriggerType\x12\x12\n\ndebug_mode\x18\x33 \x01(\x08\x12\x13\n\x0buse_console\x18\x34 \x01(\x08\x1a=\n\x0fInterfacesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x19\n\x05value\x18\x02 \x01(\x0b\x32\n.Interface:\x02\x38\x01\x1a\x31\n\x0f\x46\x61ilModuleEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"0\n\x08USISetup\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x17\n\x0frpc_timeout_sec\x18\x02 \x01(\x05\"\xf4\x01\n\x0bSwitchSetup\x12\x11\n\tctrl_intf\x18\t \x01(\t\x12\x0f\n\x07ip_addr\x18\x0b \x01(\t\x12\x13\n\x0buplink_port\x18\r \x01(\x05\x12\x0f\n\x07lo_port\x18\x0e \x01(\x05\x12\x10\n\x08\x61lt_port\x18\x10 \x01(\x05\x12\x0f\n\x07lo_addr\x18\x12 \x01(\t\x12\x11\n\tmods_addr\x18\x14 \x01(\t\x12\x0f\n\x07of_dpid\x18) \x01(\t\x12\x11\n\tdata_intf\x18* \x01(\t\x12\x0e\n\x06\x65xt_br\x18+ \x01(\t\x12\r\n\x05model\x18, \x01(\t\x12\x10\n\x08username\x18- \x01(\t\x12\x10\n\x08password\x18. \x01(\t\"\'\n\tInterface\x12\x0c\n\x04opts\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05*$\n\x0eRunTriggerType\x12\x08\n\x04PORT\x10\x00\x12\x08\n\x04VLAN\x10\x01\x62\x06proto3') ) _RUNTRIGGERTYPE = _descriptor.EnumDescriptor( @@ -40,8 +40,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=1490, - serialized_end=1526, + serialized_start=1511, + serialized_end=1547, ) _sym_db.RegisterEnumDescriptor(_RUNTRIGGERTYPE) @@ -84,8 +84,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1038, - serialized_end=1099, + serialized_start=1059, + serialized_end=1120, ) _DAQCONFIG_FAILMODULEENTRY = _descriptor.Descriptor( @@ -121,8 +121,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1101, - serialized_end=1150, + serialized_start=1122, + serialized_end=1171, ) _DAQCONFIG = _descriptor.Descriptor( @@ -405,6 +405,13 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='use_console', full_name='DaqConfig.use_console', index=39, + number=52, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], @@ -418,7 +425,7 @@ oneofs=[ ], serialized_start=34, - serialized_end=1150, + serialized_end=1171, ) @@ -455,8 +462,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1152, - serialized_end=1200, + serialized_start=1173, + serialized_end=1221, ) @@ -570,8 +577,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1203, - serialized_end=1447, + serialized_start=1224, + serialized_end=1468, ) @@ -608,8 +615,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1449, - serialized_end=1488, + serialized_start=1470, + serialized_end=1509, ) _DAQCONFIG_INTERFACESENTRY.fields_by_name['value'].message_type = _INTERFACE diff --git a/proto/system_config.proto b/proto/system_config.proto index 966a5b780a..16e8316f6f 100644 --- a/proto/system_config.proto +++ b/proto/system_config.proto @@ -123,6 +123,9 @@ message DaqConfig { // verbose output bool debug_mode = 51; + + // Drop into console mode after test + bool use_console = 52; } enum RunTriggerType { diff --git a/resources/runtime_configs/discover/port-01/ping_runtime.sh b/resources/runtime_configs/discover/port-01/ping_runtime.sh index 93a15f8df7..553e2306a8 100644 --- a/resources/runtime_configs/discover/port-01/ping_runtime.sh +++ b/resources/runtime_configs/discover/port-01/ping_runtime.sh @@ -1,4 +1,4 @@ filter="ether host 9a:02:57:1e:8f:02 and port 47808" -count=$(tcpdump -en -r /scans/monitor.pcap $filter | wc -l) +count=$(tcpdump -en -r $TEST_ROOT/scans/monitor.pcap $filter | wc -l) echo Found $count from $filter [ $count -gt 0 ] diff --git a/resources/runtime_configs/discover/port-02/ping_runtime.sh b/resources/runtime_configs/discover/port-02/ping_runtime.sh index 1326688463..399750d148 100644 --- a/resources/runtime_configs/discover/port-02/ping_runtime.sh +++ b/resources/runtime_configs/discover/port-02/ping_runtime.sh @@ -1,4 +1,4 @@ filter="ether host 9a:02:57:1e:8f:03 and port 47808" -count=$(tcpdump -en -r /scans/monitor.pcap $filter | wc -l) +count=$(tcpdump -en -r $TEST_ROOT/scans/monitor.pcap $filter | wc -l) echo Found $count from $filter [ $count -gt 0 ] diff --git a/resources/runtime_configs/long_wait/port-03/ping_runtime.sh b/resources/runtime_configs/long_wait/port-03/ping_runtime.sh index 1c4c67be59..9890859583 100644 --- a/resources/runtime_configs/long_wait/port-03/ping_runtime.sh +++ b/resources/runtime_configs/long_wait/port-03/ping_runtime.sh @@ -1,4 +1,4 @@ # Used for testing of device and type customization mappings in test_aux.sh echo Copying lizard and snake to tmp... -cp /config/type/lizard.txt /tmp/ -cp /config/device/snake.txt /tmp/ +cp $TEST_ROOT/config/type/lizard.txt $TEST_ROOT/tmp/ +cp $TEST_ROOT/config/device/snake.txt $TEST_ROOT/tmp/ diff --git a/resources/setups/baseline/module_manifest.json b/resources/setups/baseline/module_manifest.json deleted file mode 100644 index 8305cd8afd..0000000000 --- a/resources/setups/baseline/module_manifest.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "base.startup.dhcp" : { - "description" : "Check the base DHCP startup exchange" - }, - "base.switch.ping" : { - "description" : "Attempt to ping access switch (if configured)" - }, - "base.target.ping" : { - "description" : "Attempt to ping the Device Under Test" - } -} diff --git a/subset/fail/fail.daqmodule b/subset/fail/fail.daqmodule new file mode 100644 index 0000000000..9d0c04be50 --- /dev/null +++ b/subset/fail/fail.daqmodule @@ -0,0 +1,4 @@ +{ + "name": "fail", + "startup_script": "/bin/false" +} diff --git a/subset/pass/pass.daqmodule b/subset/pass/pass.daqmodule new file mode 100644 index 0000000000..f2f2c553a4 --- /dev/null +++ b/subset/pass/pass.daqmodule @@ -0,0 +1,4 @@ +{ + "name": "pass", + "startup_script": "/bin/true" +} diff --git a/subset/pentests/Dockerfile.test_nmap b/subset/pentests/nmap/Dockerfile.test_nmap similarity index 100% rename from subset/pentests/Dockerfile.test_nmap rename to subset/pentests/nmap/Dockerfile.test_nmap diff --git a/subset/pentests/nmap/nmap.daqmodule b/subset/pentests/nmap/nmap.daqmodule new file mode 100644 index 0000000000..6e4e5de92f --- /dev/null +++ b/subset/pentests/nmap/nmap.daqmodule @@ -0,0 +1,4 @@ +{ + "name": "nmap", + "startup_script": "test_nmap" +} diff --git a/subset/pentests/test_nmap b/subset/pentests/nmap/test_nmap similarity index 86% rename from subset/pentests/test_nmap rename to subset/pentests/nmap/test_nmap index 06159d0b21..7e7d7347f4 100755 --- a/subset/pentests/test_nmap +++ b/subset/pentests/nmap/test_nmap @@ -1,23 +1,23 @@ #!/bin/bash -e -source reporting.sh -CONFIG=/config/device/module_config.json -REPORT=/tmp/report.txt +source $TEST_ROOT/reporting.sh +CONFIG=$TEST_ROOT/config/device/module_config.json +REPORT=$TEST_ROOT/tmp/report.txt # security.nmap.ports test variables -REPORT_NMAP=/tmp/report_nmap.txt -LOG_NMAP=/tmp/nmap.log -OPENPORTSLIST_LOG_NMAP=/tmp/nmap.ports.log -REDACTED_LOG_NMAP=/tmp/nmap.report.log +REPORT_NMAP=$TEST_ROOT/tmp/report_nmap.txt +LOG_NMAP=$TEST_ROOT/tmp/nmap.log +OPENPORTSLIST_LOG_NMAP=$TEST_ROOT/tmp/nmap.ports.log +REDACTED_LOG_NMAP=$TEST_ROOT/tmp/nmap.report.log TEST_NAME_NMAP="security.nmap.ports" TEST_DESCRIPTION_NMAP="Automatic TCP/UDP port scan using nmap" SUMMARY_NMAP="" # security.nmap.http test variables -REPORT_HTTP=/tmp/report_http.txt -LOG_HTTP=/tmp/http.log -OPENPORTSLIST_LOG_HTTP=/tmp/http.ports.log -REDACTED_LOG_HTTP=/tmp/http.report.log +REPORT_HTTP=$TEST_ROOT/tmp/report_http.txt +LOG_HTTP=$TEST_ROOT/tmp/http.log +OPENPORTSLIST_LOG_HTTP=$TEST_ROOT/tmp/http.ports.log +REDACTED_LOG_HTTP=$TEST_ROOT/tmp/http.report.log TEST_NAME_HTTP="security.nmap.http" TEST_DESCRIPTION_HTTP="Check that the device does not have open ports exposing an unencrypted web interface using HTTP" SUMMARY_HTTP="" @@ -75,7 +75,7 @@ touch $REDACTED_LOG_NMAP cat $LOG_NMAP | tee -a $REDACTED_LOG_NMAP touch $REPORT_NMAP touch $OPENPORTSLIST_LOG_NMAP -rm -f .fail +rm -f $TEST_ROOT/.fail grep -oh '[0-9]*/open[^[:space:]]*' $LOG_NMAP | while IFS=/ read -ra parts; do state=${parts[1]} if [ "$state" == open ]; then @@ -84,7 +84,7 @@ grep -oh '[0-9]*/open[^[:space:]]*' $LOG_NMAP | while IFS=/ read -ra parts; do proto=${parts[2]} allowed=$(jq ".servers.$proto.ports.\"$port\".allowed" $CONFIG) if [ "$allowed" != true ]; then - touch .fail + touch $TEST_ROOT/.fail echo Failing ${parts[*]} | sed 's/,$//' | tee -a $REDACTED_LOG_NMAP echo -n ${parts[0]}"," | tee -a $OPENPORTSLIST_LOG_NMAP else @@ -93,12 +93,12 @@ grep -oh '[0-9]*/open[^[:space:]]*' $LOG_NMAP | while IFS=/ read -ra parts; do else echo Open port ${parts[*]} | sed 's/,$//' | tee -a $REDACTED_LOG_NMAP echo -n ${parts[0]}"," | tee -a $OPENPORTSLIST_LOG_NMAP - touch .fail + touch $TEST_ROOT/.fail fi fi done -if [ -f .fail ]; then +if [ -f $TEST_ROOT/.fail ]; then echo Open ports: cat $REDACTED_LOG_NMAP result=fail @@ -122,7 +122,7 @@ touch $REDACTED_LOG_HTTP cat $LOG_HTTP | tee -a $REDACTED_LOG_HTTP touch $REPORT_HTTP touch $OPENPORTSLIST_LOG_HTTP -rm -f .fail +rm -f $TEST_ROOT/.fail grep -oh '[0-9]*/open[^[:space:]]*' $LOG_HTTP | while IFS=/ read -ra parts; do state=${parts[1]} if [ "$state" == open ]; then @@ -130,14 +130,14 @@ grep -oh '[0-9]*/open[^[:space:]]*' $LOG_HTTP | while IFS=/ read -ra parts; do proto=${parts[4]} echo $proto if [ "$proto" == http ]; then - touch .fail + touch $TEST_ROOT/.fail echo Failing ${parts[*]} | sed 's/,$//' | tee -a $REDACTED_LOG_HTTP echo -n ${parts[0]}"," | tee -a $OPENPORTSLIST_LOG_HTTP fi fi done -if [ -f .fail ]; then +if [ -f $TEST_ROOT/.fail ]; then echo Open http ports: cat $REDACTED_LOG_HTTP result=fail @@ -163,4 +163,4 @@ write_out_result $REPORT_HTTP \ "$(cat $REDACTED_LOG_HTTP)" \ "$RESULT_AND_SUMMARY_HTTP" -cat $REPORT_NMAP $REPORT_HTTP > $REPORT \ No newline at end of file +cat $REPORT_NMAP $REPORT_HTTP > $REPORT diff --git a/subset/ping/module_manifest.json b/subset/ping/module_manifest.json new file mode 100644 index 0000000000..1f6b3585e4 --- /dev/null +++ b/subset/ping/module_manifest.json @@ -0,0 +1,11 @@ +{ + "base.startup.dhcp": { + "description": "Check the base DHCP startup exchange" + }, + "base.switch.ping": { + "description": "Attempt to ping access switch (if configured)" + }, + "base.target.ping": { + "description": "Attempt to ping the Device Under Test" + } +} diff --git a/subset/ping/ping.daqmodule b/subset/ping/ping.daqmodule new file mode 100644 index 0000000000..cd2799228b --- /dev/null +++ b/subset/ping/ping.daqmodule @@ -0,0 +1,4 @@ +{ + "name": "ping", + "startup_script": "test_ping" +} diff --git a/docker/include/bin/test_ping b/subset/ping/test_ping similarity index 73% rename from docker/include/bin/test_ping rename to subset/ping/test_ping index b66393a079..d0d8bb2805 100755 --- a/docker/include/bin/test_ping +++ b/subset/ping/test_ping @@ -1,21 +1,21 @@ #!/bin/bash -e -source reporting.sh +source $TEST_ROOT/reporting.sh -RESULT_LINES=/tmp/result_lines.txt -MONO_LOG=/tmp/mono-log.txt -MANIFEST=./module_manifest.json -REPORT_FILE=/tmp/report.txt -MODULE_CONFIG=/config/device/module_config.json +RESULT_LINES=$TEST_ROOT/tmp/result_lines.txt +MONO_LOG=$TEST_ROOT/tmp/mono-log.txt +REPORT_FILE=$TEST_ROOT/tmp/report.txt +MODULE_CONFIG=$TEST_ROOT/config/device/module_config.json +MANIFEST=$TEST_ROOT/module_manifest.json status=pass echo Baseline ping test report | tee -a $MONO_LOG # This is a check that the startup.pcap file exists and is proper. -tcpdump -en -r /scans/startup.pcap ip +tcpdump -en -r $TEST_ROOT/scans/startup.pcap ip -echo %% $(tcpdump -n -r /scans/startup.pcap | wc -l) packets captured. | tee -a $MONO_LOG +echo %% $(tcpdump -n -r $TEST_ROOT/scans/startup.pcap | wc -l) packets captured. | tee -a $MONO_LOG echo -STATIC_IP=`jq -r .static_ip /config/device/module_config.json` +STATIC_IP=`jq -r .static_ip $MODULE_CONFIG` if [ "$STATIC_IP" == null ]; then STATIC_IP= fi @@ -26,8 +26,8 @@ else req=pass ack=pass echo - tcpdump -ven -r /scans/startup.pcap port 67 | fgrep "length 1: Request" || req=fail - tcpdump -ven -r /scans/startup.pcap port 67 | fgrep "length 1: ACK" || ack=fail1 + tcpdump -ven -r $TEST_ROOT/scans/startup.pcap port 67 | fgrep "length 1: Request" || req=fail + tcpdump -ven -r $TEST_ROOT/scans/startup.pcap port 67 | fgrep "length 1: ACK" || ack=fail1 if [ $req = "fail" ] || [ $ack = "fail" ]; then status=fail echo RESULT fail base.startup.dhcp missing dhcp packets| tee -a $RESULT_LINES @@ -46,12 +46,7 @@ if [ -n "$LOCAL_IP" ]; then LOCAL_ONLY=${LOCAL_IP%/*} LOCAL_INDEX=${LOCAL_ONLY##*.} echo Using IP index $LOCAL_INDEX - LOCAL_MAC=ca:50:20:b1:4f:$(printf %02x $LOCAL_INDEX) - echo Using local MAC address $LOCAL_MAC - - LOCAL_IFACE=`hostname`-eth0 - ip link set dev $LOCAL_IFACE addr $LOCAL_MAC - ip addr add $LOCAL_IP dev $LOCAL_IFACE + ip addr add $LOCAL_IP dev lo ping -n -c 2 $SWITCH_IP || true @@ -88,8 +83,8 @@ echo Done with basic connectivity tests | tee -a $MONO_LOG echo Checking startup NTP ntp_target=${TARGET_IP%.*}.2 -ntp_request=`tcpdump -env -c 1 -r /scans/monitor.pcap dst port 123 | wc -l` -ntp_proper=`tcpdump -env -c 1 -r /scans/monitor.pcap dst port 123 and dst host $ntp_target | wc -l` +ntp_request=`tcpdump -env -c 1 -r $TEST_ROOT/scans/monitor.pcap dst port 123 | wc -l` +ntp_proper=`tcpdump -env -c 1 -r $TEST_ROOT/scans/monitor.pcap dst port 123 and dst host $ntp_target | wc -l` if [ "$ntp_request" == 0 ]; then ntp_result=skip ntp_summary="No NTP traffic detected" @@ -104,8 +99,8 @@ echo RESULT $ntp_result base.startup.ntp $ntp_summary %% NTP server $ntp_target echo Checking startup DNS activity... dns_target=${TARGET_IP%.*}.2 -dns_request=`tcpdump -env -c 1 -r /scans/startup.pcap dst port 53 | wc -l` -dns_proper=`tcpdump -env -c 1 -r /scans/startup.pcap dst port 53 and dst host $dns_target | wc -l` +dns_request=`tcpdump -env -c 1 -r $TEST_ROOT/scans/startup.pcap dst port 53 | wc -l` +dns_proper=`tcpdump -env -c 1 -r $TEST_ROOT/scans/startup.pcap dst port 53 and dst host $dns_target | wc -l` if [ "$dns_request" == 0 ]; then dns_result=skip dns_summary="No dns traffic detected" @@ -125,10 +120,10 @@ write_out_monolog $REPORT_FILE \ $RESULT_LINES -ping_runtime=/config/port/ping_runtime.sh +ping_runtime=$TEST_ROOT/config/port/ping_runtime.sh if [ -f $ping_runtime ]; then echo Executing $ping_runtime - source $ping_runtime + TEST_ROOT=$TEST_ROOT source $ping_runtime else echo $ping_runtime not found. fi diff --git a/subset/security/Dockerfile.test_tls b/subset/security/Dockerfile.test_tls index b166ecf9c3..7da5add6d9 100644 --- a/subset/security/Dockerfile.test_tls +++ b/subset/security/Dockerfile.test_tls @@ -5,7 +5,6 @@ RUN $AG update && $AG install openjdk-11-jre RUN $AG update && $AG install openjdk-11-jdk git -COPY subset/switches/module_manifest.json . COPY subset/security/ . RUN cd tlstest && ./gradlew build diff --git a/subset/security/test_tls b/subset/security/test_tls index 4a61d4afbb..b73af6c615 100755 --- a/subset/security/test_tls +++ b/subset/security/test_tls @@ -5,7 +5,8 @@ LOCAL_REPORT=tmp/report.txt RESULT_LINES=/tmp/result_lines.txt MONO_LOG=/tmp/mono-log.txt -MANIFEST=./module_manifest.json +MANIFEST=./tls.module_manifest.json +MODULE_CONFIG=/config/device/module_config.json if [ -n "$TARGET_IP" ]; then echo Collecting TLS cert from target address %% $TARGET_IP > $MONO_LOG diff --git a/subset/security/module_manifest.json b/subset/security/tls.module_manifest.json similarity index 63% rename from subset/security/module_manifest.json rename to subset/security/tls.module_manifest.json index b5ef7b4b10..3420ccf751 100644 --- a/subset/security/module_manifest.json +++ b/subset/security/tls.module_manifest.json @@ -1,20 +1,20 @@ { - "security.tls.v1_3" : { + "security.tls.v1_3": { "description": "Verify the device supports TLS 1.3 (as a client)" }, - "security.tls.v1_3.x509" : { + "security.tls.v1_3.x509": { "description": "Verify the devices supports RFC 2459 - Internet X.509 Public Key Infrastructure Certificate and CRL Profile" }, - "security.tls.v1_2" : { + "security.tls.v1_2": { "description": "Verify the device supports TLS 1.2 (as a client)" }, - "security.tls.v1_2.x509" : { - "desc" : "Verify the devices supports RFC 2459 - Internet X.509 Public Key Infrastructure Certificate and CRL Profile" + "security.tls.v1_2.x509": { + "desc": "Verify the devices supports RFC 2459 - Internet X.509 Public Key Infrastructure Certificate and CRL Profile" }, - "security.tls.v1" : { + "security.tls.v1": { "description": "Verify the device supports TLS 1.0 (as a client)" }, - "security.tls.v1.x509" : { + "security.tls.v1.x509": { "description": "Verify the devices supports RFC 2459 - Internet X.509 Public Key Infrastructure Certificate and CRL Profile" } } diff --git a/subset/switches/Dockerfile.test_switch b/subset/switches/Dockerfile.test_switch index 64cba8f29d..28e09b6f4c 100644 --- a/subset/switches/Dockerfile.test_switch +++ b/subset/switches/Dockerfile.test_switch @@ -8,7 +8,6 @@ RUN $AG update && $AG install maven tcpdump COPY subset/switches/ switches/ RUN mkdir -p switches/src/main/proto COPY usi/src/main/proto/* switches/src/main/proto/ -COPY subset/switches/module_manifest.json . RUN cd switches && mvn clean compile assembly:single diff --git a/subset/switches/test_switch b/subset/switches/test_switch index e20ff5728b..0c89272866 100755 --- a/subset/switches/test_switch +++ b/subset/switches/test_switch @@ -2,7 +2,7 @@ source reporting.sh REPORT=/tmp/report.txt LOCAL_REPORT=tmp/report.txt -MANIFEST=./module_manifest.json +MANIFEST=./switches/module_manifest.json MONO_LOG=/tmp/monolog.switch.txt RESULT_LINES=/tmp/results.switch.txt MODULE_CONFIG=/config/device/module_config.json diff --git a/testing/test_base.out b/testing/test_base.out index c0208bd8de..abd51b8cda 100644 --- a/testing/test_base.out +++ b/testing/test_base.out @@ -99,7 +99,7 @@ security.nmap.ports -------------------- Automatic TCP/UDP port scan using nmap -------------------- -# Nmap 7.60 scan initiated XXX as: nmap -v -n -T5 -sT --host-timeout=4m --open -p1-65535 -oG /tmp/nmap.log X.X.X.X +# Nmap XXX scan initiated XXX as: nmap -v -n -T5 -sT --host-timeout=4m --open -p1-65535 -oG XXX/tmp/nmap.log X.X.X.X # Ports scanned: TCP(65535;1-65535) UDP(0;) SCTP(0;) PROTOCOLS(0;) # Nmap done at XXX -- 1 IP address (1 host up) scanned in XXX No invalid ports found. @@ -111,7 +111,7 @@ security.nmap.http -------------------- Check that the device does not have open ports exposing an unencrypted web interface using HTTP -------------------- -# Nmap 7.60 scan initiated XXX as: nmap -v -n -T5 -A --script http-methods --host-timeout=4m --open -p- -oG /tmp/http.log X.X.X.X +# Nmap XXX scan initiated XXX as: nmap -v -n -T5 -A --script http-methods --host-timeout=4m --open -p- -oG XXX/tmp/http.log X.X.X.X # Ports scanned: TCP(65535;1-65535) UDP(0;) SCTP(0;) PROTOCOLS(0;) # Nmap done at XXX -- 1 IP address (1 host up) scanned in XXX No running http servers have been found. diff --git a/testing/test_base.sh b/testing/test_base.sh index 1a0701144e..1abc50fa94 100755 --- a/testing/test_base.sh +++ b/testing/test_base.sh @@ -62,6 +62,10 @@ echo %%%%%%%%%%%%%%%%%%%%%% Mud profile tests | tee -a $TEST_RESULTS rm -f local/system.yaml cp config/system/muddy.conf local/system.conf +if [ -z `which tcpdump` ]; then + export PATH=/usr/sbin:$PATH +fi + device_traffic="tcpdump -en -r inst/run-9a02571e8f01/scans/monitor.pcap port 47808" device_bcast="$device_traffic and ether broadcast" device_ucast="$device_traffic and ether dst 9a:02:57:1e:8f:02" diff --git a/testing/test_modules.out b/testing/test_modules.out index 2e2dfadd4d..5f7aae40ce 100644 --- a/testing/test_modules.out +++ b/testing/test_modules.out @@ -1,9 +1,5 @@ Running testing/test_modules.sh Base Tests -Testing ping -RESULT skip base.startup.dhcp Using static ip 10.20.0.5 -RESULT skip base.switch.ping No local IP has been set, check system config -RESULT pass base.target.ping target reached %% 10.20.0.5 Testing tls alt RESULT skip security.tls.v1 IOException unable to connect to server RESULT skip security.tls.v1.x509 IOException unable to connect to server @@ -25,18 +21,6 @@ RESULT fail security.tls.v1_2 Certificate is expired. RESULT fail security.tls.v1_2.x509 Certificate is expired. RESULT fail security.tls.v1_3 Certificate could not be validated. RESULT fail security.tls.v1_3.x509 Certificate could not be validated. -Testing nmap -RESULT pass security.nmap.ports Only allowed ports found open. -RESULT pass security.nmap.http No running http servers have been found. -Testing nmap bacnet -RESULT pass security.nmap.ports Only allowed ports found open. -RESULT pass security.nmap.http No running http servers have been found. -Testing nmap telnet -RESULT fail security.nmap.ports Some disallowed ports are open: 23. -RESULT pass security.nmap.http No running http servers have been found. -Testing nmap ohttp -RESULT fail security.nmap.ports Some disallowed ports are open: 443,12345,54321. -RESULT fail security.nmap.http Some ports are running http servers: 12345,54321. Testing ssh RESULT skip security.ssh.version Device is not running an SSH server Testing ssh ssh diff --git a/testing/test_modules.sh b/testing/test_modules.sh index 711765a9e1..9d41acbe21 100755 --- a/testing/test_modules.sh +++ b/testing/test_modules.sh @@ -10,14 +10,9 @@ cp config/system/all.conf local/system.conf TEST_LIST=/tmp/module_tests.txt cat > $TEST_LIST < inst/modules/ping/config/module_config.json +mkdir -p inst/modules/tls/config +cp resources/setups/baseline/module_config.json inst/modules/tls/config/module_config.json cat $TEST_LIST | while read module args; do if ! docker inspect daqf/test_$module:latest > /dev/null; then diff --git a/testing/test_preamble.sh b/testing/test_preamble.sh index f2028d089d..904a9ead0c 100644 --- a/testing/test_preamble.sh +++ b/testing/test_preamble.sh @@ -67,7 +67,9 @@ function redact { -e 's/Not shown: .* ports//' \ -e 's/[ \t]*$//' \ -e 's/\t/ /g' \ - -e 's/([0-9]{1,3}\.){3}[0-9]{1,3}/X.X.X.X/' + -e 's/([0-9]{1,3}\.){3}[0-9]{1,3}/X.X.X.X/' \ + -e 's/-oG .*\/tmp/-oG XXX\/tmp/' \ + -e 's/# Nmap [0-9]{1,4}\.[0-9]{1,4}/\# Nmap XXX/' # NOTE: Whitespace redaction (\t) is because many IDEs automatically strip/convert tabs to spaces. } diff --git a/testing/test_topo.sh b/testing/test_topo.sh index d802e73483..d941267534 100755 --- a/testing/test_topo.sh +++ b/testing/test_topo.sh @@ -8,8 +8,8 @@ echo mudacl tests | tee -a $TEST_RESULTS mudacl/bin/test.sh echo Mudacl exit code $? | tee -a $TEST_RESULTS -bacnet_file=/tmp/bacnet_result.txt -socket_file=/tmp/socket_result.txt +bacnet_file='$TEST_ROOT/tmp/bacnet_result.txt' +socket_file='$TEST_ROOT/tmp/socket_result.txt' MAC_BASE=9a:02:57:1e:8f diff --git a/testing/test_utils.sh b/testing/test_utils.sh index 9d06feea09..826bf6477e 100644 --- a/testing/test_utils.sh +++ b/testing/test_utils.sh @@ -46,14 +46,14 @@ function check_setup { cat >> $cmd_file < 0)) } function test_tcp { src_mac=$MAC_BASE:$(printf %02x $src_dev) dst_mac=$MAC_BASE:\$(printf %02x \$1) # Check for TCP ACKs, since that means the network is allowing it. - tcp_base="tcpdump -en -r /scans/test_ping.pcap tcp and ether dst \$src_mac" + tcp_base="tcpdump -en -r \$TEST_ROOT/scans/test_ping.pcap tcp and ether dst \$src_mac" filter="ether src \$dst_mac and src port \$2" echo \$((\$(\$tcp_base and \$filter | wc -l ) > 0)) } @@ -120,8 +120,8 @@ function run_test { test -d $conf_dir || (mkdir -p $conf_dir; echo sleep 30 >> $cmd_file) done cmd/run -s - cat inst/run-*/nodes/ping*${socket_file} | tee -a $TEST_RESULTS - cat inst/run-*/nodes/ping*${bacnet_file} | tee -a $TEST_RESULTS + cat inst/run-*/nodes/ping*/tmp/$(basename $socket_file) | tee -a $TEST_RESULTS + cat inst/run-*/nodes/ping*/tmp/$(basename $bacnet_file) | tee -a $TEST_RESULTS more inst/run-*/nodes/ping*/activate.log | cat more inst/gw0*/nodes/gw0*/activate.log | cat more inst/gw0*/dhcp_monitor.txt | cat diff --git a/testing/unit/test_runner.py b/testing/unit/test_runner.py index 70e285816b..b9600e613d 100644 --- a/testing/unit/test_runner.py +++ b/testing/unit/test_runner.py @@ -37,6 +37,7 @@ def setUp(self): } configurator.Configurator.load_and_merge = MagicMock(return_value={}) network.TestNetwork.__init__ = MagicMock(return_value=None) + DAQRunner._get_test_metadata = MagicMock(return_value={}) with patch("builtins.open", mock_open(read_data="data")): self.runner = DAQRunner(self.config) diff --git a/usi/build.conf b/usi/build.conf index d469dd0503..c6bb648952 100644 --- a/usi/build.conf +++ b/usi/build.conf @@ -1,2 +1 @@ build usi -add usi From 93a6a12ddf12f98b4f30aee9f0544d361eeb6b77 Mon Sep 17 00:00:00 2001 From: Trevor Date: Wed, 16 Sep 2020 08:58:02 -0700 Subject: [PATCH 138/212] Clear out port_acls directory for local test runs. (#640) --- bin/test_daq | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/test_daq b/bin/test_daq index 416d027886..f2b010ed66 100755 --- a/bin/test_daq +++ b/bin/test_daq @@ -60,6 +60,7 @@ if [ -d local ]; then fi mkdir -p local inst +rm -rf inst/port_acls echo I am g`whoami` From bc93eb4d5503c9b9a22d32a4365c0ff9ccbbe77e Mon Sep 17 00:00:00 2001 From: Trevor Date: Wed, 16 Sep 2020 08:58:39 -0700 Subject: [PATCH 139/212] Disable stickler print-function check (#637) --- .stickler.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.stickler.yml b/.stickler.yml index 3f44024abd..729ec6588b 100644 --- a/.stickler.yml +++ b/.stickler.yml @@ -7,6 +7,7 @@ linters: python: 3 max-line-length: 100 py3k: + ignore: E1601 checkstyle: config: ./.checkstyle.xml files: From fee1b783a1f44ff18f82d6383296225501c15279 Mon Sep 17 00:00:00 2001 From: Trevor Date: Thu, 17 Sep 2020 08:56:54 -0700 Subject: [PATCH 140/212] Update UDMI version to 1.2.0 (#646) --- etc/UDMI_VERSION | 2 +- testing/test_aux.gcp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/etc/UDMI_VERSION b/etc/UDMI_VERSION index 9084fa2f71..26aaba0e86 100644 --- a/etc/UDMI_VERSION +++ b/etc/UDMI_VERSION @@ -1 +1 @@ -1.1.0 +1.2.0 diff --git a/testing/test_aux.gcp b/testing/test_aux.gcp index 9c5cc28467..e2f0dceb7d 100644 --- a/testing/test_aux.gcp +++ b/testing/test_aux.gcp @@ -7,7 +7,7 @@ Running testing/test_aux.sh "SNS-4" : "True" }, "Version" : { - "main" : "1.1.0" + "main" : "1.2.0" } } inst/test_site/devices/AHU-1/metadata_norm.json: "hash": "175e704a" From 9ea0dbdc94713d43600d4dd67001a558581ac53c Mon Sep 17 00:00:00 2001 From: henry54809 Date: Thu, 17 Sep 2020 14:04:41 -0700 Subject: [PATCH 141/212] granular dhcp test timeouts. (#645) --- config/modules/host.conf | 6 +- daq/host.py | 2 + daq/runner.py | 61 ++++++++++++-------- daq/test_modules/base_module.py | 3 + daq/test_modules/ipaddr_module.py | 36 +++++++++++- resources/setups/baseline/module_config.json | 2 +- subset/ipaddr/build.conf | 2 +- testing/test_aux.out | 4 +- testing/test_dhcp.out | 1 + testing/test_dhcp.sh | 27 ++++++++- 10 files changed, 111 insertions(+), 33 deletions(-) diff --git a/config/modules/host.conf b/config/modules/host.conf index 00e934780a..9ca6d430da 100644 --- a/config/modules/host.conf +++ b/config/modules/host.conf @@ -4,9 +4,9 @@ build docker/modules # Default built-in tests. -add pass -add fail -add ping +add pass first +add fail first +add ping first add bacnet add mudgee diff --git a/daq/host.py b/daq/host.py index 9e8684a5cf..b07ecf2f75 100644 --- a/daq/host.py +++ b/daq/host.py @@ -383,6 +383,8 @@ def _main_module_timeout_handler(self): def heartbeat(self): """Checks module run time for each event loop""" timeout_sec = self._get_test_timeout(self.test_name) + if self.test_host: + self.test_host.heartbeat() if not timeout_sec or not self.test_start: return timeout = gcp.parse_timestamp(self.test_start) + timedelta(seconds=timeout_sec) diff --git a/daq/runner.py b/daq/runner.py index bf7669d4fc..78a5bfd66d 100644 --- a/daq/runner.py +++ b/daq/runner.py @@ -164,7 +164,7 @@ def __init__(self, config): if logging_client: logger.set_stackdriver_client(logging_client, labels={"daq_run_id": self.daq_run_id}) - test_list = self._get_test_list(config.get('host_tests', self._DEFAULT_TESTS_FILE), []) + test_list = self._get_test_list(config.get('host_tests', self._DEFAULT_TESTS_FILE)) if self.config.get('keep_hold'): LOGGER.info('Appending test_hold to master test list') test_list.append('hold') @@ -502,33 +502,46 @@ def _target_set_trigger(self, device): except Exception as e: self.target_set_error(device, e) - def _get_test_list(self, test_file, test_list): + def _get_test_list(self, test_file): no_test = self.config.get('no_test', False) if no_test: LOGGER.warning('Suppressing configured tests because no_test') - return test_list - LOGGER.info('Reading test definition file %s', test_file) - with open(test_file) as file: - line = file.readline() - while line: - cmd = re.sub(r'#.*', '', line).strip().split() - cmd_name = cmd[0] if cmd else None - argument = cmd[1] if len(cmd) > 1 else None - if cmd_name == 'add': - LOGGER.debug('Adding test %s from %s', argument, test_file) - test_list.append(argument) - elif cmd_name == 'remove': - if argument in test_list: - LOGGER.debug('Removing test %s from %s', argument, test_file) - test_list.remove(argument) - elif cmd_name == 'include': - self._get_test_list(argument, test_list) - elif cmd_name == 'build' or not cmd_name: - pass - else: - LOGGER.warning('Unknown test list command %s', cmd_name) + return [] + head = [] + body = [] + tail = [] + + def get_test_list(test_file): + LOGGER.info('Reading test definition file %s', test_file) + with open(test_file) as file: line = file.readline() - return test_list + while line: + cmd = re.sub(r'#.*', '', line).strip().split() + cmd_name = cmd[0] if cmd else None + argument = cmd[1] if len(cmd) > 1 else None + ordering = cmd[2] if len(cmd) > 2 else None + if cmd_name == 'add': + LOGGER.debug('Adding test %s from %s', argument, test_file) + if ordering == "first": + head.append(argument) + elif ordering == "last": + tail.append(argument) + else: + body.append(argument) + elif cmd_name == 'remove': + LOGGER.debug('Removing test %s from %s', argument, test_file) + for section in (head, body, tail): + if argument in section: + section.remove(argument) + elif cmd_name == 'include': + get_test_list(argument) + elif cmd_name == 'build' or not cmd_name: + pass + else: + LOGGER.warning('Unknown test list command %s', cmd_name) + line = file.readline() + get_test_list(test_file) + return [*head, *body, *tail] def _get_test_metadata(self, extension=".daqmodule", root="."): metadata = {} diff --git a/daq/test_modules/base_module.py b/daq/test_modules/base_module.py index 7a68efef09..d4e0764b67 100644 --- a/daq/test_modules/base_module.py +++ b/daq/test_modules/base_module.py @@ -42,5 +42,8 @@ def start(self, port, params, callback, finish_hook): def ip_listener(self, target_ip): """Defaults to do nothing about ip notifications""" + def heartbeat(self): + """For modules that need to do periodic checks""" + def __repr__(self): return "Target device %s test %s" % (self.device, self.test_name) diff --git a/daq/test_modules/ipaddr_module.py b/daq/test_modules/ipaddr_module.py index 04369a311c..6f2e242f54 100644 --- a/daq/test_modules/ipaddr_module.py +++ b/daq/test_modules/ipaddr_module.py @@ -4,6 +4,7 @@ import logging import time +from datetime import datetime, timedelta import os import copy import logger @@ -12,15 +13,24 @@ from .base_module import HostModule _LOG_FORMAT = "%(asctime)s %(levelname)-7s %(message)s" +LEASE_TIME_UNITS_CONVERTER = { + 's': 1, + 'm': 60, + 'h': 60 ** 2, + 'd': 24 * 60 ** 2 +} + class IpAddrModule(HostModule): """Module for inline ipaddr tests""" + _TIMEOUT_EXCEPTION = TimeoutError('DHCP Timeout expired') def __init__(self, host, tmpdir, test_name, module_config): super().__init__(host, tmpdir, test_name, module_config) self.docker_host = DockerModule(host, tmpdir, test_name, module_config) self.test_dhcp_ranges = copy.copy(self.test_config.get('dhcp_ranges', [])) self._ip_callback = None + self._lease_time_seconds = self._get_lease_time() self.tests = [ ('dhcp port_toggle test', self._dhcp_port_toggle_test), ('dhcp multi subnet test', self._multi_subnet_test), @@ -36,6 +46,7 @@ def __init__(self, host, tmpdir, test_name, module_config): self._file_handler.setFormatter(formatter) self._logger.addHandler(self._file_handler) self._force_terminated = False + self._timeout = None def start(self, port, params, callback, finish_hook): """Start the ip-addr tests""" @@ -43,8 +54,21 @@ def start(self, port, params, callback, finish_hook): self._logger.debug('Target device %s starting ipaddr test %s', self.device, self.test_name) self._next_test() + def _get_lease_time(self): + lease_time = self.host.config.get("dhcp_lease_time") + if not lease_time or lease_time[-1] not in LEASE_TIME_UNITS_CONVERTER: + return None + return float(lease_time[:-1]) * LEASE_TIME_UNITS_CONVERTER[lease_time[-1]] + + def _set_timeout(self): + if not self._lease_time_seconds: + return + self._timeout = datetime.now() + timedelta(seconds=self._lease_time_seconds) + self._logger.info('Setting DHCP timeout at %s' % self._timeout) + def _next_test(self): try: + self._timeout = None name, func = self.tests.pop(0) self._logger.info('Running ' + name) func() @@ -53,6 +77,7 @@ def _next_test(self): self._finalize(exception=e) def _dhcp_port_toggle_test(self): + self._set_timeout() if not self.host.connect_port(False): self._logger('disconnect port not enabled') return @@ -61,6 +86,7 @@ def _dhcp_port_toggle_test(self): self._ip_callback = self._next_test def _multi_subnet_test(self): + self._set_timeout() if not self.test_dhcp_ranges: self._next_test() return @@ -71,10 +97,12 @@ def _multi_subnet_test(self): self._ip_callback = self._multi_subnet_test if self.test_dhcp_ranges else self._next_test def _ip_change_test(self): + self._set_timeout() self.host.gateway.request_new_ip(self.host.target_mac) self._ip_callback = self._next_test def _analyze(self): + self._set_timeout() self._ip_callback = None self.docker_host.start(self.port, self.params, self._finalize, self._finish_hook) @@ -84,7 +112,7 @@ def _finalize(self, return_code=None, exception=None): self._ip_callback = None self._file_handler.close() if not self._force_terminated: - self.callback(return_code=None, exception=exception) + self.callback(return_code=return_code, exception=exception) def terminate(self): """Terminate this set of tests""" @@ -99,3 +127,9 @@ def ip_listener(self, target_ip): self._logger.info('ip notification %s' % target_ip) if self._ip_callback: self._ip_callback() + + def heartbeat(self): + if self._timeout and datetime.now() >= self._timeout: + self._logger.error('DHCP times out after %ds lease time.' % self._lease_time_seconds) + self.terminate() + self.callback(exception=self._TIMEOUT_EXCEPTION) diff --git a/resources/setups/baseline/module_config.json b/resources/setups/baseline/module_config.json index 5999aa59b6..3f74efb2ac 100644 --- a/resources/setups/baseline/module_config.json +++ b/resources/setups/baseline/module_config.json @@ -2,7 +2,7 @@ "modules": { "ipaddr": { "enabled": false, - "timeout_sec": 900, + "timeout_sec": 0, "port_flap_timeout_sec": 20, "dhcp_ranges": [{"start": "192.168.0.1", "end": "192.168.255.254", "prefix_length": 16}] }, diff --git a/subset/ipaddr/build.conf b/subset/ipaddr/build.conf index 42b759fff5..03c9feadf8 100644 --- a/subset/ipaddr/build.conf +++ b/subset/ipaddr/build.conf @@ -1,2 +1,2 @@ build subset/ipaddr -add ipaddr +add ipaddr last diff --git a/testing/test_aux.out b/testing/test_aux.out index 8a6bd9e9cf..e8bb1a3878 100644 --- a/testing/test_aux.out +++ b/testing/test_aux.out @@ -114,7 +114,7 @@ port-01 module_config modules ], "enabled": false, "port_flap_timeout_sec": 20, - "timeout_sec": 900 + "timeout_sec": 0 }, "manual": { "enabled": true @@ -173,7 +173,7 @@ port-02 module_config modules ], "enabled": false, "port_flap_timeout_sec": 20, - "timeout_sec": 900 + "timeout_sec": 0 }, "manual": { "enabled": true diff --git a/testing/test_dhcp.out b/testing/test_dhcp.out index 06ba950d71..3bf5881c31 100644 --- a/testing/test_dhcp.out +++ b/testing/test_dhcp.out @@ -5,6 +5,7 @@ DHCP Tests 9a02571e8f03: [] 9a02571e8f04: [] 9a02571e8f05: [] +9a02571e8f06: ['9a02571e8f06:ipaddr:TimeoutError'] Device 1 ip triggers: 1 0 Device 2 ip triggers: 0 0 Device 3 long ip triggers: 1 diff --git a/testing/test_dhcp.sh b/testing/test_dhcp.sh index 5fd721546c..e561377e57 100755 --- a/testing/test_dhcp.sh +++ b/testing/test_dhcp.sh @@ -7,12 +7,13 @@ echo DHCP Tests >> $TEST_RESULTS cat < local/system.conf source config/system/default.yaml site_description="Multi-Device Configuration" -switch_setup.uplink_port=6 +switch_setup.uplink_port=7 interfaces.faux-1.opts= interfaces.faux-2.opts=xdhcp interfaces.faux-3.opts= interfaces.faux-4.opts= interfaces.faux-5.opts= +interfaces.faux-6.opts= monitor_scan_sec=1 EOF @@ -62,7 +63,31 @@ cat < local/site/mac_addrs/$intf_mac/module_config.json } EOF +# DHCP times out in extended DHCP tests +intf_mac="9a02571e8f06" +mkdir -p local/site/mac_addrs/$intf_mac +cat < local/site/mac_addrs/$intf_mac/module_config.json +{ + "modules": { + "ipaddr": { + "enabled": true, + "timeout_sec": 0, + "port_flap_timeout_sec": 20, + "dhcp_ranges": [] + } + } +} +EOF + +function kill_dhcp_client { + CONTAINER=$1 + pid=$(docker exec $CONTAINER ps aux | grep dhclient | awk '{print $2}') + echo Killing dhcp client in $CONTAINER pid $pid + docker exec $CONTAINER kill $pid +} +# Check that killing the dhcp client on a device times out the ipaddr test. +monitor_log "Target port 6 connect successful" "kill_dhcp_client daq-faux-6" cmd/run -b -s settle_sec=0 dhcp_lease_time=120s cat inst/result.log | sort | tee -a $TEST_RESULTS From 2cbbada7f73df4b41e49969515291880e220ba20 Mon Sep 17 00:00:00 2001 From: henry54809 Date: Fri, 18 Sep 2020 12:26:24 -0700 Subject: [PATCH 142/212] fix no_test option (#647) --- daq/runner.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/daq/runner.py b/daq/runner.py index 78a5bfd66d..993d66afb6 100644 --- a/daq/runner.py +++ b/daq/runner.py @@ -167,7 +167,8 @@ def __init__(self, config): test_list = self._get_test_list(config.get('host_tests', self._DEFAULT_TESTS_FILE)) if self.config.get('keep_hold'): LOGGER.info('Appending test_hold to master test list') - test_list.append('hold') + if 'hold' not in test_list: + test_list.append('hold') config['test_list'] = test_list config['test_metadata'] = self._get_test_metadata() LOGGER.info('DAQ RUN id: %s' % self.daq_run_id) @@ -506,7 +507,7 @@ def _get_test_list(self, test_file): no_test = self.config.get('no_test', False) if no_test: LOGGER.warning('Suppressing configured tests because no_test') - return [] + return ['hold'] head = [] body = [] tail = [] From ee9c420957242200b42d7eb1738c5be548bdcfb1 Mon Sep 17 00:00:00 2001 From: jhughesbiot <50999916+jhughesbiot@users.noreply.github.com> Date: Sat, 19 Sep 2020 09:46:36 -0700 Subject: [PATCH 143/212] Tls updates (#626) * TLS test support --- .pylintrc | 2 +- bin/test_module | 26 + docker/include/bin/start_faux | 4 + docker/include/security/nginxfail.conf | 2 +- docker/include/security/nginxpass.conf | 1 - .../security/tlsfaux/certs/CA_Faux.key | 5 + .../security/tlsfaux/certs/CA_Faux.pem | 15 + .../security/tlsfaux/certs/CA_Faux.srl | 1 + .../security/tlsfaux/certs/ecparam.pem | 3 + .../include/security/tlsfaux/certs/server.crt | 29 +- .../include/security/tlsfaux/certs/server.csr | 22 +- .../include/security/tlsfaux/certs/server.key | 29 +- docker/include/security/tlsfaux/client.py | 39 ++ .../security/tlsfaux/generate_certs.py | 54 +- docker/include/security/tlsfaux/server.py | 33 +- docker/modules/Dockerfile.aardvark2 | 24 + docs/device_report.md | 81 +-- resources/setups/baseline/module_config.json | 3 +- subset/security/Dockerfile.test_tls | 5 +- subset/security/readme.md | 74 ++- subset/security/test_tls | 15 +- subset/security/tls.module_manifest.json | 35 +- subset/security/tlstest/build.gradle | 14 +- .../main/java/CertificateSignatureStatus.java | 4 + .../src/main/java/CertificateStatus.java | 1 - .../security/tlstest/src/main/java/Certs.java | 302 --------- .../tlstest/src/main/java/CipherStatus.java | 6 + .../tlstest/src/main/java/Client.java | 338 ++++++++++ .../src/main/java/KeyLengthStatus.java | 5 + .../security/tlstest/src/main/java/Main.java | 61 +- .../tlstest/src/main/java/Report.java | 10 +- .../src/main/java/ResultGenerator.java | 142 +++++ .../tlstest/src/main/java/Server.java | 586 ++++++++++++++++++ .../tlstest/src/main/java/TestResult.java | 6 + testing/test_aux.out | 35 +- testing/test_modules.out | 33 +- testing/test_modules.sh | 2 +- 37 files changed, 1518 insertions(+), 529 deletions(-) create mode 100644 docker/include/security/tlsfaux/certs/CA_Faux.key create mode 100644 docker/include/security/tlsfaux/certs/CA_Faux.pem create mode 100644 docker/include/security/tlsfaux/certs/CA_Faux.srl create mode 100644 docker/include/security/tlsfaux/certs/ecparam.pem create mode 100644 docker/include/security/tlsfaux/client.py create mode 100644 docker/modules/Dockerfile.aardvark2 create mode 100644 subset/security/tlstest/src/main/java/CertificateSignatureStatus.java delete mode 100644 subset/security/tlstest/src/main/java/Certs.java create mode 100644 subset/security/tlstest/src/main/java/CipherStatus.java create mode 100644 subset/security/tlstest/src/main/java/Client.java create mode 100644 subset/security/tlstest/src/main/java/KeyLengthStatus.java create mode 100644 subset/security/tlstest/src/main/java/ResultGenerator.java create mode 100644 subset/security/tlstest/src/main/java/Server.java create mode 100644 subset/security/tlstest/src/main/java/TestResult.java diff --git a/.pylintrc b/.pylintrc index bcdaa03a32..918f56efe9 100644 --- a/.pylintrc +++ b/.pylintrc @@ -1,5 +1,5 @@ [MASTER] good-names=fd,e output-format=parseable -disable=F0401,R0201,R0902,W0703,I0011,W0403,E1102,R0903,E0611,W0511,W0613 +disable=F0401,R0201,R0902,W0703,I0011,W0403,E1102,R0903,E0611,W0511,W0613,E1601 max-line-length=100 diff --git a/bin/test_module b/bin/test_module index 5eb73b7a77..e8308cfb8e 100755 --- a/bin/test_module +++ b/bin/test_module @@ -56,15 +56,34 @@ docker_args+=" -v $module_dir/scans:/scans" echo Capturing fake startup.pcap... sudo tcpdump -c 3 -eni $faux_intf -Z root -w $module_dir/scans/startup.pcap || true +echo Staring module pcap... +sudo tcpdump -U -eni $faux_intf -Z root -w $module_dir/scans/test_$module.pcap & +pid=$1 +sleep 5 +echo Module pcap started + docker_args+=" --env TARGET_IP=$faux_ip" docker_args+=" --env TARGET_MAC=01:02:03:04:05:06" + mkdir -p $config_dir docker_args+=" -v $config_dir:/config/inst" docker_args+=" -v $config_dir:/config/port" docker_args+=" -v $config_dir:/config/device" docker_args+=" -v $config_dir:/config/type" +# If testing the tls module, we need a few +# additional things setup +if [[ "$module" == "tls" ]]; then + #CA file is neededto validate the certs properly so we need to + #extract it from the faux device + CA_FILE=$(docker exec daq-$faux_intf cat ./tlsfaux/certs/CA_Faux.pem) + + #Write the contents of the CA file to the module_config location which + #will be mounted later for reference within test module + echo "$CA_FILE" > $config_dir/CA_Faux.pem +fi + docker rm -f $container || true cid=$( docker run -d --privileged --name $container --hostname $container \ @@ -102,6 +121,13 @@ if [ -n "$failed" ]; then false fi +#now interrupt the process. get its PID: +echo Stopping module pcap... +echo $pid +#interrupt it: +sudo kill -2 $pid +echo Module pcap stopped + echo Killed containers `docker kill $container` `docker kill daq-faux-$module` echo echo %%%%%%%%%%%%%% Module test results: $target %%%%%%%%%%%%%%% diff --git a/docker/include/bin/start_faux b/docker/include/bin/start_faux index 016a60bb7a..699405b28f 100755 --- a/docker/include/bin/start_faux +++ b/docker/include/bin/start_faux @@ -215,10 +215,14 @@ if [ -n "${options[tls]}" ]; then echo Starting tls server on port 443 https. mv /root/nginx/nginxpass.conf /etc/nginx/nginx.conf service nginx start + python tlsfaux/client.py 1.2 google.com & + python tlsfaux/client.py 1.3 google.com & elif [ -n "${options[expiredtls]}" ]; then echo Starting expired tls server on port 443 https. mv /root/nginx/nginxfail.conf /etc/nginx/nginx.conf service nginx start + python tlsfaux/client.py 1.2 not-a-good-url.google.com & + python tlsfaux/client.py 1.3 not-a-good-url.google.com & fi if [ -n "${options[pubber]}" ]; then diff --git a/docker/include/security/nginxfail.conf b/docker/include/security/nginxfail.conf index 3d41569baf..a2ebc029dc 100644 --- a/docker/include/security/nginxfail.conf +++ b/docker/include/security/nginxfail.conf @@ -27,7 +27,7 @@ http { auth_basic_user_file /etc/nginx/.htpasswd; } } - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE + ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE ssl_prefer_server_ciphers on; include /etc/nginx/conf.d/*.conf; diff --git a/docker/include/security/nginxpass.conf b/docker/include/security/nginxpass.conf index f437093444..2ba20b1975 100644 --- a/docker/include/security/nginxpass.conf +++ b/docker/include/security/nginxpass.conf @@ -32,4 +32,3 @@ http { include /etc/nginx/conf.d/*.conf; } - diff --git a/docker/include/security/tlsfaux/certs/CA_Faux.key b/docker/include/security/tlsfaux/certs/CA_Faux.key new file mode 100644 index 0000000000..2afafa5bed --- /dev/null +++ b/docker/include/security/tlsfaux/certs/CA_Faux.key @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgtpGg0FNSyrE0MHCI +cohQKupudOr7Acv4msSCO3M4mKShRANCAARVuwqGOKSndsIZ0SqNRqKxTljTI6fO +cmzwgRTmUPw1iFG1RYclAUYDqhCasZSQvAN3T3nRlScsB9wJOnBMIPAg +-----END PRIVATE KEY----- diff --git a/docker/include/security/tlsfaux/certs/CA_Faux.pem b/docker/include/security/tlsfaux/certs/CA_Faux.pem new file mode 100644 index 0000000000..0b8ac6c445 --- /dev/null +++ b/docker/include/security/tlsfaux/certs/CA_Faux.pem @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICWTCCAf+gAwIBAgIUY3MT+gDwvwAsSbipYXPsDmuYLmIwCgYIKoZIzj0EAwIw +gYExEzARBgoJkiaJk/IsZAEZFgNEQVExCzAJBgNVBAYTAlVTMRUwEwYDVQQIDAxN +b3VudGFpblZpZXcxDzANBgNVBAcMBktpbmdzWDEMMAoGA1UECgwDREFRMREwDwYD +VQQLDAhTb2Z0d2FyZTEUMBIGA1UEAwwLREFRIENBIFJvb3QwHhcNMjAwODE4MjEy +NjU4WhcNMjAwOTE3MjEyNjU4WjCBgTETMBEGCgmSJomT8ixkARkWA0RBUTELMAkG +A1UEBhMCVVMxFTATBgNVBAgMDE1vdW50YWluVmlldzEPMA0GA1UEBwwGS2luZ3NY +MQwwCgYDVQQKDANEQVExETAPBgNVBAsMCFNvZnR3YXJlMRQwEgYDVQQDDAtEQVEg +Q0EgUm9vdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABFW7CoY4pKd2whnRKo1G +orFOWNMjp85ybPCBFOZQ/DWIUbVFhyUBRgOqEJqxlJC8A3dPedGVJywH3Ak6cEwg +8CCjUzBRMB0GA1UdDgQWBBRQbxTiYvb2Z6Yy67i9xJKfmZ7cwDAfBgNVHSMEGDAW +gBRQbxTiYvb2Z6Yy67i9xJKfmZ7cwDAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49 +BAMCA0gAMEUCIQC/q0Ta92QzXoivZ6N5gDq+MJ0JlyP2bJEfKi+k0mMgRQIgR9qg +PJWJiFLkqWk0AoT3e1sT85hScH207syoJK6bmyM= +-----END CERTIFICATE----- diff --git a/docker/include/security/tlsfaux/certs/CA_Faux.srl b/docker/include/security/tlsfaux/certs/CA_Faux.srl new file mode 100644 index 0000000000..0b77d5a334 --- /dev/null +++ b/docker/include/security/tlsfaux/certs/CA_Faux.srl @@ -0,0 +1 @@ +1B649FEFDD9816F5FA7C2A6A76DCC12341A1426D diff --git a/docker/include/security/tlsfaux/certs/ecparam.pem b/docker/include/security/tlsfaux/certs/ecparam.pem new file mode 100644 index 0000000000..a76e47d959 --- /dev/null +++ b/docker/include/security/tlsfaux/certs/ecparam.pem @@ -0,0 +1,3 @@ +-----BEGIN EC PARAMETERS----- +BggqhkjOPQMBBw== +-----END EC PARAMETERS----- diff --git a/docker/include/security/tlsfaux/certs/server.crt b/docker/include/security/tlsfaux/certs/server.crt index 2580390f73..2da2227d4a 100644 --- a/docker/include/security/tlsfaux/certs/server.crt +++ b/docker/include/security/tlsfaux/certs/server.crt @@ -1,20 +1,13 @@ -----BEGIN CERTIFICATE----- -MIIDWDCCAkACCQCZ5obbadNWBjANBgkqhkiG9w0BAQsFADBuMQswCQYDVQQGEwJH -QjEPMA0GA1UECAwGTG9uZG9uMQ8wDQYDVQQHDAZLaW5nc1gxFjAUBgNVBAoMDUV4 -Y2VsUmVkc3RvbmUxETAPBgNVBAsMCFNvZnR3YXJlMRIwEAYDVQQDDAkxMjcuMC4w -LjEwHhcNMTkwNjA1MTIyMjAyWhcNMjAwNjA0MTIyMjAyWjBuMQswCQYDVQQGEwJH -QjEPMA0GA1UECAwGTG9uZG9uMQ8wDQYDVQQHDAZLaW5nc1gxFjAUBgNVBAoMDUV4 -Y2VsUmVkc3RvbmUxETAPBgNVBAsMCFNvZnR3YXJlMRIwEAYDVQQDDAkxMjcuMC4w -LjEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDcgEJmj0TM5Ex26CEV -GgMjWkygHwveT+GhI7B7+9yxPMOhOMEoAJKgGLhFEt3IrzgxcrBRUyWdV4mbz821 -In/sMxLVjfPFmiTFYkjDazmn8ZQrtuEgj/xnpQZvVHQCS1JoM/XmVV8JV0SAY513 -BBgK+dsdrFOiCjkMyZGRmSxxafoQLY0v1InHQvAsYnPvQpNODd+Id71ImrXs3lKr -If98onjcZT97UL+9gGH8Pxy/srlpOcEV4W1VokDevugBUoXd7iT6Epi1wbHeJuHW -wZ1SCw7Hom2XUkbAeNViEt0AFLQMv4BEII7yb9BubTmPuT0L7f7PaLN2wK9Fk0n8 -5wgFAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAEu+qOvpj9/Wy6Og8btB1c2N4B+Q -gROsAHM8mD7WYDn58TeuvmZcdEHhCX9zloWpcmRs5Qs+gIhCLkodcqdxnMQsW1GS -tR3qaz+66t5j8YhxVTnepAkJ2aa3xbiwRDM4SOsyO67g4UeljrXCli9Trgcrpyhy -NIAmLtrMqDhP0TIHIY0ijY/xi/8O+2WCtuA/ZoHWzM/dRmK25MKC/zCOJ8li5Nlk -tI9BriHAvEvlUjke/9nDYhA2Wh6qz1u+PXw2jSCgIP3PIhVPVDY8N3fx3aHnJgVx -mvYbFa3YyFvhhKY0riZdPfZEFFNX04aFiH1rteIZXV82c3MSzJZiOPPAYhg= +MIIB5zCCAY0CFBtkn+/dmBb1+nwqanbcwSNBoUJtMAoGCCqGSM49BAMCMIGBMRMw +EQYKCZImiZPyLGQBGRYDREFRMQswCQYDVQQGEwJVUzEVMBMGA1UECAwMTW91bnRh +aW5WaWV3MQ8wDQYDVQQHDAZLaW5nc1gxDDAKBgNVBAoMA0RBUTERMA8GA1UECwwI +U29mdHdhcmUxFDASBgNVBAMMC0RBUSBDQSBSb290MB4XDTIwMDgxODIxMjY1OFoX +DTIxMTIzMTIxMjY1OFowajELMAkGA1UEBhMCVVMxFTATBgNVBAgMDE1vdW50YWlu +VmlldzEPMA0GA1UEBwwGS2luZ3NYMQwwCgYDVQQKDANEQVExETAPBgNVBAsMCFNv +ZnR3YXJlMRIwEAYDVQQDDAkxMjcuMC4wLjEwWTATBgcqhkjOPQIBBggqhkjOPQMB +BwNCAAQ/sTIhNsoG5/SZ+eEHtpK2KpQirKVIw1oLdecsgt6sGONAI6tRY+iHhIDL +3F9rMwDv+JICFSnBOGgOHFve4pUHMAoGCCqGSM49BAMCA0gAMEUCID7hLKM/FDu3 +WDhHjTxZy/8j3CWMqA01z+3sBNsiQzBTAiEAgKv1sqSeOuMPyLgzC2w0OMUMKWBZ +W2Rf0Nml1Oa5//o= -----END CERTIFICATE----- diff --git a/docker/include/security/tlsfaux/certs/server.csr b/docker/include/security/tlsfaux/certs/server.csr index c0efbb3a04..c71590d197 100644 --- a/docker/include/security/tlsfaux/certs/server.csr +++ b/docker/include/security/tlsfaux/certs/server.csr @@ -1,17 +1,9 @@ -----BEGIN CERTIFICATE REQUEST----- -MIICszCCAZsCAQAwbjELMAkGA1UEBhMCR0IxDzANBgNVBAgMBkxvbmRvbjEPMA0G -A1UEBwwGS2luZ3NYMRYwFAYDVQQKDA1FeGNlbFJlZHN0b25lMREwDwYDVQQLDAhT -b2Z0d2FyZTESMBAGA1UEAwwJMTI3LjAuMC4xMIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEA3IBCZo9EzORMdughFRoDI1pMoB8L3k/hoSOwe/vcsTzDoTjB -KACSoBi4RRLdyK84MXKwUVMlnVeJm8/NtSJ/7DMS1Y3zxZokxWJIw2s5p/GUK7bh -II/8Z6UGb1R0AktSaDP15lVfCVdEgGOddwQYCvnbHaxTogo5DMmRkZkscWn6EC2N -L9SJx0LwLGJz70KTTg3fiHe9SJq17N5SqyH/fKJ43GU/e1C/vYBh/D8cv7K5aTnB -FeFtVaJA3r7oAVKF3e4k+hKYtcGx3ibh1sGdUgsOx6Jtl1JGwHjVYhLdABS0DL+A -RCCO8m/Qbm05j7k9C+3+z2izdsCvRZNJ/OcIBQIDAQABoAAwDQYJKoZIhvcNAQEL -BQADggEBAAjiq319PYrwINIM5Gu3cnG5ZvGNUl6jAjn1DCeZ8G5Qz+S0gTfPheC9 -TgyAtkLpGr74OjF39wtNHIcJ/dtFHAV39H8NEhTFSp2stWtuAZtaulQ6zrgzL0L8 -whIeGRSfzU865WIrDfrx4bJbZN0gjV27Grr0LOvAcicJt08K1Tby9feEGWJdNQjo -4Ehg+8uGrgUIOTXFlytEoZn1z5SJiyYN/p46MVH/EeY3eq+EzenDYMX43W2lBt28 -9O9c+tUnSoRxGuuMTAkAxlmB5z9JtzXsSzryQTk7ULXqM3GSYNJt5ad8KW7ploSZ -mrMNUsqshZN2EjPAIAp9MP6wvWIlnZQ= +MIIBJDCBzAIBADBqMQswCQYDVQQGEwJVUzEVMBMGA1UECAwMTW91bnRhaW5WaWV3 +MQ8wDQYDVQQHDAZLaW5nc1gxDDAKBgNVBAoMA0RBUTERMA8GA1UECwwIU29mdHdh +cmUxEjAQBgNVBAMMCTEyNy4wLjAuMTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA +BD+xMiE2ygbn9Jn54Qe2krYqlCKspUjDWgt15yyC3qwY40Ajq1Fj6IeEgMvcX2sz +AO/4kgIVKcE4aA4cW97ilQegADAKBggqhkjOPQQDAgNHADBEAiBW4Rf+O8igPdEw +uqFwxAKUgKQfOmWrnvtcNgSp30Yo3wIgB/Ef+N+K8MnnwF7BRD3b/qJteR5Bu8w4 +ewCLTe/JpD4= -----END CERTIFICATE REQUEST----- diff --git a/docker/include/security/tlsfaux/certs/server.key b/docker/include/security/tlsfaux/certs/server.key index 30609a2d8b..dd45e7ddda 100644 --- a/docker/include/security/tlsfaux/certs/server.key +++ b/docker/include/security/tlsfaux/certs/server.key @@ -1,28 +1,5 @@ -----BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDcgEJmj0TM5Ex2 -6CEVGgMjWkygHwveT+GhI7B7+9yxPMOhOMEoAJKgGLhFEt3IrzgxcrBRUyWdV4mb -z821In/sMxLVjfPFmiTFYkjDazmn8ZQrtuEgj/xnpQZvVHQCS1JoM/XmVV8JV0SA -Y513BBgK+dsdrFOiCjkMyZGRmSxxafoQLY0v1InHQvAsYnPvQpNODd+Id71ImrXs -3lKrIf98onjcZT97UL+9gGH8Pxy/srlpOcEV4W1VokDevugBUoXd7iT6Epi1wbHe -JuHWwZ1SCw7Hom2XUkbAeNViEt0AFLQMv4BEII7yb9BubTmPuT0L7f7PaLN2wK9F -k0n85wgFAgMBAAECggEAONm0xP6RTYZbFJk61lbzkizY7ruycqoD0WkDOqQwPV4e -TjX0zxx+sVpOQDjiB7jtcwpP3VfjrdKA/zQvpFD1zG9KntbPkBXy/xUdD41Yuy00 -96RaHOwitpI8u315v5Gt+IHVF4LRUvY2Cigk1CexDztmPBtPIMsj9GEP8AsfA0pF -9EFdnanVOPMRhOSaBSG6gb85AbxQt3PLmfoeDixXZYKvhnViqmpyVnMvgLAC31E/ -n9RSzcQNkcDtJYDL5E6hCC+uGs8WNcmVoaW3uiJulT4/s0HD9O52Oj9P65eiBFiJ -tRnZ4hDIvNfcNm+aYXNSdeSqLEP8LrnCtR8SqtkXjQKBgQD4lQGOnGHS0Rq9wtSn -4gT+IGWOQtrblOUCzpZBwoje9Tb0pb6A2uVNnomJQS5WlWmobYrrP3L9fP3f1vgl -152adIox2Urt2q4FafL+4pzqeErPx+jaBv3cEGyj98QYtXNzMBvXmDtVMja5Ibp3 -VKu7iGFboqgqGWWMX5fN9MRG3wKBgQDjFLvSOsuHg1s7dTPwqN8b4/QuKyera7yP -5YQyx+1qniUJBYjOHRPJvRFzqbHz+cV0LE1U2+sHz1UFh3859RDJrI63K22NHfRt -PfVLLVHCx2A1CYz0YX4rYK42EWU9tXqSsiIi8C8twdmoC0u8vs6aFbxcYIT1IqnS -c0umTZ7BmwKBgEe5xu89VESeLVcfxniCkOo6stLvm3LMbZ/3uAdVeGTM4ISK5oML -pipVWl4OPq6hAhGlOfZTInzd+esCfit9IW6VveJQTnx/IsNRJNpCzQAioYN+rUNr -zQgYfSB6t0xh3uQXt5DnzgbxLDUS9FjGR58e5Oip8FflaBWu54B35cKFAoGAJVr6 -zsmnQ6KjNnPAWJ2fHjpwp8unmfZ+LXnHNodXEgvz8bj8WVPFNpGotks7H/R9u++x -xPzse/tqdB9nGYSr/1EopQ861VURKYtgt747zfv4YqEwk98Z307nObPA4Nbi1BED -tpWmXTOfd5psGh+VYxmiQ9wI4z6RizI2RqRMMnMCgYEAsvLIpFAkCaEXSePIrdBp -vmMKPHemXdrGTARxMvpbToI2LNepxmLhQyrk8Uc5RBCcuXjj1pPYWu8OBBr1IJDY -eR/VFGbVcH8VJwjMz6J2wYzzeisdOFozRJYNN6e4vliW9Qvmzwtn1FO2WmE8Pgfm -dD6LxwRjqb5tlKZyFvyySXo= +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgEFbGwvyFmjazEnd9 +BPgG8ZIIdgaQ1NCEr5c55UU0U4yhRANCAAQ/sTIhNsoG5/SZ+eEHtpK2KpQirKVI +w1oLdecsgt6sGONAI6tRY+iHhIDL3F9rMwDv+JICFSnBOGgOHFve4pUH -----END PRIVATE KEY----- diff --git a/docker/include/security/tlsfaux/client.py b/docker/include/security/tlsfaux/client.py new file mode 100644 index 0000000000..eb2342d511 --- /dev/null +++ b/docker/include/security/tlsfaux/client.py @@ -0,0 +1,39 @@ +from __future__ import absolute_import +import ssl +import sys +import time + +arguments = sys.argv +HOST = "" +PORT = 443 +VERSION = arguments[1] + +try: + HOST = arguments[2] +except Exception: + pass + +SSL_VERSION = None +if(VERSION == "1.2"): + # Force TLS 1.2 + SSL_VERSION = ssl.PROTOCOL_TLSv1_2 +elif(VERSION == "1.3"): + # Pick highest version which should be 1.3 + SSL_VERSION = ssl.PROTOCOL_TLS + + +print("SSL Client Started...") +while len(HOST) > 0: + try: + print("Getting Server Certificate...") + cert = ssl.get_server_certificate((HOST, PORT), ssl_version=SSL_VERSION) + if(len(cert) > 0): + print("Server Certificate Resolved") + else: + print("No Certificate Resolved") + except Exception as e: + print("Server Certificate Failure") + print(e) + finally: + time.sleep(30) +print("SSL Client Stopped") diff --git a/docker/include/security/tlsfaux/generate_certs.py b/docker/include/security/tlsfaux/generate_certs.py index 05822f19b5..4f1eaa510e 100644 --- a/docker/include/security/tlsfaux/generate_certs.py +++ b/docker/include/security/tlsfaux/generate_certs.py @@ -2,8 +2,47 @@ filepath = "/".join(absolute_filepath.script_directory) + "/certs/" -command_key = 'openssl req -nodes -newkey rsa:2048 -keyout ' + filepath + 'server.key -out ' + filepath + 'server.csr -subj "/C=GB/ST=London/L=KingsX/O=ExcelRedstone/OU=Software/CN=127.0.0.1"' -command_cert ='openssl x509 -req -days 365 -in ' + filepath + 'server.csr -signkey ' + filepath + 'server.key -out ' + filepath + 'server.crt' +# This may be needed, not sure yet, needs more validation testing +command_rnd = 'touch /root/.rnd' + +# Create the ecparam key to allow for DH/DHE/ECDSA ciphers +command_ecparam = 'openssl ecparam -out ' + filepath + 'ecparam.pem -name prime256v1' + +# Create a CA Root Key +command_ca_key = 'openssl genpkey -paramfile ' + filepath + 'ecparam.pem -out ' + filepath + 'CA_Faux.key' + +# Create and self sign the root Certificat e +command_ca_crt = 'openssl req -x509 -new -key ' + filepath + 'CA_Faux.key -out ' + filepath + 'CA_Faux.pem -subj "/DC=DAQ/C=US/ST=MountainView/L=KingsX/O=DAQ/OU=Software/CN=DAQ CA Root"' + + + +# Create the intermediate key +# command_int_key ='openssl genrsa -out ' + filepath +'intermediate.key 4096' + +# Create an intermediate key and csr +# command_int_key_csr = 'openssl req -nodes -newkey rsa:2048 -keyout ' + filepath + 'intermediate.key -out ' + filepath + 'intermediate.csr -subj "/C=US/ST=MountainView/L=KingsX/O=DAQ/OU=Software/CN=DAQ Intermediate"' + +# Generate the intermediate using the csr and sign with the CA Root key +# command_int_cert = 'openssl x509 -req -in ' + filepath + 'intermediate.csr -CA ' + filepath + 'CA_Faux.pem -CAkey ' + filepath + 'CA_Faux.key -CAcreateserial -out ' + filepath + 'intermediate.pem -days 500 -sha256' + + + +# Create a server private key +command_server_key = 'openssl genpkey -paramfile ' + filepath + 'ecparam.pem -out ' + filepath + 'server.key' + +# Create a server csr +command_server_csr = 'openssl req -nodes -newkey ec:'+ filepath + 'ecparam.pem -keyout ' + filepath + 'server.key -out ' + filepath + 'server.csr -subj "/C=US/ST=MountainView/L=KingsX/O=DAQ/OU=Software/CN=127.0.0.1"' + +# Generate the server cert using the csr and sign with the CA Root key +command_server_cert = 'openssl x509 -req -in ' + filepath + 'server.csr -CA ' + filepath + 'CA_Faux.pem -CAkey ' + filepath + 'CA_Faux.key -CAcreateserial -out ' + filepath + 'server.crt -days 500 -sha256' + +# Generate the certificate using the csr and sign with the Intermediate Root key +# command_cert = 'openssl x509 -req -in ' + filepath + 'server.csr -CA ' + filepath + 'intermediate.pem -CAkey ' + filepath + 'intermediate.key -CAcreateserial -out ' + filepath + 'server.pem -days 500 -sha256' + + +# Combine the CA and root into one cert +# command_combine = 'cat ' + filepath + 'server.pem ' + filepath + 'CA_Faux.pem > ' + filepath + 'server.crt' + def run_shell_command(command): process = subprocess.Popen(command, universal_newlines=True, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) @@ -12,5 +51,12 @@ def run_shell_command(command): if len(text) > 0: print(text) -run_shell_command(command_key) -run_shell_command(command_cert) +run_shell_command(command_rnd) +run_shell_command(command_ecparam) + +run_shell_command(command_ca_key) +run_shell_command(command_ca_crt) + +run_shell_command(command_server_key) +run_shell_command(command_server_csr) +run_shell_command(command_server_cert) diff --git a/docker/include/security/tlsfaux/server.py b/docker/include/security/tlsfaux/server.py index a0454b3931..d27d4a98b3 100644 --- a/docker/include/security/tlsfaux/server.py +++ b/docker/include/security/tlsfaux/server.py @@ -16,26 +16,31 @@ context.load_cert_chain(certfile=filename_cert, keyfile=filename_key) bind_socket = socket.socket() +bind_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) bind_socket.bind((hostname,port)) bind_socket.listen(5) def test_data(connstream,data): - print("test_data:",data) - return false + print("test_data:",data) + return false def read_client_data(connstream): - data = connstream.read() - while data: - if not test_data(connstream,data): - break - data = connstream.read() + data = connstream.read() + while data: + if not test_data(connstream,data): + break + data = connstream.read() print("SSL Server started...") while True: - newsocket, fromaddr = bind_socket.accept() - connstream = context.wrap_socket(newsocket, server_side=True) - try: - read_client_data(connstream) - finally: - connstream.shutdown(socket.SHUT_RDWR) - connstream.close() + newsocket, fromaddr = bind_socket.accept() + connstream = context.wrap_socket(newsocket, server_side=True) + print(connstream.cipher()) + print(connstream.version()) + try: + read_client_data(connstream) + except: + pass + finally: + connstream.shutdown(socket.SHUT_RDWR) + connstream.close() diff --git a/docker/modules/Dockerfile.aardvark2 b/docker/modules/Dockerfile.aardvark2 new file mode 100644 index 0000000000..2c9ba954c4 --- /dev/null +++ b/docker/modules/Dockerfile.aardvark2 @@ -0,0 +1,24 @@ +# Image name: daqf/aardvark +# +# Base image called aardvark because the code is lazy and evaluates alphabetically. +# +# _.---._ /\\ +# ./' "--`\// +# ./ o \ +# /./\ )______ \__ \ +# ./ / /\ \ | \ \ \ \ +# / / \ \ | |\ \ \7 +# " " " " + +# Need to use ubuntu because mininet is very persnickity about versions. +FROM ubuntu:focal + +# Dump all our junks into the root home directory. +WORKDIR /root + +COPY bin/retry_cmd bin/ +COPY docker/include/utils/reporting.sh . + +ENV AG="bin/retry_cmd apt-get -qqy --no-install-recommends -o=Dpkg::Use-Pty=0" + +RUN $AG update && $AG install net-tools bash iproute2 iputils-ping tcpdump strace vim jq nano diff --git a/docs/device_report.md b/docs/device_report.md index 91b32d6ed0..8dec01db66 100644 --- a/docs/device_report.md +++ b/docs/device_report.md @@ -13,7 +13,7 @@ |------------------|------------------------| | Test report start date | XXX | | Test report end date | XXX | -| +| | Attempt number | 1 | ## Device Identification @@ -56,7 +56,7 @@ Overall device result FAIL |---|---|---|---|---|---| |Required|1|0|0|0|0| |Recommended|1|0|0|0|1| -|Other|6|2|21|1|2| +|Other|6|2|20|1|2| |Result|Test|Category|Expectation|Notes| |---|---|---|---|---| @@ -87,12 +87,11 @@ Overall device result FAIL |skip|security.passwords.ssh|Other|Other|Port 22 not open on target device.| |skip|security.passwords.telnet|Other|Other|Port 23 not open on target device.| |gone|security.ports.nmap|Security|Recommended|| -|skip|security.tls.v1|Other|Other|IOException unable to connect to server| -|skip|security.tls.v1.x509|Other|Other|IOException unable to connect to server| -|skip|security.tls.v1_2|Other|Other|IOException unable to connect to server| -|skip|security.tls.v1_2.x509|Other|Other|IOException unable to connect to server| -|skip|security.tls.v1_3|Other|Other|IOException unable to connect to server| -|skip|security.tls.v1_3.x509|Other|Other|IOException unable to connect to server| +|skip|security.tlsv1.server|Other|Other|IOException unable to connect to server.| +|skip|security.tlsv1_2.client|Other|Other|No client initiated TLS communication detected| +|skip|security.tlsv1_2.server|Other|Other|IOException unable to connect to server.| +|skip|security.tlsv1_3.client|Other|Other|No client initiated TLS communication detected| +|skip|security.tlsv1_3.server|Other|Other|IOException unable to connect to server.| |gone|unknown.fake.llama|Other|Other|| |gone|unknown.fake.monkey|Other|Other|| @@ -161,8 +160,8 @@ Automatic TCP/UDP port scan using nmap -------------------- # Nmap XXX scan initiated XXX as: nmap -v -n -T5 -sT -sU --host-timeout=4m --open -pU:47808,T:23,443,80, -oG XXX/tmp/nmap.log X.X.X.X # Ports scanned: TCP(3;23,80,443) UDP(1;47808) SCTP(0;) PROTOCOLS(0;) -Host: X.X.X.X () Status: Up -Host: X.X.X.X () Ports: 47808/closed/udp//bacnet/// +Host: X.X.X.X () Status: Up +Host: X.X.X.X () Ports: 47808/closed/udp//bacnet/// # Nmap done at XXX -- 1 IP address (1 host up) scanned in XXX No invalid ports found. -------------------- @@ -175,8 +174,8 @@ Check that the device does not have open ports exposing an unencrypted web inter -------------------- # Nmap XXX scan initiated XXX as: nmap -v -n -T5 -A --script http-methods --host-timeout=4m --open -p- -oG XXX/tmp/http.log X.X.X.X # Ports scanned: TCP(65535;1-65535) UDP(0;) SCTP(0;) PROTOCOLS(0;) -Host: X.X.X.X () Status: Up -Host: X.X.X.X () Ports: 10000/open/tcp//snet-sensor-mgmt?/// +Host: X.X.X.X () Status: Up +Host: X.X.X.X () Ports: 10000/open/tcp//snet-sensor-mgmt?/// # Nmap done at XXX -- 1 IP address (1 host up) scanned in XXX No running http servers have been found. -------------------- @@ -308,59 +307,70 @@ RESULT fail protocol.bacnet.pic PICS file defined however a BACnet device was no -------------------- Collecting TLS cert from target address --------------------- -security.tls.v1 --------------------- -Verify the device supports TLS 1.0 (as a client) --------------------- -See log above --------------------- -RESULT skip security.tls.v1 IOException unable to connect to server +Gathering TLS 1 Server Information.... +TLS 1Server Implementation Skipping Test, could not open connection +TLS 1 Server Information Complete. + + +Gathering TLS 1.2 Server Information.... +TLS 1.2Server Implementation Skipping Test, could not open connection +TLS 1.2 Server Information Complete. + + +Gathering TLS 1.3 Server Information.... +TLS 1.3Server Implementation Skipping Test, could not open connection +TLS 1.3 Server Information Complete. + + +Gathering TLS Client X.X.X.X Information.... +TLS Client Information Complete. +Gathering TLS Client X.X.X.X Information.... +TLS Client Information Complete. -------------------- -security.tls.v1.x509 +security.tlsv1.server -------------------- -Verify the devices supports RFC 2459 - Internet X.509 Public Key Infrastructure Certificate and CRL Profile +Verify the device supports at least TLS 1.0 (as a server) -------------------- See log above -------------------- -RESULT skip security.tls.v1.x509 IOException unable to connect to server +RESULT skip security.tlsv1.server IOException unable to connect to server. -------------------- -security.tls.v1_2 +security.tlsv1_2.client -------------------- -Verify the device supports TLS 1.2 (as a client) +null -------------------- See log above -------------------- -RESULT skip security.tls.v1_2 IOException unable to connect to server +RESULT skip security.tlsv1_2.client No client initiated TLS communication detected -------------------- -security.tls.v1_2.x509 +security.tlsv1_2.server -------------------- -null +Verify the device supports TLS 1.2 (as a server) -------------------- See log above -------------------- -RESULT skip security.tls.v1_2.x509 IOException unable to connect to server +RESULT skip security.tlsv1_2.server IOException unable to connect to server. -------------------- -security.tls.v1_3 +security.tlsv1_3.client -------------------- -Verify the device supports TLS 1.3 (as a client) +null -------------------- See log above -------------------- -RESULT skip security.tls.v1_3 IOException unable to connect to server +RESULT skip security.tlsv1_3.client No client initiated TLS communication detected -------------------- -security.tls.v1_3.x509 +security.tlsv1_3.server -------------------- -Verify the devices supports RFC 2459 - Internet X.509 Public Key Infrastructure Certificate and CRL Profile +Verify the device supports TLS 1.3 (as a server) -------------------- See log above -------------------- -RESULT skip security.tls.v1_3.x509 IOException unable to connect to server +RESULT skip security.tlsv1_3.server IOException unable to connect to server. ``` @@ -369,6 +379,7 @@ RESULT skip security.tls.v1_3.x509 IOException unable to connect to server |Attribute|Value| |---|---| |enabled|True| +|ca_file|CA_Faux.pem| ## Module password diff --git a/resources/setups/baseline/module_config.json b/resources/setups/baseline/module_config.json index 3f74efb2ac..9c40ffca15 100644 --- a/resources/setups/baseline/module_config.json +++ b/resources/setups/baseline/module_config.json @@ -27,7 +27,8 @@ "enabled": true }, "tls": { - "enabled": true + "enabled": true, + "ca_file": "CA_Faux.pem" }, "udmi": { "enabled": true diff --git a/subset/security/Dockerfile.test_tls b/subset/security/Dockerfile.test_tls index 7da5add6d9..0525d27b68 100644 --- a/subset/security/Dockerfile.test_tls +++ b/subset/security/Dockerfile.test_tls @@ -1,9 +1,10 @@ -FROM daqf/aardvark:latest +FROM daqf/aardvark2:latest + # Do this alone first so it can be re-used by other build files. RUN $AG update && $AG install openjdk-11-jre -RUN $AG update && $AG install openjdk-11-jdk git +RUN $AG update && $AG install openjdk-11-jdk git tshark COPY subset/security/ . diff --git a/subset/security/readme.md b/subset/security/readme.md index fc4653e5e6..9d411dc831 100644 --- a/subset/security/readme.md +++ b/subset/security/readme.md @@ -1,48 +1,66 @@ # Security testing ## test_tls -The TLS test attempts to verify various versions of TLS support. Separate connections will be attempted with different SSL context with the associated TLS support, 1.0, 1.2 and 1.3. +The TLS test attempts to verify various versions of TLS support. Separate connections will be attempted with different SSL context with the associated TLS support, 1.0, 1.2 and 1.3 to teset devices server TLS capabilities. A 5 min max scan period is also used to capture TLS client level capabilities for TLS 1.2 and 1.3. -### Testing procedure +### Testing procedure for server testing After establishing connections to devices, the test will proceed to validate the available certificates with the following criteria: 1. The certificate is in the x509 format - 2. The public key length is at least 2048. Currently handles both RSA and DSA public key formats. - 3. The certificate is not expired and active for the current date. -The cipher suite used is also checked but does not currently affect the outcome of the results. Currently the expected cipher suites are ECDH and ECSA. If these are not present, a warning message will be logged in the activate.log of the switch node. + 2. The public key length is at the correct bit length + - If public key is RSA format - Key length must be at least 2048 + - If public key is EC format - key length must be at least 224 + 3. The certificate is not expired and active for the current date + 4. The cipher suite is valid:(only for TLS < 1.3) + - If RSA public key format - No cipher check is required + - If EC pubic key format - Check if cipher suites ECDH and ECSA are present +5. The certificat is signed by a CA. This can be a local CA from the manufacturer and does not require an official CA signature. + +### Testing procedure for client testing +A 5 minute maximum scan period is utilized to analyze outbound traffic from the device. A thirty second wait period between scans is utilized to allow for early completion of the test and not require the full 5 minutes if possible. The results expec the following criteria to pass for TLS 1.2 and 1.3 success. + +1. Device initiates handshake on ports 443(HTTPS) or 8883 (MQTT) +2. Server completes the handshake +3. Device is supports ECDH and ECDSA ciphers. Only checked for TLS 1.2 - ### Note for test developers -The functional test code is included in the `tlstest/src/main/java` folder. +The functional test code is included in the `tlstest/src/main/java` folder - ### Conditions for security.tls.v1 - - pass -> If the device responds to a connection with TLS 1.0 support and provides a valid certificate. - - fail -> If the device responds to a connection with TLS 1.0 support and provides an invalid certificate. - - skip -> If no connection to the device can be established. +### Available Configurations: +The tls test requires specifying the CA certificate used to sign the signature for validation. If this is not added, DAQ will still run the test but will always show failure results for the server tests. To do this, you need to add the name of the ca_file to the modules section of the device config_module.json. See the below example: +``` + "modules": { + "tls": { + "ca_file": "ca.pem" + } + } +``` +The file must be loaded into the aux directory of the device, i.e local/site/mac_addres//aux/ca.pem -### Conditions for security.tls.v1.x509 - - pass -> If the device responds to a connection with TLS 1.0 support and provides a valid certificate. - - fail -> If the device responds to a connection with TLS 1.0 support and provides an invalid certificate. + ### Conditions for security.tls.v1.server + - pass -> If the device responds to a connection with TLS 1.0, support and provides a valid certificate, has a valid key length and has a valid cipher suite. + - fail -> If the device responds to a connection with TLS 1.0 support and provides an invalid certificate or provides an invalid key length or an invalid cipher suite. - skip -> If no connection to the device can be established. -### Conditions for security.tls.v1_2 - - pass -> If the device responds to a connection with TLS 1.2 support and provides a valid certificate. - - fail -> If the device responds to a connection with TLS 1.2 support and provides an invalid certificate. + ### Conditions for security.tls.v1_2.server + - pass -> If the device responds to a connection with TLS 1.2, support and provides a valid certificate, has a valid key length and has a valid cipher suite. + - fail -> If the device responds to a connection with TLS 1.2 support and provides an invalid certificate or provides an invalid key length or an invalid cipher suite. - skip -> If no connection to the device can be established. -### Conditions for security.tls.v1_2.x509 - - pass -> If the device responds to a connection with TLS 1.2 support and provides a valid certificate. - - fail -> If the device responds to a connection with TLS 1.2 support and provides an invalid certificate. + ### Conditions for security.tls.v1_3.server + - pass -> If the device responds to a connection with TLS 1.3, support and provides a valid certificate and has a valid key length. + - fail -> If the device responds to a connection with TLS 1.3 support and provides an invalid certificate or provides an invalid key length. - skip -> If no connection to the device can be established. -### Conditions for security.tls.v1_3 - - pass -> If the device responds to a connection with TLS 1.3 support and provides a valid certificate. - - fail -> If the device responds to a connection with TLS 1.3 support and provides an invalid certificate. - - skip -> If no connection to the device can be established. + ### Conditions for security.tls.v1_2.client + - pass -> If the device makes a TLS 1.2 connection to an external server and the server completes the handshake. The device must support the ECDH and ECDSA cipher suites during the handshake. + - fail -> If the attemps to make a TLS 1.2 connection to an external server and the server does not complete the handshake or if the handshake does not includes the ECDH and ECDSA cipher suite support. + - skip -> If no TLS 1.2 device initiated connection can be detected. + + ### Conditions for security.tls.v1_3.client + - pass -> If the device makes a TLS 1.3 connection to an external server and the server completes the handshake. + - fail -> If the attemps to make a TLS 1.3 connection to an external server and the server does not complete the handshake. + - skip -> If no TLS 1.3 device initiated connection can be detected. -### Conditions for security.tls.v1_3.x509 - - pass -> If the device responds to a connection with TLS 1.3 support and provides a valid certificate. - - fail -> If the device responds to a connection with TLS 1.3 support and provides an invalid certificate. - - skip -> If no connection to the device can be established. ## test_password The password test runs a dictionary brute force on protocols HTTP, HTTPS, SSH and Telnet to check if the device has changed login credentials from defaults to a more secure combination. diff --git a/subset/security/test_tls b/subset/security/test_tls index b73af6c615..7bf08ec75b 100755 --- a/subset/security/test_tls +++ b/subset/security/test_tls @@ -5,13 +5,25 @@ LOCAL_REPORT=tmp/report.txt RESULT_LINES=/tmp/result_lines.txt MONO_LOG=/tmp/mono-log.txt +DEVICE_CONFIG=/config/device/ MANIFEST=./tls.module_manifest.json MODULE_CONFIG=/config/device/module_config.json if [ -n "$TARGET_IP" ]; then echo Collecting TLS cert from target address %% $TARGET_IP > $MONO_LOG - java -jar tlstest/build/libs/tlstest.jar $TARGET_IP + export CA_FILE="None" + if [ -f "$MODULE_CONFIG" ]; then + echo "Module Config present" + CA_FILE=`jq -r .modules.tls.ca_file $MODULE_CONFIG` + elif [ -f "$DEVICE_CONFIG/CA_Faux.pem" ]; then + echo "CA Faux found" + #Module test won't have a module_config file but injects the CA file + #directly where it should be + CA_FILE="CA_Faux.pem" + fi + + java -jar tlstest/build/libs/tlstest.jar $TARGET_IP $CA_FILE grep "RESULT" $LOCAL_REPORT | tee -a $RESULT_LINES grep -v "RESULT" $LOCAL_REPORT | tee -a $MONO_LOG @@ -31,3 +43,4 @@ else $RESULT_LINES fi + diff --git a/subset/security/tls.module_manifest.json b/subset/security/tls.module_manifest.json index 3420ccf751..881e4c54ef 100644 --- a/subset/security/tls.module_manifest.json +++ b/subset/security/tls.module_manifest.json @@ -1,20 +1,17 @@ { - "security.tls.v1_3": { - "description": "Verify the device supports TLS 1.3 (as a client)" - }, - "security.tls.v1_3.x509": { - "description": "Verify the devices supports RFC 2459 - Internet X.509 Public Key Infrastructure Certificate and CRL Profile" - }, - "security.tls.v1_2": { - "description": "Verify the device supports TLS 1.2 (as a client)" - }, - "security.tls.v1_2.x509": { - "desc": "Verify the devices supports RFC 2459 - Internet X.509 Public Key Infrastructure Certificate and CRL Profile" - }, - "security.tls.v1": { - "description": "Verify the device supports TLS 1.0 (as a client)" - }, - "security.tls.v1.x509": { - "description": "Verify the devices supports RFC 2459 - Internet X.509 Public Key Infrastructure Certificate and CRL Profile" - } -} + "security.tlsv1.server": { + "description": "Verify the device supports at least TLS 1.0 (as a server)" + }, + "security.tlsv1_2.server": { + "description": "Verify the device supports TLS 1.2 (as a server)" + }, + "security.tlsv1_3.server": { + "description": "Verify the device supports TLS 1.3 (as a server)" + }, + "security.tlsv1_2.client": { + "desc": "Verify the device supports at least TLS 1.2 (as a client)" + }, + "security.tlsv1_3.client": { + "desc": "Verify the device supports at least TLS 1.3 (as a client)" + } +} \ No newline at end of file diff --git a/subset/security/tlstest/build.gradle b/subset/security/tlstest/build.gradle index 273d4123c1..a7957055f2 100644 --- a/subset/security/tlstest/build.gradle +++ b/subset/security/tlstest/build.gradle @@ -7,8 +7,8 @@ apply plugin: 'java' apply plugin: 'application' apply plugin: 'eclipse' mainClassName = "Main" -sourceCompatibility = 1.8 -targetCompatibility = 1.8 +sourceCompatibility = 1.11 +targetCompatibility = 1.11 repositories { jcenter() @@ -18,8 +18,10 @@ dependencies { api 'org.apache.commons:commons-math3:3.6.1' implementation 'com.google.guava:guava:23.0' - + compile 'com.google.code.gson:gson:2.8.6' + compile group: 'org.bouncycastle', name: 'bcprov-jdk16', version: '1.45' testImplementation 'junit:junit:4.13' + } jar { @@ -28,4 +30,8 @@ jar { 'Main-Class': 'Main' ) } -} \ No newline at end of file + from { + configurations.compileClasspath.filter{ it.exists() }.collect { it.isDirectory() ? it : zipTree(it) } + } + exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA' +} diff --git a/subset/security/tlstest/src/main/java/CertificateSignatureStatus.java b/subset/security/tlstest/src/main/java/CertificateSignatureStatus.java new file mode 100644 index 0000000000..afc62ad4f3 --- /dev/null +++ b/subset/security/tlstest/src/main/java/CertificateSignatureStatus.java @@ -0,0 +1,4 @@ +public enum CertificateSignatureStatus { + CERTIFICATE_CA_SIGNED, + CERTIFICATE_SELF_SIGNED, +} diff --git a/subset/security/tlstest/src/main/java/CertificateStatus.java b/subset/security/tlstest/src/main/java/CertificateStatus.java index 83dc200307..e58dfb263b 100644 --- a/subset/security/tlstest/src/main/java/CertificateStatus.java +++ b/subset/security/tlstest/src/main/java/CertificateStatus.java @@ -4,5 +4,4 @@ public enum CertificateStatus { CERTIFICATE_NOT_YET_VALID, CERTIFICATE_EXPIRED, CERTIFICATE_TYPE_UNSUPPORTED, - PUBLIC_KEY_INVALID_LENGTH } diff --git a/subset/security/tlstest/src/main/java/Certs.java b/subset/security/tlstest/src/main/java/Certs.java deleted file mode 100644 index 700fee6085..0000000000 --- a/subset/security/tlstest/src/main/java/Certs.java +++ /dev/null @@ -1,302 +0,0 @@ -import java.io.IOException; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; -import java.security.PublicKey; -import java.security.cert.Certificate; -import java.security.cert.CertificateExpiredException; -import java.security.cert.CertificateNotYetValidException; -import java.security.cert.X509Certificate; -import java.security.interfaces.DSAPublicKey; -import java.security.interfaces.RSAPublicKey; -import javax.net.ssl.*; - -public class Certs { - - public static String ipAddress; - public static int port; - - public Certs(String ipAddress, int port) { - this.ipAddress = ipAddress; - this.port = port; - } - - String certificateReport = ""; - Report report = new Report(); - - public boolean testTLSVersions() throws Exception { - try { - boolean tlsV10 = testTlsVersion("1"); - boolean tlsV12 = testTlsVersion("1.2"); - boolean tlsV13 = testTlsVersion("1.3"); - return tlsV10 || tlsV12 || tlsV13; - } finally { - report.writeReport(certificateReport); - } - } - - private boolean testTlsVersion(String tlsVersion) throws Exception { - SSLSocket socket; - try { - // Attempt to open an SSL Socket at the TLS version specified - socket = makeSSLSocket(ipAddress, port, "TLSv" + tlsVersion); - } catch (IOException e) { - System.out.println("TLSv" + tlsVersion + " Failed: " + e.getMessage()); - e.printStackTrace(); - skipTls(tlsVersion); - skipTlsX509(tlsVersion); - return false; - } - - // Validate Server Certificates While using specified TLS version - CertificateStatus certStatus = CertificateStatus.CERTIFICATE_INVALID; - try { - Certificate[] certificates = getServerCertificates(socket); - certStatus = validateCertificates(certificates); - } catch (SSLHandshakeException e) { - System.out.println("SSLHandshakeException: Unable to complete handshake:" + e.getMessage()); - e.printStackTrace(); - } catch (Exception e) { - System.out.println("Certificate Validation Failed: " + e.getMessage()); - e.printStackTrace(); - } - - validateCipher(socket); - passTls(certStatus, tlsVersion); - passX509(certStatus, tlsVersion); - return certStatus == CertificateStatus.CERTIFICATE_VALID; - } - - /** - * Validate the Cipher while using specified TLS Version - * - * @param socket SSLSocket to use to retrieve the cipher - * @return - */ - private boolean validateCipher(SSLSocket socket) { - try { - String cipher = getSessionCipher(socket); - certificateReport += "Cipher:" + cipher + "\n"; - boolean ecdh = cipher.toUpperCase().contains("ECDH"); - if (ecdh) { - certificateReport += "Cipher Suite ECDH present.\n"; - } else { - certificateReport += "WARNING: Cipher Suite ECDH NOT present.\n"; - } - boolean ecdhsa = cipher.toUpperCase().contains("ECDSA"); - if (ecdhsa) { - certificateReport += "Cipher Suite ECDSA present.\n"; - } else { - certificateReport += "WARNING: Cipher Suite ECDSA NOT present.\n"; - } - return ecdh && ecdhsa; - } catch (Exception e) { - System.out.println("Cipher Validation Failed: " + e.getMessage()); - e.printStackTrace(); - return false; - } - } - - private CertificateStatus validateCertificates(Certificate[] certificates) { - for (Certificate certificate : certificates) { - - if (certificate instanceof X509Certificate) { - try { - certificateReport += "Certificate:\n" + certificate + "\n"; - // Check the expiration date - X509Certificate x509Certificate = (X509Certificate) certificate; - x509Certificate.checkValidity(); - certificateReport += "Certificate is active for current date.\n\n"; - // Check the public key bit length is at least 2048 - PublicKey key = x509Certificate.getPublicKey(); - int keyLength = 0; - if (key instanceof RSAPublicKey) { - keyLength = ((RSAPublicKey) key).getModulus().bitLength(); - } else if (key instanceof DSAPublicKey) { - keyLength = ((DSAPublicKey) key).getParams().getP().bitLength(); - } - if (keyLength >= 2048) { - certificateReport += "Certificate has valid public key length: " + keyLength + "\n\n"; - return CertificateStatus.CERTIFICATE_VALID; - } - return CertificateStatus.PUBLIC_KEY_INVALID_LENGTH; - } catch (CertificateExpiredException cee) { - certificateReport += "Certificate is expired.\n"; - return CertificateStatus.CERTIFICATE_EXPIRED; - } catch (CertificateNotYetValidException e) { - certificateReport += "Certificate not yet valid.\n"; - return CertificateStatus.CERTIFICATE_NOT_YET_VALID; - } - } else { - certificateReport += "Unsupported certificate type.\n"; - return CertificateStatus.CERTIFICATE_TYPE_UNSUPPORTED; - } - } - return CertificateStatus.CERTIFICATE_INVALID; - } - - private void passX509(CertificateStatus status, String tlsVersion) { - - if (status == CertificateStatus.CERTIFICATE_VALID) { - certificateReport += - "RESULT pass security.tls.v" - + tlsVersion.replace(".", "_") - + ".x509 " - + getCertStatusMessage(status) - + "\n"; - } else { - certificateReport += - "RESULT fail security.tls.v" - + tlsVersion.replace(".", "_") - + ".x509 " - + getCertStatusMessage(status) - + "\n"; - } - - // if (status) { - // certificateReport += "RESULT pass security.tls.v" + tlsVersion.replace(".", "_") + - // ".x509\n"; - // } else { - // certificateReport += "RESULT fail security.tls.v" + tlsVersion.replace(".", "_") + - // ".x509\n"; - // } - } - - private void passTls(CertificateStatus status, String tlsVersion) { - if (status == CertificateStatus.CERTIFICATE_VALID) { - certificateReport += - "RESULT pass security.tls.v" - + tlsVersion.replace(".", "_") - + " " - + getCertStatusMessage(status) - + "\n"; - } else { - certificateReport += - "RESULT fail security.tls.v" - + tlsVersion.replace(".", "_") - + " " - + getCertStatusMessage(status) - + "\n"; - } - // - // if (status) { - // certificateReport += "RESULT pass security.tls.v" + tlsVersion.replace(".", "_") + "\n"; - // } else { - // certificateReport += "RESULT fail security.tls.v" + tlsVersion.replace(".", "_") + "\n"; - // } - } - - private String getCertStatusMessage(CertificateStatus status) { - String message = ""; - switch (status) { - case CERTIFICATE_VALID: - message = "Certificate active for current date and public key length > 2048."; - break; - case CERTIFICATE_NOT_YET_VALID: - message = "Certificate not yet active for current date."; - break; - case CERTIFICATE_EXPIRED: - message = "Certificate is expired."; - break; - case CERTIFICATE_TYPE_UNSUPPORTED: - message = "Certificate type is NOT in supported x509 format."; - break; - case PUBLIC_KEY_INVALID_LENGTH: - message = "Certificate public key length is < 2048."; - break; - case CERTIFICATE_INVALID: - default: - message = "Certificate could not be validated."; - } - return message; - } - - private void skipTls(String tlsVersion) { - certificateReport += - "RESULT skip security.tls.v" - + tlsVersion.replace(".", "_") - + " IOException unable to connect to server\n"; - } - - private void skipTlsX509(String tlsVersion) { - certificateReport += - "RESULT skip security.tls.v" - + tlsVersion.replace(".", "_") - + ".x509 IOException unable to connect to server\n"; - } - - /** - * Creates a trust manager to accept all certificates. This is required since we need this test to - * be able to connect to any device and can't know anything about the certificates before hand. - * - * @return A valid TrustManager which accepts all valid X509Certificates - */ - private TrustManager[] trustAllManager() { - // Create a trust manager that does not validate certificate chains - return new TrustManager[] { - new X509TrustManager() { - public java.security.cert.X509Certificate[] getAcceptedIssuers() { - return null; - } - - public void checkClientTrusted(X509Certificate[] certs, String authType) {} - - public void checkServerTrusted(X509Certificate[] certs, String authType) {} - } - }; - } - - /** - * Attemps to complete the SSL handshake and retrieve the Server Certificates. Server certificates - * in this context refers to the device being tested. - * - * @param socket The SSLSocket which connects to the device for testing - * @throws Exception - */ - private Certificate[] getServerCertificates(SSLSocket socket) throws IOException { - socket.startHandshake(); - return socket.getSession().getPeerCertificates(); - } - - /** - * Attemps to complete the SSL handshake and retrieve the Cipher Used. - * - * @param socket The SSLSocket which connects to the device for testing - * @throws Exception - */ - private String getSessionCipher(SSLSocket socket) throws IOException { - socket.startHandshake(); - return socket.getSession().getCipherSuite(); - } - - /** - * @param host This is the host IP address of the device being tested - * @param port This is teh Port of the SSL connection for the device being tested. - * @param protocol The SSL protocol to be tested. - * @return SSLSocket which supports only the SSL protocol defined. - * @throws Exception - */ - private SSLSocket makeSSLSocket(String host, int port, String protocol) - throws NoSuchAlgorithmException, KeyManagementException, IOException { - SSLSocketFactory factory = makeSSLFactory(trustAllManager(), protocol); - - SSLSocket socket = (SSLSocket) factory.createSocket(host, port); - socket.setEnabledProtocols(new String[] {protocol}); - return socket; - } - - /** - * Create an SSLSocketFactory with the defined trust manager and protocol - * - * @param trustManager TrustManager to be used in the SSLContext - * @param protocol The SSL protocol to be used in the SSLContext - * @return An initialized SSLSocketFactory with SSLContext defined by input parameters - * @throws Exception - */ - private SSLSocketFactory makeSSLFactory(TrustManager[] trustManager, String protocol) - throws NoSuchAlgorithmException, KeyManagementException { - // Install the all-trusting trust manager - SSLContext sslContext = SSLContext.getInstance(protocol); - sslContext.init(null, trustManager, new java.security.SecureRandom()); - return sslContext.getSocketFactory(); - } -} diff --git a/subset/security/tlstest/src/main/java/CipherStatus.java b/subset/security/tlstest/src/main/java/CipherStatus.java new file mode 100644 index 0000000000..e9a84893a5 --- /dev/null +++ b/subset/security/tlstest/src/main/java/CipherStatus.java @@ -0,0 +1,6 @@ +public enum CipherStatus { + INVALID, + VALID, + SKIPPED +} + diff --git a/subset/security/tlstest/src/main/java/Client.java b/subset/security/tlstest/src/main/java/Client.java new file mode 100644 index 0000000000..756a8b3db6 --- /dev/null +++ b/subset/security/tlstest/src/main/java/Client.java @@ -0,0 +1,338 @@ +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; + +import java.io.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +public class Client { + private final String clientIpAddress; + private final int[] ports; + private final String[] tlsVersion; + private String captureFile = "/scans/test_tls.pcap"; + private String clientReport = ""; + private int totalScans = 0; + private int maxScans = 10; + + public Client(String clientIpAddress, int[] ports,String[] tlsVersion) { + this.clientIpAddress = clientIpAddress; + this.ports = ports; + this.tlsVersion = tlsVersion; + } + + /** + * Scan the provided capture file and validate it's results. + * @param captureFile Capture file to scan and validate + * @return True indicates file contained expected traffic and could be validated. False indicates no + * traffic could be detected to validate. + */ + private boolean validateCaptureFile(String captureFile,String tlsVersion){ + System.out.println("Scanning Capture File: " + captureFile); + this.captureFile = captureFile; + //Check all servers that have been contacted by the DUT to see + //if they have completed a SSL/TLS handshake + List serverList = getServers(tlsVersion); + if(serverList.size()>0){ + boolean handshakeComplete = serverList.stream().anyMatch(serverIp -> isHandshakeCompleted(serverIp,tlsVersion)); + boolean cipherValid = checkClientCiphers(); + passClient(handshakeComplete, cipherValid,tlsVersion); + return true; + } + else{ + System.out.println("No client initiated TLS communication detected in capture file: " + captureFile); + return false; + } + } + + /** + * Validate all versions of TLS requested for client side communications. + * Scan the capture file a maximum of 10 times between all versions + * which equates to 5 minutes total wait time. Any longer can cause + * a module timeout. + * @return + */ + public String validate(){ + System.out.println("Validating Client TLS Versions..."); + for(int i = 0;i ciphers = getClientCiphers(); + boolean ecdh = isCipherSupported(ciphers,"ECDH"); + boolean ecdsa = isCipherSupported(ciphers,"ECDSA"); + if(ecdh) { + System.out.println("ECDH Client Cipher Detected: " + ecdh); + } + if(ecdh) { + System.out.println("ECDSA Client Cipher Detected: " + ecdsa); + } + return ecdh && ecdsa; + } + + /** + * Inspect the capture file for all hello messages from the client device (DUT) + * @return List List of all client Hello packets resolved + */ + private List getClientCiphers(){ + String[] command = new String[]{"tshark", "-r", captureFile,"-Vx", + "-Y", "ssl.handshake.ciphersuites and ip.src=="+clientIpAddress+""}; + String procRes = runCommand(command,true); + String[] lines = procRes.split("\n"); + System.out.println("Cipher Resp Size: " + lines.length); + List cipherList = new ArrayList(); + Arrays.stream(lines).forEach(line->{ + if(line.contains("Cipher Suite:")){ + line = line.trim(); + if(!cipherList.contains(line)){ + System.out.println("Unique Cipher: " + line); + cipherList.add(line); + } + } + }); + return cipherList; + } + + /** + * Resolve all the servers that the DUT has reached out to over SSL/TLS + * @return List of IP addresses of all the servers resolved + */ + private List getServers(String tlsVersion){ + JsonArray clientHelloPackets = getClientHelloPackets(tlsVersion); + System.out.println("Client Hello Messages Resolved: " + clientHelloPackets.size()); + List serverList = new ArrayList(); + for (int i = 0; i < clientHelloPackets.size(); ++i) { + String serverIp = clientHelloPackets.get(i).getAsJsonObject() + .getAsJsonObject("_source") + .getAsJsonObject("layers") + .getAsJsonObject("ip") + .getAsJsonPrimitive("ip.dst").getAsString(); + if (!serverList.contains(serverIp) && !serverIp.equals(clientIpAddress)) { + serverList.add(serverIp); + System.out.println("Unique Server IP Detected: " + serverIp); + } + } + return serverList; + } + + /** + * Inspect the capture file for all hello messages from the client device (DUT) + * on specified port. + * 0x0303 -> TLS 1.2 + * 0x0304 -> TLS 1.3 + * @return JsonArray of all client Hello packets resolved + */ + private JsonArray getClientHelloPackets(String tlsVersion){ + List commands = new LinkedList(); + commands.add("tshark"); + commands.add("-r"); + commands.add(captureFile); + commands.add("-T"); + commands.add("json"); + commands.add("ssl.handshake.type==1"); + commands.add("and"); + commands.add("ip.src=="+clientIpAddress); + commands.add("and"); + commands.add(getPortsFilter()); + commands.add("and"); + if(tlsVersion == "1.2"){ + commands.add("ssl.handshake.version==0x0303"); + } + else{ + commands.add("tls.handshake.extensions.supported_version==0x0304"); + } + String procRes = runCommand(commands.toArray(new String[0]),false); + //The process can potentially get run as root so account for + //possible nuisance warning messages that mess up the json packet + procRes = procRes.substring(procRes.indexOf('[')); + JsonElement e = JsonParser.parseString(procRes); + return e.getAsJsonArray(); + } + + private String getPortsFilter(){ + StringBuilder sb = new StringBuilder(); + sb.append("("); + for(int i = 0;i0?" or ":""); + sb.append("tcp.port=="+ports[i]); + } + sb.append(")"); + return sb.toString(); + } + + /** + * Inspect the capture file for completed client/server SSL/TLS handshakes + * ssl.handshake.type==14 -> ServerHelloDone indicating handshake has completed for TLS 1.2 + * ssl.handshake.type==2 -> ServerHello indicating handshake has completed for TLS 1.3 + * + * @param serverIp IP address for the server side of the connection + * @return True when a completed handshake can be detected for the server and client + */ + private boolean isHandshakeCompleted(String serverIp,String tlsVersion){ + System.out.println("Checking handshake completion for: " + serverIp+"->"+clientIpAddress); + String[] command; + if(tlsVersion.equals("1.2")){ + command = handshakeCompleteMessageTls1_2(serverIp); + } + else{ + command = handshakeCompleteMessageTls1_3(serverIp); + } + boolean completed = runCommand(command,false).length()>0; + if(completed){ + System.out.println("Handshake Completed for: " + serverIp + "->" + clientIpAddress); + } + else{ + System.out.println("Handshake not completed for: " + serverIp + "->" + clientIpAddress); + } + return completed; + } + + /** + * Create the wireshark filter needed to find completed TLS 1.2 handshakes + * + * ssl.handshake.type==14 -> ServerHelloDone indicating handshake has completed for TLS 1.2 + * @param serverIp IP address for the server side of the connection + * @return + */ + private String[] handshakeCompleteMessageTls1_2(String serverIp){ + return new String[]{"tshark", + "-r", + captureFile, + "ssl.handshake.type==14", + "and", + "ip.src=="+serverIp, + " and ", + "ip.dst=="+clientIpAddress, + "and", + getPortsFilter() + }; + } + + /** + * Create the wireshark filter needed to find completed TLS 1.3 handshakes + * + * ssl.handshake.type==2 -> ServerHello indicating handshake has completed for TLS 1.3 + * @param serverIp IP address for the server side of the connection + * @return + */ + private String[] handshakeCompleteMessageTls1_3(String serverIp){ + return new String[]{"tshark", + "-r", + captureFile, + "ssl.handshake.type==2", + "and", + "ip.src=="+serverIp, + " and ", + "ip.dst=="+clientIpAddress, + "and", + getPortsFilter() + }; + } + + private boolean isCipherSupported(List cipherList, String cipher ){ + return cipherList.stream().anyMatch(s -> s.contains(cipher)); + } + + private void passClient(boolean handshake,boolean cipherValid,String tlsVersion) { + if (handshake && cipherValid) { + clientReport += + "\nRESULT pass security.tlsv" + + tlsVersion.replace(".","_") + + ".client" + + " Client/Server completed handshake and ECDH/ECDSA supported ciphers."; + } else { + clientReport += + "\nRESULT fail security.tlsv" + + tlsVersion.replace(".","_") + + ".client"; + clientReport+=handshake?"":" No completed SSL/TLS handshake detected."; + clientReport+=cipherValid?"":" Cipher could not be validated."; + } + } + + private void skipClient(String skipMessage,String tlsVersion) { + clientReport += + "\nRESULT skip security.tlsv" + + tlsVersion.replace(".","_") + + ".client " + + skipMessage; + } + + private static String runCommand(String[] command, boolean useRawData){ + ProcessBuilder processBuilder = new ProcessBuilder(); + processBuilder.command(command); + try { + processBuilder.redirectErrorStream(true); + Process process = processBuilder.start(); + + BufferedReader reader = + new BufferedReader(new InputStreamReader(process.getInputStream())); + StringBuffer sb = new StringBuffer(); + String line; + while ((line = reader.readLine()) != null) { + if(useRawData){ + if(sb.length()>0){ + sb.append("\n"); + } + sb.append(line); + } + else{ + sb.append(line.trim()); + } + } + process.waitFor(); + String result = sb.toString(); + return result; + } catch (IOException e) { + e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return ""; + } +} diff --git a/subset/security/tlstest/src/main/java/KeyLengthStatus.java b/subset/security/tlstest/src/main/java/KeyLengthStatus.java new file mode 100644 index 0000000000..fb12087b90 --- /dev/null +++ b/subset/security/tlstest/src/main/java/KeyLengthStatus.java @@ -0,0 +1,5 @@ +public enum KeyLengthStatus { + PUBLIC_KEY_INVALID_LENGTH, + PUBLIC_KEY_RSA_VALID_LENGTH, + PUBLIC_KEY_EC_VALID_LENGTH +} diff --git a/subset/security/tlstest/src/main/java/Main.java b/subset/security/tlstest/src/main/java/Main.java index b88525dc3d..c92523ada9 100644 --- a/subset/security/tlstest/src/main/java/Main.java +++ b/subset/security/tlstest/src/main/java/Main.java @@ -1,22 +1,61 @@ public class Main { public static void main(String[] args) throws Exception { + String tlsReport = ""; + Report report = new Report(); - if (args.length != 1) { - throw new IllegalArgumentException("Expected target ipAddress/hostname as argument"); + if (args.length != 2) { + throw new IllegalArgumentException("Expected 2 args, only " + args.length + " detected."); } - String ipAddress = args[0]; + String caFile = "None".equals(args[1])?null:args[1]; + System.out.println("Args:"); + System.out.println("IP Address: " + ipAddress); + System.out.println("CA File: " + caFile); + //Generate the Client/Server test objects + Server tlsServer1_0 = new Server(ipAddress, 443,"1",caFile); + Server tlsServer1_2 = new Server(ipAddress, 443,"1.2",caFile); + Server tlsServer1_3 = new Server(ipAddress, 443,"1.3",caFile); + Client client = new Client(ipAddress,new int[]{443,8883},new String[]{"1.2","1.3"}); + //Client client_1_3 = new Client(ipAddress,443,"1.3"); + //Run the tests + tlsReport += validateServerTls(tlsServer1_0); + tlsReport += validateServerTls(tlsServer1_2); + tlsReport += validateServerTls(tlsServer1_3); + tlsReport += validateClientTls(client); + //tlsReport += validateClientTls(client_1_3); + //Generate the results + tlsReport += ResultGenerator.generateServerResults(tlsServer1_0); + tlsReport += ResultGenerator.generateServerResults(tlsServer1_2); + tlsReport += ResultGenerator.generateServerResults(tlsServer1_3); + report.writeReport(tlsReport); + } + + public static String validateServerTls(Server tlsTest) { + String report = ""; + try { + report += tlsTest.validate(); + } + catch(Exception e){ + report +="Server TLS failed\n"; + report +=e.getMessage(); + } + finally { + return report; + } + } - Certs tlsTest = new Certs(ipAddress, 443); + public static String validateClientTls(Client client){ + String report = ""; try { - if (tlsTest.testTLSVersions()) { - System.out.println("Certificate read successfully"); - } else { - System.out.println("Certificate read failed"); - } - } catch (Exception e) { - System.err.println("Exception main:" + e.getMessage()); + report += client.validate(); + } + catch(Exception e){ + report +="Client TLS failed\n"; + report +=e.getMessage(); + } + finally { + return report; } } } diff --git a/subset/security/tlstest/src/main/java/Report.java b/subset/security/tlstest/src/main/java/Report.java index 2ed26348bc..71a41d64e0 100644 --- a/subset/security/tlstest/src/main/java/Report.java +++ b/subset/security/tlstest/src/main/java/Report.java @@ -4,17 +4,10 @@ import java.io.IOException; public class Report { - - boolean debug = true; - - String reportFilename = "tmp/report.txt"; + private final String reportFilename = "tmp/report.txt"; public void writeReport(String certificateReport) { try { - if (debug) { - System.out.println(certificateReport); - } - String[] directory = reportFilename.split("/"); File dir = new File(directory[directory.length - 2]); @@ -28,3 +21,4 @@ public void writeReport(String certificateReport) { } } } + diff --git a/subset/security/tlstest/src/main/java/ResultGenerator.java b/subset/security/tlstest/src/main/java/ResultGenerator.java new file mode 100644 index 0000000000..33b8ff706b --- /dev/null +++ b/subset/security/tlstest/src/main/java/ResultGenerator.java @@ -0,0 +1,142 @@ +import java.util.Arrays; + +public class ResultGenerator { + + public static String generateServerResults(Server tlsServer){ + String report = ""; + if(tlsServer.getServerResult() == TestResult.PASS + && tlsServer.getCertificateResult() == TestResult.PASS){ + report = generatePassResults(tlsServer); + } + else if(tlsServer.getServerResult() == TestResult.SKIP + || tlsServer.getCertificateResult() ==TestResult.SKIP){ + report = generateServerSkipResult(tlsServer); + } + else{ + report = generateFailResults(tlsServer); + } + + return report; + } + + private static String generatePassResults(Server server){ + String report = ""; + report += + "\nRESULT pass security.tlsv" + + server.getTlsVersion().replace(".","_") + + ".server " + + getKeyLengthStatusMessage(server.getServerKeyLengthStatus()) + " " + + getCertStatusMessage(server.getServerCertStatus()) + " " + + getSignatureMessage(server.getSigStatus()) + " " + + getCipherStatusMessage(server.getCipherStatus()); + return report; + } + + private static String generateFailResults(Server server){ + String report = ""; + report += + "\nRESULT fail security.tlsv" + + server.getTlsVersion().replace(".","_") + + ".server"; + if(server.getServerKeyLengthStatus() == KeyLengthStatus.PUBLIC_KEY_INVALID_LENGTH){ + report+=" " + getKeyLengthStatusMessage(server.getServerKeyLengthStatus()); + } + if(server.getServerCertStatus() != CertificateStatus.CERTIFICATE_VALID){ + report+=" " + getCertStatusMessage(server.getServerCertStatus()); + } + if(server.getSigStatus() != CertificateSignatureStatus.CERTIFICATE_CA_SIGNED){ + report+=" " + getSignatureMessage(server.getSigStatus()); + } + if(server.getCipherStatus() == CipherStatus.VALID){ + report+=" " + getCipherStatusMessage(server.getCipherStatus()); + } + return report; + } + + private static String generateServerSkipResult(Server server) { + String report = + "\nRESULT skip security.tlsv" + + server.getTlsVersion().replace(".","_") + + ".server" + + " IOException unable to connect to server."; + return report; + } + + public static String getKeyLengthStatusMessage(KeyLengthStatus status){ + String message =""; + switch (status) { + case PUBLIC_KEY_RSA_VALID_LENGTH: + message = "Certificate public key length is >= 2048."; + break; + case PUBLIC_KEY_EC_VALID_LENGTH: + message = "Certificate public key length is >= 224."; + break; + case PUBLIC_KEY_INVALID_LENGTH: + default: + message = "Certificate public key length too short."; + } + return message; + } + + public static String getCipherStatusMessage(CipherStatus status){ + String message =""; + switch (status) { + case VALID: + message = "Cipher Valid."; + break; + case INVALID: + message = "Cipher Invalid."; + break; + case SKIPPED: + default: + message = "Cipher check not required."; + } + return message; + } + + public static String getSignatureMessage(CertificateSignatureStatus status){ + String message =""; + switch (status) { + case CERTIFICATE_CA_SIGNED: + message = "Certificate has been signed by a CA."; + break; + case CERTIFICATE_SELF_SIGNED: + default: + message = "Certificate has not been signed by a CA."; + } + return message; + } + + public static String getCertStatusMessage(CertificateStatus status) { + String message =""; + switch (status) { + case CERTIFICATE_VALID: + message = "Certificate active for current date."; + break; + case CERTIFICATE_NOT_YET_VALID: + message = "Certificate not yet active for current date."; + break; + case CERTIFICATE_EXPIRED: + message = "Certificate is expired."; + break; + case CERTIFICATE_TYPE_UNSUPPORTED: + message = "Certificate type is NOT in supported x509 format."; + break; + case CERTIFICATE_INVALID: + default: + message = "Certificate could not be validated."; + } + return message; + } + + public static String combineTlsVersions(String[] tlsVersions){ + StringBuilder sb = new StringBuilder(); + Arrays.stream(tlsVersions).forEach(tls ->{ + sb.append(sb.length()>0?",":""); + sb.append(tls); + }); + return sb.toString(); + } +} + + diff --git a/subset/security/tlstest/src/main/java/Server.java b/subset/security/tlstest/src/main/java/Server.java new file mode 100644 index 0000000000..8cc340b3e2 --- /dev/null +++ b/subset/security/tlstest/src/main/java/Server.java @@ -0,0 +1,586 @@ +import org.bouncycastle.jce.provider.JDKKeyPairGenerator; +import org.bouncycastle.openssl.PEMWriter; + +import java.io.*; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.cert.*; +import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.ECPublicKey; +import java.security.interfaces.RSAPublicKey; +import javax.crypto.Cipher; +import javax.net.ssl.*; + +public class Server { + private final String ipAddress; + private final int port; + private final String tlsVersion; + private final String caFile; + + private CertificateStatus serverCertStatus = CertificateStatus.CERTIFICATE_INVALID; + private KeyLengthStatus serverKeyLengthStatus = KeyLengthStatus.PUBLIC_KEY_INVALID_LENGTH; + private CertificateSignatureStatus sigStatus = CertificateSignatureStatus.CERTIFICATE_SELF_SIGNED; + private CipherStatus cipherStatus = CipherStatus.INVALID; + + private String certificateReport = ""; + boolean skip = false; + + public Server(String ipAddress, int port,String tlsVersion,String caFile) { + this.ipAddress = ipAddress; + this.port = port; + this.tlsVersion = tlsVersion; + this.caFile = caFile; + } + + public String validate(){ + try { + appendReport("Gathering TLS " + tlsVersion + " Server Information...."); + testTlsVersion(); + } + catch(Exception e){ + System.out.println("Unexpected Error"); + e.printStackTrace(); + } + finally { + appendReport("TLS " + tlsVersion + " Server Information Complete.\n\n"); + return certificateReport; + } + } + + public TestResult getServerResult(){ + if(skip){ + return TestResult.SKIP; + } + else if((serverKeyLengthStatus == KeyLengthStatus.PUBLIC_KEY_RSA_VALID_LENGTH + || serverKeyLengthStatus == KeyLengthStatus.PUBLIC_KEY_EC_VALID_LENGTH) + && (cipherStatus == CipherStatus.VALID || cipherStatus == CipherStatus.SKIPPED)){ + return TestResult.PASS; + } + else{ + return TestResult.FAIL; + } + } + + public TestResult getCertificateResult(){ + if(skip){ + return TestResult.SKIP; + } + else if(serverCertStatus == CertificateStatus.CERTIFICATE_VALID && + sigStatus == CertificateSignatureStatus.CERTIFICATE_CA_SIGNED){ + return TestResult.PASS; + } + else{ + return TestResult.FAIL; + } + } + + public CipherStatus getCipherStatus(){ + return cipherStatus; + } + + public CertificateStatus getServerCertStatus(){ + return serverCertStatus; + } + + public KeyLengthStatus getServerKeyLengthStatus(){ + return serverKeyLengthStatus; + } + + public CertificateSignatureStatus getSigStatus(){ + return sigStatus; + } + + public String getTlsVersion(){ + return tlsVersion; + } + + /**Append the message to the report object and add a new line before + * the message + * + * @param message String message to append + */ + public void appendReport(String message){ + certificateReport += "\n"+message; + } + + private void testTlsVersion() throws Exception { + SSLSocket socket; + try { + // Attempt to open an SSL Socket at the TLS version specified + socket = makeSSLSocket(ipAddress, port, "TLSv" + tlsVersion); + } catch (Exception e) { + appendReport("TLS " + tlsVersion + "Server Implementation Skipping Test, could not open connection"); + System.out.println("TLSv" + tlsVersion + " Failed: " + e.getMessage()); + e.printStackTrace(); + skip = true; + return; + } + + // Validate Server Certificates While using specified TLS version + try { + Certificate[] certificates = getServerCertificates(socket); + serverKeyLengthStatus = validateKeyLength(certificates); + serverCertStatus = validateCertificates(certificates); + sigStatus = validateSignature(certificates); + cipherStatus = validateCipher(certificates); + + } catch (SSLHandshakeException e) { + System.out.println("SSLHandshakeException: Unable to complete handshake:" + e.getMessage()); + e.printStackTrace(); + skip = true; + } catch (Exception e) { + System.out.println("Certificate Validation Failed: " + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * Validate the Cipher while using specified TLS Version. + * + * Skip - TLS 1.3 or RSA Public Key have no cipher requirement + * Pass - If EC Public Key ECDH and ECDSA are supported in cipher + * Fail - If EC Public Key and ECDH and ECDSA are not supported in cipher + * @param certificates Array of all certificates provided with no cipher + * restrictions on the connection + * @return + */ + private CipherStatus validateCipher(Certificate[] certificates ) { + try { + appendReport("\nValidating Cipher..."); + if(tlsVersion.equals("1.3")){ + appendReport("No Cipher check required for TLS 1.3"); + return CipherStatus.SKIPPED; + } + for(int i = 0;i= minKeySize && minKeySize>0) { + if(key instanceof RSAPublicKey){ + keyLengthStatus = KeyLengthStatus.PUBLIC_KEY_RSA_VALID_LENGTH; + } + else if(key instanceof ECPublicKey){ + keyLengthStatus = KeyLengthStatus.PUBLIC_KEY_EC_VALID_LENGTH; + } + } + } + } + return keyLengthStatus; + } + + + private KeyLengthStatus validateKeyLengthRSAorEC(Certificate[] certificates){ + KeyLengthStatus keyLengthStatus = KeyLengthStatus.PUBLIC_KEY_INVALID_LENGTH; + for (Certificate certificate : certificates) { + if (certificate instanceof X509Certificate) { + int minKeySize = -1; + int keyLength = 0; + X509Certificate x509Certificate = (X509Certificate) certificate; + // Check the public key bit length is at least 2048 + PublicKey key = x509Certificate.getPublicKey(); + appendReport("Validating Public Key\n " + key); + if (key instanceof RSAPublicKey) { + minKeySize = 2048; + keyLength = ((RSAPublicKey) key).getModulus().bitLength(); + appendReport("RSA Key Length: " + keyLength); + } + else if(key instanceof ECPublicKey){ + minKeySize = 224; + keyLength = ((ECPublicKey)key).getParams().getOrder().bitLength(); + appendReport("EC Key Length: " + keyLength); + } + else{ + appendReport("Public Key not supported: " + key); + } + if (keyLength >= minKeySize && minKeySize > 0) { + if (key instanceof RSAPublicKey) { + keyLengthStatus = KeyLengthStatus.PUBLIC_KEY_RSA_VALID_LENGTH; + } else if (key instanceof ECPublicKey) { + keyLengthStatus = KeyLengthStatus.PUBLIC_KEY_EC_VALID_LENGTH; + } + } + } + } + return keyLengthStatus; + } + + private CertificateStatus validateCertificates(Certificate[] certificates) { + appendReport("Checking Certificate..."); + for (Certificate certificate : certificates) { + + if (certificate instanceof X509Certificate) { + try { + appendReport("Certificate:\n" + certificate); + // Check the expiration date + X509Certificate x509Certificate = (X509Certificate) certificate; + x509Certificate.checkValidity(); + appendReport("Certificate is active for current date.\n\n"); + return CertificateStatus.CERTIFICATE_VALID; + } catch (CertificateExpiredException cee) { + appendReport("Certificate is expired."); + return CertificateStatus.CERTIFICATE_EXPIRED; + } catch (CertificateNotYetValidException e) { + appendReport("Certificate not yet valid."); + return CertificateStatus.CERTIFICATE_NOT_YET_VALID; + } + } else { + appendReport("Unsupported certificate type."); + return CertificateStatus.CERTIFICATE_TYPE_UNSUPPORTED; + } + } + appendReport("Certificate Checked."); + return CertificateStatus.CERTIFICATE_INVALID; + } + + private String combineCerts(Certificate[] certificates){ + String certChain = ""; + for (Certificate certificate : certificates) { + if (certificate instanceof X509Certificate) { + try { + X509Certificate x509Certificate = (X509Certificate) certificate; + String pem = convertToBase64PEMString(x509Certificate); + certChain+=pem; + } catch (Exception e) { + e.printStackTrace(); + } + } + } + return certChain ; + } + + private CertificateSignatureStatus validateSignature(Certificate[] certificates) { + appendReport("Checking Certificate Signature..."); + System.out.println("CA File: " + caFile); + appendReport("Certificates found: " + certificates.length); + try { + File certFile = writePemFile(certificates, tlsVersion + "_cert.pem"); + File caFile = resolveCAFile(); + System.out.println("CA file resolved"); + if(caFile!=null){ + System.out.println("CA File exists: " + caFile.exists()); + String[] cmd = new String[]{"openssl","verify","-CAfile",caFile.getAbsolutePath(),certFile.getAbsolutePath()}; + String procResp = runCommand(cmd,true).trim(); + appendReport("Certificate Validation\n" + procResp); + System.out.println("CA Validation Response: " + procResp); + if(procResp.equals(certFile.getAbsolutePath()+": OK")){ + System.out.println("Certificate Signature Validated"); + appendReport("Certificate Signature Validated"); + return CertificateSignatureStatus.CERTIFICATE_CA_SIGNED; + } + else{ + System.out.println("Certificate Signature Validation Failed"); + appendReport("Certificate Signature Validation Failed"); + } + } + else{ + System.out.println("CA File not resolved"); + appendReport("CA File not Resolved:"); + } + } + catch(Exception e){ + System.out.println("Certificate Signature Validation Error: " + e.getMessage()); + e.printStackTrace(); + } + appendReport("Certificate Signature Checked."); + return CertificateSignatureStatus.CERTIFICATE_SELF_SIGNED; + } + + /** + * Write a Pem File to the temp directory + * + * @param x509Cert X.509 Certificate to write in PEM encoding + * @param fileName Name of the file to be written to the tmp directory + * @throws Exception + */ + private File writePemFile(Certificate x509Cert,String fileName) throws Exception{ + File tmp = new File("tmp").exists()?new File("tmp"):new File("/root/tmp"); + //File tmp = new File("tmp"); + if(!tmp.exists()){ + tmp.mkdirs(); + } + File f = new File("tmp/"+fileName); + System.out.println("Writing PEM to " + f.getAbsolutePath()); + String pem = convertToBase64PEMString(x509Cert); + FileWriter fw = new FileWriter(f.getAbsolutePath()); + fw.write(pem); + fw.close(); + System.out.println("PEM File Written"); + return f; + } + + /** + * Combine all certificates and write a PEM File to the temp directory + * @param certificates Array of X.509 Certificates to combine and write in PEM encoding + * @param fileName Name of the file to be written to the tmp directory + * @throws Exception + * @return + */ + private File writePemFile(Certificate[] certificates,String fileName) throws Exception{ + //Tmp directory location is different based on context so we'll check where we're at + File tmp= new File("tmp/").exists()?new File("tmp/"):new File("/root/tmp/"); + if(!tmp.exists()){ + tmp.mkdirs(); + } + File f = new File("tmp/"+fileName); + System.out.println("Writing PEM to " + f.getAbsolutePath()); + String pem = combineCerts(certificates); + FileWriter fw = new FileWriter(f.getAbsolutePath()); + fw.write(pem); + fw.close(); + System.out.println("PEM File Written"); + return f; + } + + private File resolveCAFile(){ + System.out.println("Resolving CA File..."); + File caFile = resolveCAFromFile(); + if(caFile!=null){ + if(caFile.exists()){ + return caFile; + } + } + return null; + } + + /** + * Read the CA file from the device folder(/config/device) + * @return + */ + private File resolveCAFromFile(){ + System.out.println("Resolving CA from File: " + caFile); + File f = null; + if(caFile!=null){ + f = new File("/config/device/"+caFile); + } + return f; + } + + /** + * Converts a {@link X509Certificate} instance into a Base-64 encoded string (PEM format). + * + * @param x509Cert A X509 Certificate instance + * @return PEM formatted String + * @throws CertificateEncodingException + */ + public String convertToBase64PEMString(Certificate x509Cert) throws IOException { + StringWriter sw = new StringWriter(); + try (PEMWriter pw = new PEMWriter(sw)) { + pw.writeObject(x509Cert); + } + return sw.toString(); + } + + /** + * Creates a trust manager to accept all certificates. This is required since we need this test to + * be able to connect to any device and can't know anything about the certificates before hand. + * + * @return A valid TrustManager which accepts all valid X509Certificates + */ + private TrustManager[] trustAllManager() { + // Create a trust manager that does not validate certificate chains + return new TrustManager[] { + new X509TrustManager() { + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return null; + } + + public void checkClientTrusted(X509Certificate[] certs, String authType) {} + + public void checkServerTrusted(X509Certificate[] certs, String authType) {} + } + }; + } + + /** + * Attemps to complete the SSL handshake and retrieve the Server Certificates. Server certificates + * in this context refers to the device being tested. + * + * @param socket The SSLSocket which connects to the device for testing + * @throws Exception + */ + private Certificate[] getServerCertificates(SSLSocket socket) throws IOException { + socket.startHandshake(); + return socket.getSession().getPeerCertificates(); + } + + /** + * Attemps to complete the SSL handshake and retrieve the Cipher Used. + * + * @param socket The SSLSocket which connects to the device for testing + * @throws Exception + */ + private String getSessionCipher(SSLSocket socket) throws IOException { + socket.startHandshake(); + return socket.getSession().getCipherSuite(); + } + + /** + * @param host This is the host IP address of the device being tested + * @param port This is teh Port of the SSL connection for the device being tested. + * @param protocol The SSL protocol to be tested. + * @return SSLSocket which supports only the SSL protocol defined. + * @throws Exception + */ + private SSLSocket makeSSLSocket(String host, int port, String protocol) + throws NoSuchAlgorithmException, KeyManagementException, IOException { + SSLSocketFactory factory = makeSSLFactory(trustAllManager(), protocol); + + SSLSocket socket = (SSLSocket) factory.createSocket(host, port); + socket.setEnabledProtocols(new String[] {protocol}); + //socket.setEnabledCipherSuites(getSupportedCiphers()); + return socket; + } + + /** + * Create an SSLSocketFactory with the defined trust manager and protocol + * + * @param trustManager TrustManager to be used in the SSLContext + * @param protocol The SSL protocol to be used in the SSLContext + * @return An initialized SSLSocketFactory with SSLContext defined by input parameters + * @throws Exception + */ + private SSLSocketFactory makeSSLFactory(TrustManager[] trustManager, String protocol) + throws NoSuchAlgorithmException, KeyManagementException { + // Install the all-trusting trust manager + SSLContext sslContext = SSLContext.getInstance(protocol); + sslContext.init(null, trustManager, new java.security.SecureRandom()); + return sslContext.getSocketFactory(); + } + + private static String runCommand(String[] command, boolean useRawData){ + ProcessBuilder processBuilder = new ProcessBuilder(); + processBuilder.command(command); + try { + processBuilder.redirectErrorStream(true); + Process process = processBuilder.start(); + + BufferedReader reader = + new BufferedReader(new InputStreamReader(process.getInputStream())); + StringBuffer sb = new StringBuffer(); + String line; + while ((line = reader.readLine()) != null) { + if(useRawData){ + if(sb.length()>0){ + sb.append("\n"); + } + sb.append(line); + } + else{ + sb.append(line.trim()); + } + } + process.waitFor(); + String result = sb.toString(); + return result; + } catch (IOException e) { + e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return ""; + } + + private static String[] getSupportedCiphers(){ + return + new String[]{ + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", + "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA" + }; + } +} + + diff --git a/subset/security/tlstest/src/main/java/TestResult.java b/subset/security/tlstest/src/main/java/TestResult.java new file mode 100644 index 0000000000..8b6af2d348 --- /dev/null +++ b/subset/security/tlstest/src/main/java/TestResult.java @@ -0,0 +1,6 @@ +public enum TestResult { + PASS, + FAIL, + SKIP +} + diff --git a/testing/test_aux.out b/testing/test_aux.out index e8bb1a3878..2cb3922c50 100644 --- a/testing/test_aux.out +++ b/testing/test_aux.out @@ -21,24 +21,21 @@ RESULT info protocol.bacnet.version Protocol version: 1 RESULT skip protocol.bacnet.pic BACnet device found, but pics.csv not found in device type directory. RESULT info protocol.bacnet.version Protocol version: 1 RESULT pass protocol.bacnet.pic The devices matches the PICS -RESULT skip security.tls.v1 IOException unable to connect to server -RESULT skip security.tls.v1.x509 IOException unable to connect to server -RESULT skip security.tls.v1_2 IOException unable to connect to server -RESULT skip security.tls.v1_2.x509 IOException unable to connect to server -RESULT skip security.tls.v1_3 IOException unable to connect to server -RESULT skip security.tls.v1_3.x509 IOException unable to connect to server -RESULT fail security.tls.v1 Certificate is expired. -RESULT fail security.tls.v1.x509 Certificate is expired. -RESULT fail security.tls.v1_2 Certificate is expired. -RESULT fail security.tls.v1_2.x509 Certificate is expired. -RESULT fail security.tls.v1_3 Certificate could not be validated. -RESULT fail security.tls.v1_3.x509 Certificate could not be validated. -RESULT pass security.tls.v1 Certificate active for current date and public key length > 2048. -RESULT pass security.tls.v1.x509 Certificate active for current date and public key length > 2048. -RESULT pass security.tls.v1_2 Certificate active for current date and public key length > 2048. -RESULT pass security.tls.v1_2.x509 Certificate active for current date and public key length > 2048. -RESULT pass security.tls.v1_3 Certificate active for current date and public key length > 2048. -RESULT pass security.tls.v1_3.x509 Certificate active for current date and public key length > 2048. +RESULT skip security.tlsv1.server IOException unable to connect to server. +RESULT skip security.tlsv1_2.client No client initiated TLS communication detected +RESULT skip security.tlsv1_2.server IOException unable to connect to server. +RESULT skip security.tlsv1_3.client No client initiated TLS communication detected +RESULT skip security.tlsv1_3.server IOException unable to connect to server. +RESULT fail security.tlsv1.server Certificate is expired. Certificate has not been signed by a CA. +RESULT pass security.tlsv1_2.client Client/Server completed handshake and ECDH/ECDSA supported ciphers. +RESULT fail security.tlsv1_2.server Certificate is expired. Certificate has not been signed by a CA. +RESULT pass security.tlsv1_3.client Client/Server completed handshake and ECDH/ECDSA supported ciphers. +RESULT fail security.tlsv1_3.server Certificate is expired. Certificate has not been signed by a CA. +RESULT fail security.tlsv1.server Certificate has not been signed by a CA. Cipher Valid. +RESULT pass security.tlsv1_2.client Client/Server completed handshake and ECDH/ECDSA supported ciphers. +RESULT fail security.tlsv1_2.server Certificate has not been signed by a CA. Cipher Valid. +RESULT pass security.tlsv1_3.client Client/Server completed handshake and ECDH/ECDSA supported ciphers. +RESULT fail security.tlsv1_3.server Certificate has not been signed by a CA. RESULT skip security.passwords.http Port 80 not open on target device. RESULT skip security.passwords.https Port 443 not open on target device. RESULT skip security.passwords.ssh Port 22 not open on target device. @@ -143,6 +140,7 @@ port-01 module_config modules } }, "tls": { + "ca_file": "CA_Faux.pem", "enabled": true }, "typeconf": { @@ -199,6 +197,7 @@ port-02 module_config modules "enabled": true }, "tls": { + "ca_file": "CA_Faux.pem", "enabled": true }, "udmi": { diff --git a/testing/test_modules.out b/testing/test_modules.out index 5f7aae40ce..2d73387cf4 100644 --- a/testing/test_modules.out +++ b/testing/test_modules.out @@ -1,26 +1,23 @@ Running testing/test_modules.sh Base Tests Testing tls alt -RESULT skip security.tls.v1 IOException unable to connect to server -RESULT skip security.tls.v1.x509 IOException unable to connect to server -RESULT skip security.tls.v1_2 IOException unable to connect to server -RESULT skip security.tls.v1_2.x509 IOException unable to connect to server -RESULT skip security.tls.v1_3 IOException unable to connect to server -RESULT skip security.tls.v1_3.x509 IOException unable to connect to server +RESULT skip security.tlsv1.server IOException unable to connect to server. +RESULT skip security.tlsv1_2.client No client initiated TLS communication detected +RESULT skip security.tlsv1_2.server IOException unable to connect to server. +RESULT skip security.tlsv1_3.client No client initiated TLS communication detected +RESULT skip security.tlsv1_3.server IOException unable to connect to server. Testing tls alt tls -RESULT pass security.tls.v1 Certificate active for current date and public key length > 2048. -RESULT pass security.tls.v1.x509 Certificate active for current date and public key length > 2048. -RESULT pass security.tls.v1_2 Certificate active for current date and public key length > 2048. -RESULT pass security.tls.v1_2.x509 Certificate active for current date and public key length > 2048. -RESULT pass security.tls.v1_3 Certificate active for current date and public key length > 2048. -RESULT pass security.tls.v1_3.x509 Certificate active for current date and public key length > 2048. +RESULT pass security.tlsv1.server Certificate public key length is >= 224. Certificate active for current date. Certificate has been signed by a CA. Cipher Valid. +RESULT skip security.tlsv1_2.client No client initiated TLS communication detected +RESULT pass security.tlsv1_2.server Certificate public key length is >= 224. Certificate active for current date. Certificate has been signed by a CA. Cipher Valid. +RESULT skip security.tlsv1_3.client No client initiated TLS communication detected +RESULT pass security.tlsv1_3.server Certificate public key length is >= 224. Certificate active for current date. Certificate has been signed by a CA. Cipher check not required. Testing tls alt expiredtls -RESULT fail security.tls.v1 Certificate is expired. -RESULT fail security.tls.v1.x509 Certificate is expired. -RESULT fail security.tls.v1_2 Certificate is expired. -RESULT fail security.tls.v1_2.x509 Certificate is expired. -RESULT fail security.tls.v1_3 Certificate could not be validated. -RESULT fail security.tls.v1_3.x509 Certificate could not be validated. +RESULT fail security.tlsv1.server Certificate is expired. Certificate has not been signed by a CA. +RESULT skip security.tlsv1_2.client No client initiated TLS communication detected +RESULT fail security.tlsv1_2.server Certificate is expired. Certificate has not been signed by a CA. +RESULT skip security.tlsv1_3.client No client initiated TLS communication detected +RESULT fail security.tlsv1_3.server Certificate is expired. Certificate has not been signed by a CA. Testing ssh RESULT skip security.ssh.version Device is not running an SSH server Testing ssh ssh diff --git a/testing/test_modules.sh b/testing/test_modules.sh index 9d41acbe21..93b7924302 100755 --- a/testing/test_modules.sh +++ b/testing/test_modules.sh @@ -18,7 +18,7 @@ ssh ssh ssh sshv1 EOF -DAQ_TARGETS=aardvark,faux1,faux2 bin/docker_build force inline +DAQ_TARGETS=aardvark,aardvark2,faux1,faux2 bin/docker_build force inline mkdir -p inst/modules/tls/config cp resources/setups/baseline/module_config.json inst/modules/tls/config/module_config.json From 1d5ea87bae878b13016fc3690571c80972492cc0 Mon Sep 17 00:00:00 2001 From: Trevor Date: Mon, 21 Sep 2020 21:14:17 -0700 Subject: [PATCH 144/212] Adding node-forge upgrade (#649) --- firebase/functions/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/firebase/functions/package.json b/firebase/functions/package.json index 5032f5b1ff..939ce751b6 100644 --- a/firebase/functions/package.json +++ b/firebase/functions/package.json @@ -16,6 +16,7 @@ "@google-cloud/iot": "1.8.0", "firebase-admin": "9.2.0", "firebase-functions": "3.11.0", + "node-forge": ">=0.10.0", "extend": "3.0.2" }, "private": true From e376cc7408bc5856551fdc2553f2ea10263ca25b Mon Sep 17 00:00:00 2001 From: henry54809 Date: Tue, 22 Sep 2020 13:31:35 -0700 Subject: [PATCH 145/212] ipaddr DHCP timeout behavior change (#652) --- daq/test_modules/ipaddr_module.py | 12 ++++++++---- testing/test_dhcp.out | 4 +++- testing/test_dhcp.sh | 4 ++++ 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/daq/test_modules/ipaddr_module.py b/daq/test_modules/ipaddr_module.py index 6f2e242f54..53a93a276a 100644 --- a/daq/test_modules/ipaddr_module.py +++ b/daq/test_modules/ipaddr_module.py @@ -23,7 +23,7 @@ class IpAddrModule(HostModule): """Module for inline ipaddr tests""" - _TIMEOUT_EXCEPTION = TimeoutError('DHCP Timeout expired') + _TIMEOUT_EXCEPTION = TimeoutError('DHCP analysis step timeout expired') def __init__(self, host, tmpdir, test_name, module_config): super().__init__(host, tmpdir, test_name, module_config) @@ -130,6 +130,10 @@ def ip_listener(self, target_ip): def heartbeat(self): if self._timeout and datetime.now() >= self._timeout: - self._logger.error('DHCP times out after %ds lease time.' % self._lease_time_seconds) - self.terminate() - self.callback(exception=self._TIMEOUT_EXCEPTION) + if self.docker_host.start_time: + self.terminate() + self.callback(exception=self._TIMEOUT_EXCEPTION) + else: + self._logger.error('DHCP times out after %ds lease time' % self._lease_time_seconds) + self.tests = self.tests[-1:] + self._next_test() diff --git a/testing/test_dhcp.out b/testing/test_dhcp.out index 3bf5881c31..1b57cd6c4f 100644 --- a/testing/test_dhcp.out +++ b/testing/test_dhcp.out @@ -5,7 +5,7 @@ DHCP Tests 9a02571e8f03: [] 9a02571e8f04: [] 9a02571e8f05: [] -9a02571e8f06: ['9a02571e8f06:ipaddr:TimeoutError'] +9a02571e8f06: [] Device 1 ip triggers: 1 0 Device 2 ip triggers: 0 0 Device 3 long ip triggers: 1 @@ -13,4 +13,6 @@ Device 4 ip triggers: 1 Device 4 subnet 1 ip: 1 subnet 2 ip: 1 subnet 3 ip: 2 Device 5 ip triggers: 1 Device 5 num of ips: 2 +DHCP timeouts: 1 +Device 6 DHCP timeouts: 1 Done with tests diff --git a/testing/test_dhcp.sh b/testing/test_dhcp.sh index e561377e57..a60cff4159 100755 --- a/testing/test_dhcp.sh +++ b/testing/test_dhcp.sh @@ -116,4 +116,8 @@ for iface in $(seq 1 5); do fi done +dhcp_timeouts=$(cat inst/cmdrun.log | fgrep 'DHCP times out after 120s lease time' | wc -l) +device_6_dhcp_timeouts=$(cat inst/cmdrun.log | fgrep 'DHCP times out after 120s lease time' | fgrep 'ipaddr_ipaddr06' | wc -l) +echo "DHCP timeouts: $dhcp_timeouts" | tee -a $TEST_RESULTS +echo "Device 6 DHCP timeouts: $device_6_dhcp_timeouts" | tee -a $TEST_RESULTS echo Done with tests | tee -a $TEST_RESULTS From 87ccff315812cff3070ab876a24bce4e3aa9ca9a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 22 Sep 2020 23:36:33 -0700 Subject: [PATCH 146/212] Update dependency node-forge to v0.10.0 [SECURITY] (#650) --- firebase/functions/package-lock.json | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/firebase/functions/package-lock.json b/firebase/functions/package-lock.json index 3a1f4f2679..e662329985 100644 --- a/firebase/functions/package-lock.json +++ b/firebase/functions/package-lock.json @@ -521,6 +521,13 @@ "integrity": "sha512-tbjzndQvSIHGBLzHnhDs3cL4RBjLbLXc2pYvGH+imGVu5b4RMAttUTdnmW2UH0t11QeBTXZ7wlXPS7hrypO/tg==", "requires": { "node-forge": "^0.9.0" + }, + "dependencies": { + "node-forge": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.2.tgz", + "integrity": "sha512-naKSScof4Wn+aoHU6HBsifh92Zeicm1GDQKd1vp3Y/kOi8ub0DozCa9KpvYNCXslFHYRmLNiqRopGdTGwNLpNw==" + } } }, "gtoken": { @@ -1559,6 +1566,13 @@ "integrity": "sha512-S4blHBQWZRnEW44OcR7TL9WR+QCqByRvhNDZ/uuQfpxywfupikf/miba8js1jZi6ZOGv5slgSuoshCWh6EMDzg==", "requires": { "node-forge": "^0.9.0" + }, + "dependencies": { + "node-forge": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.2.tgz", + "integrity": "sha512-naKSScof4Wn+aoHU6HBsifh92Zeicm1GDQKd1vp3Y/kOi8ub0DozCa9KpvYNCXslFHYRmLNiqRopGdTGwNLpNw==" + } } }, "graceful-fs": { @@ -1901,9 +1915,9 @@ "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" }, "node-forge": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.1.tgz", - "integrity": "sha512-G6RlQt5Sb4GMBzXvhfkeFmbqR6MzhtnT7VTHuLadjkii3rdYHNdw0m8zA4BTxVIh68FicCQ2NSUANpsqkr9jvQ==" + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" }, "object-assign": { "version": "4.1.1", From d43ec399f34ec60e0397d9c682459962b866abef Mon Sep 17 00:00:00 2001 From: Trevor Date: Wed, 23 Sep 2020 09:43:20 -0700 Subject: [PATCH 147/212] Basic UDMI provisioner test (#648) --- cmd/run | 4 +++ codecov.yml | 5 ++++ daq/gateway.py | 8 +++++- daq/host.py | 1 + daq/report.py | 2 +- daq/test_modules/external_module.py | 6 ++--- docker/include/bin/start_faux | 13 ++++++++++ .../include/network/scripts/start_networking | 18 ++++++++++++- docker/modules/Dockerfile.networking | 13 +++++++++- docs/device_report.md | 12 ++++++++- subset/cloud/test_udmi | 25 +++++++++++++------ testing/test_aux.gcp | 3 +++ testing/test_aux.sh | 7 +++--- 13 files changed, 99 insertions(+), 18 deletions(-) create mode 100644 codecov.yml diff --git a/cmd/run b/cmd/run index 451fef20f8..1a405bb6e7 100755 --- a/cmd/run +++ b/cmd/run @@ -15,6 +15,10 @@ echo Clearing previous state... sudo rm -rf inst/reports inst/run-port-* $cmdrun_log sudo chown -f $USER -R inst || true +if [ -n "$site_path" -a -f "$site_path/cloud_iot_config.json" ]; then + cp $site_path/cloud_iot_config.json inst/config/ +fi + if [ -n "$build_tests" ]; then release_tag=`git describe --dirty || echo unknown` # If the current commit is a release tag, then pull images. diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000000..58e59b885d --- /dev/null +++ b/codecov.yml @@ -0,0 +1,5 @@ +coverage: + status: + patch: + default: + threshold: .5% diff --git a/daq/gateway.py b/daq/gateway.py index 60b6abe193..081b488ae7 100644 --- a/daq/gateway.py +++ b/daq/gateway.py @@ -62,7 +62,9 @@ def _initialize(self): # Work around an instability in the faucet/clib/docker library, b/152520627. if getattr(cls, 'pullImage'): setattr(cls, 'pullImage', lambda x: True) - host = self.runner.add_host(host_name, port=host_port, cls=cls, tmpdir=self.tmpdir) + vol_maps = [os.path.abspath('inst/config') + ':/config/inst'] + host = self.runner.add_host(host_name, port=host_port, cls=cls, tmpdir=self.tmpdir, + vol_maps=vol_maps) host.activate() self.host = host self._change_lease_time(self.runner.config.get('initial_dhcp_lease_time')) @@ -105,6 +107,10 @@ def activate(self): self.activated = True self._scan_finalize() + def get_base_dir(self): + """Return the gateways base directory for instance files""" + return os.path.abspath(self.tmpdir) + def _change_lease_time(self, lease_time): LOGGER.info('Gateway %s change lease time to %s', self.port_set, lease_time) self.execute_script('change_lease_time', lease_time) diff --git a/daq/host.py b/daq/host.py index b07ecf2f75..e1d078f104 100644 --- a/daq/host.py +++ b/daq/host.py @@ -701,6 +701,7 @@ def _get_module_params(self): 'port_base': self._port_base, 'device_base': self._device_aux_path(), 'type_base': self._type_aux_path(), + 'gw_base': self.gateway.get_base_dir(), 'scan_base': self.scan_base } if ext_loip: diff --git a/daq/report.py b/daq/report.py index d3ee8e5046..60733ba380 100644 --- a/daq/report.py +++ b/daq/report.py @@ -209,7 +209,7 @@ def _write_test_summary(self): self._write_test_tables() def _accumulate_result(self, test_name, result, extra='', module_name=None): - assert test_name not in self._results, 'result already exists' + assert test_name not in self._results, 'result already exists: ' % test_name if result not in self._result_headers: self._result_headers.append(result) diff --git a/daq/test_modules/external_module.py b/daq/test_modules/external_module.py index d7789a41eb..ef0dbf0a28 100644 --- a/daq/test_modules/external_module.py +++ b/daq/test_modules/external_module.py @@ -11,7 +11,7 @@ from .base_module import HostModule -LOGGER = logger.get_logger('external_module') +LOGGER = logger.get_logger('exmodule') class ExternalModule(HostModule): @@ -90,7 +90,7 @@ def opt_param(key): def _get_vol_maps(self, params): vol_maps = [(params['scan_base'], os.path.join(self.basedir, "scans"))] - kinds = ('inst', 'port', 'device', 'type') + kinds = ('inst', 'port', 'device', 'type', 'gw') maps = list(map(lambda kind: self._map_if_exists(params, kind), kinds)) vol_maps.extend(filter(lambda vol_map: vol_map, maps)) return vol_maps @@ -100,7 +100,7 @@ def _map_if_exists(self, params, kind): if base and os.path.exists(base): abs_base = os.path.abspath(base) dst = os.path.join(self.basedir, 'config', kind) - LOGGER.info('%s mapping %s to %s', self, abs_base, dst) + LOGGER.debug('%s mapping %s to %s', self, abs_base, dst) return (abs_base, dst) return None diff --git a/docker/include/bin/start_faux b/docker/include/bin/start_faux index 699405b28f..a5ff2a7179 100755 --- a/docker/include/bin/start_faux +++ b/docker/include/bin/start_faux @@ -226,6 +226,19 @@ elif [ -n "${options[expiredtls]}" ]; then fi if [ -n "${options[pubber]}" ]; then + extraField=`jq .extraField local/pubber.json` + if [ "$extraField" == null ]; then + deviceId=`jq -r .deviceId local/pubber.json` + gateway=`ip route | sed -rn 's/default via (.*) dev.*/\1/p'` + echo Contacting pagent $gateway for new device key for $deviceId + curl http://$gateway:8192?device=$deviceId > pagent.json || echo pagent error + echo pagent reply: + cat pagent.json + jq -r '."rsa_private.pem"' pagent.json > local/rsa_private.pem + openssl pkcs8 -topk8 -inform PEM -outform DER -in local/rsa_private.pem -nocrypt > local/rsa_private.pkcs8 + echo Updated pubber private key from pagent for device $deviceId + ls -l local/rsa_* + fi echo Running cloud pubber tool... (while date; do pubber/bin/run local/pubber.json diff --git a/docker/include/network/scripts/start_networking b/docker/include/network/scripts/start_networking index 331585c2fe..eb7afe827b 100755 --- a/docker/include/network/scripts/start_networking +++ b/docker/include/network/scripts/start_networking @@ -17,7 +17,7 @@ done # Enable a web-server for configuration access. mkdir -p /tmp/public -(cd /tmp/public; python -m SimpleHTTPServer &) +(cd /tmp/public; python3 -m http.server &) # Enable NAT to the outside world, through the docker bridge. echo 1 > /proc/sys/net/ipv4/ip_forward @@ -46,5 +46,21 @@ echo dhcp-host=*,ignore >> /etc/dnsmasq.conf # Start the NTP server service ntp start +# For cloud-based provisioning tests. +GCP_CRED_FILE=/config/inst/gcp_service_account.json +SITE_MODEL=$PWD/test_site + +if [ -f /config/inst/gcp_service_account.json ]; then + echo Activating pagent with $GCP_CRED_FILE + ( + gcloud auth activate-service-account --key-file $GCP_CRED_FILE + gcloud auth list + project_id=`jq -r .project_id $GCP_CRED_FILE` + cd udmi + echo bin/pagent $SITE_MODEL $project_id + bin/pagent $SITE_MODEL $project_id + ) & +fi + echo Blocking for all eternity. ./autorestart_dnsmasq diff --git a/docker/modules/Dockerfile.networking b/docker/modules/Dockerfile.networking index 86ae77238b..f400609a23 100644 --- a/docker/modules/Dockerfile.networking +++ b/docker/modules/Dockerfile.networking @@ -5,11 +5,22 @@ FROM daqf/aardvark:latest -RUN $AG update && $AG install dnsmasq ethtool iptables netcat ntp python curl +RUN $AG update && $AG install apt-transport-https ca-certificates curl gnupg2 +RUN echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" \ + | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list +RUN curl https://packages.cloud.google.com/apt/doc/apt-key.gpg \ + | apt-key --keyring /usr/share/keyrings/cloud.google.gpg add - + +RUN $AG update && $AG install dnsmasq ethtool iptables netcat ntp \ + python3 python3-pip python3-setuptools gnupg google-cloud-sdk COPY docker/include/network/scripts/* ./ RUN mkdir -p /etc COPY docker/include/etc/ntp.conf /etc +RUN pip3 install pyyaml + +COPY resources/test_site/ test_site/ +COPY udmi/ udmi/ # Weird workaround for problem running tcdump in a privlidged container. RUN mv /usr/sbin/tcpdump /usr/bin/tcpdump diff --git a/docs/device_report.md b/docs/device_report.md index 8dec01db66..d69eec5ecd 100644 --- a/docs/device_report.md +++ b/docs/device_report.md @@ -56,7 +56,7 @@ Overall device result FAIL |---|---|---|---|---|---| |Required|1|0|0|0|0| |Recommended|1|0|0|0|1| -|Other|6|2|20|1|2| +|Other|6|2|21|1|2| |Result|Test|Category|Expectation|Notes| |---|---|---|---|---| @@ -64,6 +64,7 @@ Overall device result FAIL |skip|base.switch.ping|Other|Other|No local IP has been set, check system config| |pass|base.target.ping|Connectivity|Required|target reached| |skip|cloud.udmi.pointset|Other|Other|No device id| +|skip|cloud.udmi.provision|Other|Other|No device id| |skip|cloud.udmi.state|Other|Other|No device id| |skip|cloud.udmi.system|Other|Other|No device id| |info|communication.type.broadcast|Other|Other|Broadcast packets received. Unicast packets received.| @@ -478,6 +479,15 @@ RESULT skip security.passwords.telnet Port 23 not open on target device. #### Report ``` +-------------------- +cloud.udmi.provision +-------------------- +Validates device provision payload. +-------------------- +No device id +-------------------- +RESULT skip cloud.udmi.provision No device id + -------------------- cloud.udmi.state -------------------- diff --git a/subset/cloud/test_udmi b/subset/cloud/test_udmi index 0f016e18e6..882a1ec637 100755 --- a/subset/cloud/test_udmi +++ b/subset/cloud/test_udmi @@ -21,14 +21,9 @@ message_types="state pointset system" device_id=`jq -r .device_id /config/device/module_config.json` -# Do basic network connectivity check +# Enable dns for GCP lookup echo "nameserver 8.8.8.8" >> /etc/resolv.conf -cat /etc/resolv.conf -ping -c 2 google.com || true # blocked on github actions -echo "********GOOGLE PAGE********" -curl google.com -echo "***************************" if [ "$device_id" == null ]; then skip="No device id" elif [ ! -f $gcp_cred ]; then @@ -39,7 +34,7 @@ fi if [ -n "$skip" ]; then echo Skipping udmi test because $skip - for message_type in $message_types; do + for message_type in provision $message_types; do TEST_NAME="cloud.udmi.$message_type" TEST_DESCRIPTION="Validates device $message_type payload." RESULT_AND_SUMMARY="RESULT skip $TEST_NAME $skip" @@ -63,6 +58,22 @@ echo Configured topic is $gcp_topic echo Target device is $device_id echo +ACTIVATE_LOG=/config/gw/nodes/gw*/activate.log +more $ACTIVATE_LOG | cat +if fgrep "Processing provisioning request for device $device_id" $ACTIVATE_LOG; then + result=pass + detail="Found provisioning request" +else + result=fail + detail="No provisioning request" +fi +TEST_NAME="cloud.udmi.provision" +TEST_DESCRIPTION="Validates dynamic provisioning request" +RESULT_AND_SUMMARY="RESULT $result $TEST_NAME $detail" +write_out_result $REPORT "$TEST_NAME" "$TEST_DESCRIPTION" \ + "$skip" "$RESULT_AND_SUMMARY" + + timeout 90 validator/bin/validate $project_id $schema_path pubsub $subscription local/ || true function message_report { diff --git a/testing/test_aux.gcp b/testing/test_aux.gcp index e2f0dceb7d..686d16d127 100644 --- a/testing/test_aux.gcp +++ b/testing/test_aux.gcp @@ -14,12 +14,15 @@ inst/test_site/devices/AHU-1/metadata_norm.json: "hash": "175e704a" inst/test_site/devices/AHU-22/metadata_norm.json: "hash": "bf0ba5fa" inst/test_site/devices/GAT-123/metadata_norm.json: "hash": "cbcf045e" inst/test_site/devices/SNS-4/metadata_norm.json: "hash": "879557b4" +RESULT fail cloud.udmi.provision No provisioning request RESULT pass cloud.udmi.state Payload successfully validated RESULT fail cloud.udmi.pointset "Unrecognized field \"extraField\" (class com.google.daq.mqtt.registrar.UdmiSchema$PointsetMessage), not marked as ignorable (3 known properties: \"version\", \"points\", \"timestamp\"])\n at [Source: UNKNOWN; line: -1, column: -1] (through reference chain: com.google.daq.mqtt.registrar.UdmiSchema$PointsetMessage[\"extraField\"])" RESULT pass cloud.udmi.system Payload successfully validated +RESULT pass cloud.udmi.provision Found provisioning request RESULT pass cloud.udmi.state Payload successfully validated RESULT pass cloud.udmi.pointset Payload successfully validated RESULT pass cloud.udmi.system Payload successfully validated +RESULT skip cloud.udmi.provision No device id RESULT skip cloud.udmi.state No device id RESULT skip cloud.udmi.pointset No device id RESULT skip cloud.udmi.system No device id diff --git a/testing/test_aux.sh b/testing/test_aux.sh index d00e8267aa..ed6f03dc6f 100755 --- a/testing/test_aux.sh +++ b/testing/test_aux.sh @@ -9,10 +9,10 @@ echo Aux Tests >> $TEST_RESULTS function make_pubber { device=$1 faux=$2 - fail=$3 + extra=$3 gateway=$4 local_dir=inst/faux/$faux/local/ - echo Creating $device with $fail/$gateway in $local_dir + echo Creating $device with $extra/$gateway in $local_dir mkdir -p $local_dir if [ "$gateway" == null ]; then cp resources/test_site/devices/$device/rsa_private.pkcs8 $local_dir @@ -25,7 +25,7 @@ function make_pubber { "projectId": "$project_id", "cloudRegion": $cloud_region, "registryId": $registry_id, - "extraField": $fail, + "extraField": $extra, "keyFile": "local/rsa_private.pkcs8", "gatewayId": $gateway, "deviceId": "$device" @@ -111,6 +111,7 @@ for mac in 9a02571e8f01 3c5ab41e8f0b 3c5ab41e8f0a; do fgrep -h RESULT inst/run-$mac/nodes/ping*/activate.log \ | sed -e 's/\s*\(%%.*\)*$//' | tee -a $TEST_RESULTS done + # Add the RESULT lines from all aux test report files. capture_test_results bacext capture_test_results macoui From a02abded74a99a5dd6aa592aa741f74a77ad18de Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 23 Sep 2020 11:48:15 -0700 Subject: [PATCH 148/212] Pin dependency node-forge to 0.10.0 (#653) --- firebase/functions/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firebase/functions/package.json b/firebase/functions/package.json index 939ce751b6..9cc0a5d7e6 100644 --- a/firebase/functions/package.json +++ b/firebase/functions/package.json @@ -16,7 +16,7 @@ "@google-cloud/iot": "1.8.0", "firebase-admin": "9.2.0", "firebase-functions": "3.11.0", - "node-forge": ">=0.10.0", + "node-forge": "0.10.0", "extend": "3.0.2" }, "private": true From 3cb5ce7c71c14b867d6fa270764705ee4a278d9c Mon Sep 17 00:00:00 2001 From: henry54809 Date: Thu, 24 Sep 2020 22:46:38 -0700 Subject: [PATCH 149/212] Cisco switch more expected table output (#657) --- .../java/daq/usi/BaseSwitchController.java | 17 ++++- .../daq/usi/BaseSwitchControllerTest.java | 69 ++++++++++++++++++- 2 files changed, 80 insertions(+), 6 deletions(-) diff --git a/usi/src/main/java/daq/usi/BaseSwitchController.java b/usi/src/main/java/daq/usi/BaseSwitchController.java index dc2f736d37..64aebae806 100644 --- a/usi/src/main/java/daq/usi/BaseSwitchController.java +++ b/usi/src/main/java/daq/usi/BaseSwitchController.java @@ -76,6 +76,11 @@ protected static HashMap mapSimpleTable( } else { // Tabular data is not always reported in perfectly alignment, we need to calculate the // correct values based off of the sections in between white spaces + int nextHeaderStart = header.indexOf(colNames[i + 1]); + if (Character.isWhitespace(values.charAt(lastSectionEnd)) + && lastSectionEnd < nextHeaderStart) { + lastSectionEnd++; + } int firstWhiteSpace = getFirstWhiteSpace(values.substring(lastSectionEnd)) + lastSectionEnd; // Wrong table header line @@ -86,12 +91,18 @@ protected static HashMap mapSimpleTable( int lastWhiteSpace = getIndexOfNonWhitespaceAfterWhitespace(values.substring(firstWhiteSpace)) + firstWhiteSpace; - int nextHeaderStart = header.indexOf(colNames[i + 1]); - if (nextHeaderStart >= firstWhiteSpace) { + // Account for empty values in a table. + if (nextHeaderStart >= firstWhiteSpace && nextHeaderStart <= lastWhiteSpace) { secEnd = nextHeaderStart; } else { - secEnd = Math.max(lastWhiteSpace, nextHeaderStart); + char beforeHead = values.charAt(nextHeaderStart - 1); + if (Character.isWhitespace(beforeHead)) { + secEnd = Math.max(lastWhiteSpace, nextHeaderStart); + } else { + secEnd = lastWhiteSpace; + } } + } lastSectionEnd = secEnd; // \u00A0 is non-breaking space which trim ignores. diff --git a/usi/src/test/java/daq/usi/BaseSwitchControllerTest.java b/usi/src/test/java/daq/usi/BaseSwitchControllerTest.java index 7fea888b3b..ab5e5f4c18 100644 --- a/usi/src/test/java/daq/usi/BaseSwitchControllerTest.java +++ b/usi/src/test/java/daq/usi/BaseSwitchControllerTest.java @@ -32,7 +32,7 @@ void mapSimpleTableEmptyInput() { @Test void mapSimpleTableSampleInputAT() { String raw = "Interface Admin Pri Oper Power Device Class Max \n" - + "port1.0.1 Enabled Low Powered 3337 n/a 0 15400 [C]"; + + "port1.0.1 Enabled Low Powered 3337 n/a 0 15400 [C]"; String[] colNames = {"Interface", "Admin", "Pri", "Oper", "Power", "Device", "Class", "Max"}; String[] mapNames = {"interface", "admin", "pri", "oper", "power", "device", "class", "max"}; Map expected = Map.of("interface", "port1.0.1", "admin", "Enabled", "pri", @@ -47,7 +47,7 @@ void mapSimpleTableSampleInputAT() { @Test void mapSimpleTableSampleInputCisco9300() { String raw = "Port         Name               Status       Vlan       Duplex  Speed Type\n" - + "Gi1/0/1                         connected    routed     a-full  a-100 10/100/1000BaseTX"; + + "Gi1/0/1                         connected    routed     a-full  a-100 10/100/1000BaseTX"; String[] colNames = {"Port", "Name", "Status", "Vlan", "Duplex", "Speed", "Type"}; String[] mapNames = {"interface", "name", "status", "vlan", "duplex", "speed", "type"}; Map expected = Map.of("interface", "Gi1/0/1", "name", "", "status", @@ -59,10 +59,73 @@ void mapSimpleTableSampleInputCisco9300() { } } + @Test + void mapSimpleTableSampleInput2Cisco9300() { + String raw = "Port Name Status Vlan Duplex Speed Type\n" + + "Gi1/0/5 connected trunk a-full a-1000 10/100/1000BaseTX"; + String[] colNames = {"Port", "Name", "Status", "Vlan", "Duplex", "Speed", "Type"}; + String[] mapNames = {"interface", "name", "status", "vlan", "duplex", "speed", "type"}; + Map expected = Map.of("interface", "Gi1/0/5", "name", "", "status", + "connected", "vlan", "trunk", "duplex", "a-full", "speed", "a-1000", + "type", "10/100/1000BaseTX"); + Map response = BaseSwitchController.mapSimpleTable(raw, colNames, mapNames); + for (String key : response.keySet()) { + assertEquals(expected.get(key), response.get(key)); + } + } + + @Test + void mapSimpleTableTestStartOffsetInputCisco9300() { + String raw = "Port Name Status Vlan Duplex Speed Type\n" + + "Gi1/0/5 connected trunk a-full a-1000 10/100/1000BaseTX"; + String[] colNames = {"Port", "Name", "Status", "Vlan", "Duplex", "Speed", "Type"}; + String[] mapNames = {"interface", "name", "status", "vlan", "duplex", "speed", "type"}; + Map expected = Map.of("interface", "Gi1/0/5", "name", "", "status", + "connected", "vlan", "trunk", "duplex", "a-full", "speed", "a-1000", + "type", "10/100/1000BaseTX"); + Map response = BaseSwitchController.mapSimpleTable(raw, colNames, mapNames); + System.out.println(response); + for (String key : response.keySet()) { + assertEquals(expected.get(key), response.get(key)); + } + } + + @Test + void mapSimpleTableTestStartOffsetInput2Cisco9300() { + String raw = "Port Name Status Vlan Duplex Speed Type\n" + + "Gi1/0/5 connected trunk a-full a-1000 10/100/1000BaseTX"; + String[] colNames = {"Port", "Name", "Status", "Vlan", "Duplex", "Speed", "Type"}; + String[] mapNames = {"interface", "name", "status", "vlan", "duplex", "speed", "type"}; + Map expected = Map.of("interface", "Gi1/0/5", "name", "", "status", + "connected", "vlan", "trunk", "duplex", "a-full", "speed", "a-1000", + "type", "10/100/1000BaseTX"); + Map response = BaseSwitchController.mapSimpleTable(raw, colNames, mapNames); + System.out.println(response); + for (String key : response.keySet()) { + assertEquals(expected.get(key), response.get(key)); + } + } + + @Test + void mapSimpleTableTestStartOffsetInput3Cisco9300() { + String raw = "Port Name Status Vlan Duplex Speed Type\n" + + "Gi1/0/5 connected trunk a-full a-1000 10/100/1000BaseTX"; + String[] colNames = {"Port", "Name", "Status", "Vlan", "Duplex", "Speed", "Type"}; + String[] mapNames = {"interface", "name", "status", "vlan", "duplex", "speed", "type"}; + Map expected = Map.of("interface", "Gi1/0/5", "name", "", "status", + "connected", "vlan", "trunk", "duplex", "a-full", "speed", "a-1000", + "type", "10/100/1000BaseTX"); + Map response = BaseSwitchController.mapSimpleTable(raw, colNames, mapNames); + System.out.println(response); + for (String key : response.keySet()) { + assertEquals(expected.get(key), response.get(key)); + } + } + @Test void mapSimpleTableMissingValues() { String raw = "Port         Name               Status       Vlan       Duplex  Speed Type\n" - + "Gi1/0/1                             routed     a-full  a-100 10/100/1000BaseTX"; + + "Gi1/0/1                             routed     a-full  a-100 10/100/1000BaseTX"; String[] colNames = {"Port", "Name", "Status", "Vlan", "Duplex", "Speed", "Type"}; String[] mapNames = {"interface", "name", "status", "vlan", "duplex", "speed", "type"}; Map expected = Map.of("interface", "Gi1/0/1", "name", "", "status", From 37aafa36a4bf92c1204faff4fb44903c8f64328a Mon Sep 17 00:00:00 2001 From: frgitdaq <62390501+frgitdaq@users.noreply.github.com> Date: Wed, 30 Sep 2020 16:58:49 +0100 Subject: [PATCH 150/212] DHCP Short (9) (#579) addition of DHCP short disconnection test --- docker/include/bin/start_faux | 14 +++-- .../network/NTPClient/src/main/java/Main.java | 29 ++++------ resources/setups/baseline/module_config.json | 6 +- subset/ipaddr/Dockerfile.test_ipaddr | 3 + subset/ipaddr/README.md | 14 +++++ subset/ipaddr/dhcp_tests.py | 56 +++++++++++++------ subset/network/ntp_tests.py | 7 +-- testing/test_aux.out | 20 +++++++ testing/test_preamble.sh | 2 +- 9 files changed, 103 insertions(+), 48 deletions(-) create mode 100644 subset/ipaddr/README.md diff --git a/docker/include/bin/start_faux b/docker/include/bin/start_faux index a5ff2a7179..9af5cd1eaa 100755 --- a/docker/include/bin/start_faux +++ b/docker/include/bin/start_faux @@ -161,12 +161,18 @@ fi if [ -n "${options[ntpv4]}" ]; then dhcp_ntp=$(fgrep NTPSERVERS= /run/ntpdate.dhcp) ntp_server=`echo $dhcp_ntp | cut -d "'" -f 2` - echo Transmitting NTP query to $ntp_server using NTPv4 - java -jar NTPClient/build/libs/NTPClient-1.0-SNAPSHOT.jar $ntp_server 123 4 2 > ntp.log & + (while true; do + echo Transmitting NTP query to $ntp_server using NTPv4 + java -jar NTPClient/build/libs/NTPClient-1.0-SNAPSHOT.jar $ntp_server 123 4 > ntp.log + sleep 8 + done) & elif [ -n "${options[ntpv3]}" ]; then STATIC_NTP_SERVER=216.239.35.8 - echo Transmitting NTP query to $STATIC_NTP_SERVER using NTPv3 - java -jar NTPClient/build/libs/NTPClient-1.0-SNAPSHOT.jar $STATIC_NTP_SERVER 123 3 2 > ntp.log & + (while true; do + echo Transmitting NTP query to $STATIC_NTP_SERVER using NTPv3 + timeout 5 java -jar NTPClient/build/libs/NTPClient-1.0-SNAPSHOT.jar $STATIC_NTP_SERVER 123 3 > ntp.log + sleep 8 + done) & fi # ntp_pass queries the NTP server learnt from DHCP. ntp_fail sends to time.google.com diff --git a/docker/include/network/NTPClient/src/main/java/Main.java b/docker/include/network/NTPClient/src/main/java/Main.java index 0bfe635d31..bd30683961 100644 --- a/docker/include/network/NTPClient/src/main/java/Main.java +++ b/docker/include/network/NTPClient/src/main/java/Main.java @@ -5,6 +5,7 @@ import java.text.DecimalFormat; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; public class Main { @@ -14,33 +15,26 @@ public class Main { static byte version = 3; static int port = 123; static int timerPeriod = 10; - static byte leapIndicator = 3; + static byte leapIndicator = 0; /** * Constructs and sends NTP packets to target NTP server. */ public static void main(String[] args) { - if (args.length < 2) { - throw new IllegalArgumentException("Usage: server_name port version timerPeriod"); + if (args.length < 3) { + throw new IllegalArgumentException("Usage: server_name port version"); } serverName = args[0]; port = Integer.parseInt(args[1]); version = Byte.parseByte(args[2]); - timerPeriod = Integer.parseInt(args[3]); - Runnable senderRunnable = new Runnable() { - @Override - public void run() { - try { - sendRequest(); - } catch (IOException e) { - System.out.println(e.getMessage()); - } - } - }; - ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); - executor.scheduleAtFixedRate(senderRunnable, 0, timerPeriod, TimeUnit.SECONDS); + try { + sendRequest(); + } catch (IOException e) { + System.out.println(e.getMessage()); + } + } private static void sendRequest() throws IOException { @@ -85,8 +79,5 @@ private static void sendPacket(DatagramSocket socket, DatagramPacket packet, byt + (msg.transmitTimestamp - destinationTimestamp)) / 2; System.out.println("Local clock offset: " + new DecimalFormat("0.00").format(localClockOffset * 1000) + " ms"); - if (localClockOffset * 1000 < 128) { - leapIndicator = 0; - } } } diff --git a/resources/setups/baseline/module_config.json b/resources/setups/baseline/module_config.json index 9c40ffca15..646be8a36f 100644 --- a/resources/setups/baseline/module_config.json +++ b/resources/setups/baseline/module_config.json @@ -4,7 +4,11 @@ "enabled": false, "timeout_sec": 0, "port_flap_timeout_sec": 20, - "dhcp_ranges": [{"start": "192.168.0.1", "end": "192.168.255.254", "prefix_length": 16}] + "dhcp_ranges": [ + {"start": "192.168.0.1", "end": "192.168.255.254", "prefix_length": 16}, + {"start": "172.16.0.1", "end": "172.31.255.254", "prefix_length": 12}, + {"start": "10.0.0.1", "end": "10.255.255.254", "prefix_length": 8} + ] }, "pass": { "enabled": true diff --git a/subset/ipaddr/Dockerfile.test_ipaddr b/subset/ipaddr/Dockerfile.test_ipaddr index 8c0efd6620..5ba36af862 100644 --- a/subset/ipaddr/Dockerfile.test_ipaddr +++ b/subset/ipaddr/Dockerfile.test_ipaddr @@ -2,6 +2,9 @@ FROM daqf/aardvark:latest RUN $AG update && $AG install python python-setuptools python-pip netcat +RUN pip install --upgrade pip +RUN pip install scapy + COPY subset/ipaddr/dhcp_tests.py . COPY subset/ipaddr/test_dhcp . diff --git a/subset/ipaddr/README.md b/subset/ipaddr/README.md new file mode 100644 index 0000000000..a3dee54b7f --- /dev/null +++ b/subset/ipaddr/README.md @@ -0,0 +1,14 @@ +# DHCP Tests + +## General + +The ipaddr module is triggered by native ipaddr test. +This is because the functional code included in ipaddr communicates with the openflow supported switch via the universal switch interface. This module analyzes the output of the ipaddr in the tmp/activate.log file for DHCP activity. + +## Tests + +### connection.network.dhcp_short +- Reconnect device and check for DHCP request. +#### Result Cases: +- PASS: A DHCP request has been received by the device after the port has been disconnected and connected. +- FAIL: No DHCP request was received (this will also be the case if the target is using a static IP). diff --git a/subset/ipaddr/dhcp_tests.py b/subset/ipaddr/dhcp_tests.py index 50102f9824..444c72119f 100644 --- a/subset/ipaddr/dhcp_tests.py +++ b/subset/ipaddr/dhcp_tests.py @@ -1,10 +1,10 @@ -"""Dummy ipaddr accompanying docker module""" - from __future__ import absolute_import import sys +from scapy.all import DHCP TEST_REQUEST = str(sys.argv[1]) - +DHCP_REQUEST = 3 +DHCP_ACKNOWLEDGE = 5 def main(): """main""" @@ -13,32 +13,52 @@ def main(): dash_break_line = '--------------------\n' description_dhcp_short = 'Reconnect device and check for DHCP request.' description_dhcp_long = 'Wait for lease expiry and check for DHCP request.' + running_port_toggle = 'Running dhcp port_toggle test' + ip_notification = 'ip notification' result = None + summary = None def _write_report(string_to_append): with open(report_filename, 'a+') as file_open: file_open.write(string_to_append) - def _test_dhcp_short(): - return 'fail' + def _get_dhcp_type(capture, dhcp_type, after=None): + for packet in capture: + if DHCP not in packet: + continue + if packet[DHCP].options[0][1] == dhcp_type: + if after is None: + return packet + if packet.time > after: + return packet + return None - def _test_dhcp_long(): - return 'fail' + def _get_dhcp_option(packet, option): + for opt in packet[DHCP].options: + if opt[0] == option: + return opt[1] + return None + + def _test_dhcp_short(): + fd = open(ipaddr_log, 'r') + run_dhcp_short = False + for line in fd: + if run_dhcp_short: + if ip_notification in line: + fd.close() + return 'pass', 'DHCP request received.' + if running_port_toggle in line: + run_dhcp_short = True + fd.close() + return 'fail', 'No DHCP request received.' _write_report("{b}{t}\n{b}".format(b=dash_break_line, t=TEST_REQUEST)) - summary = "" - with open(ipaddr_log, 'r') as fd: - summary = fd.read() - if TEST_REQUEST == 'connection.network.dhcp_short': - _write_report("{d}\n{b} \n {s}".format(b=dash_break_line, d=description_dhcp_short, - s=summary)) - result = _test_dhcp_short() - elif TEST_REQUEST == 'connection.network.dhcp_long': - _write_report("{d}\n{b}".format(b=dash_break_line, d=description_dhcp_long)) - result = _test_dhcp_long() + if TEST_REQUEST == 'connection.network.dhcp_short': + result, summary = _test_dhcp_short() + _write_report("{d}\n{b}".format(b=dash_break_line, d=description_dhcp_short)) - _write_report("RESULT {r} {t} \n".format(r=result, t=TEST_REQUEST)) + _write_report("RESULT {r} {t} {s}\n".format(r=result, t=TEST_REQUEST, s=summary)) if __name__ == "__main__": diff --git a/subset/network/ntp_tests.py b/subset/network/ntp_tests.py index 6d0eb6b13b..f001734ff0 100644 --- a/subset/network/ntp_tests.py +++ b/subset/network/ntp_tests.py @@ -81,11 +81,8 @@ def test_ntp_support(): def test_ntp_update(): - startup_capture = rdpcap(startup_pcap_file) - packets = ntp_packets(startup_capture) - if os.path.isfile(monitor_pcap_file): - monitor_capture = rdpcap(monitor_pcap_file) - packets += ntp_packets(monitor_capture) + capture = rdpcap(monitor_pcap_file) + packets = ntp_packets(capture) if len(packets) < 2: add_summary("Not enough NTP packets received.") return 'skip' diff --git a/testing/test_aux.out b/testing/test_aux.out index 2cb3922c50..c3a19e54d2 100644 --- a/testing/test_aux.out +++ b/testing/test_aux.out @@ -107,6 +107,16 @@ port-01 module_config modules "end": "192.168.255.254", "prefix_length": 16, "start": "192.168.0.1" + }, + { + "end": "172.31.255.254", + "prefix_length": 12, + "start": "172.16.0.1" + }, + { + "end": "10.255.255.254", + "prefix_length": 8, + "start": "10.0.0.1" } ], "enabled": false, @@ -167,6 +177,16 @@ port-02 module_config modules "end": "192.168.255.254", "prefix_length": 16, "start": "192.168.0.1" + }, + { + "end": "172.31.255.254", + "prefix_length": 12, + "start": "172.16.0.1" + }, + { + "end": "10.255.255.254", + "prefix_length": 8, + "start": "10.0.0.1" } ], "enabled": false, diff --git a/testing/test_preamble.sh b/testing/test_preamble.sh index 904a9ead0c..3edd54ba5f 100644 --- a/testing/test_preamble.sh +++ b/testing/test_preamble.sh @@ -67,7 +67,7 @@ function redact { -e 's/Not shown: .* ports//' \ -e 's/[ \t]*$//' \ -e 's/\t/ /g' \ - -e 's/([0-9]{1,3}\.){3}[0-9]{1,3}/X.X.X.X/' \ + -e 's/([0-9]{1,3}\.){3}[0-9]{1,3}/X.X.X.X/g' \ -e 's/-oG .*\/tmp/-oG XXX\/tmp/' \ -e 's/# Nmap [0-9]{1,4}\.[0-9]{1,4}/\# Nmap XXX/' From 34ab30309b16502594911c78977e360607e3ed13 Mon Sep 17 00:00:00 2001 From: frgitdaq <62390501+frgitdaq@users.noreply.github.com> Date: Wed, 30 Sep 2020 18:08:32 +0100 Subject: [PATCH 151/212] Private Address (6) (#584) Addition of the connection.dhcp.private_address test --- .../qualification/system_module_config.json | 10 ++++ .../remediation/system_module_config.json | 10 ++++ subset/ipaddr/dhcp_tests.py | 46 ++++++++++++++++++- subset/ipaddr/test_dhcp | 1 + 4 files changed, 65 insertions(+), 2 deletions(-) diff --git a/resources/setups/qualification/system_module_config.json b/resources/setups/qualification/system_module_config.json index 1cc6fd9835..5a5ddd90fb 100644 --- a/resources/setups/qualification/system_module_config.json +++ b/resources/setups/qualification/system_module_config.json @@ -75,6 +75,16 @@ "required": "pass", "expected": "Required Pass" }, + "connection.dhcp.private_address": { + "category": "Connection", + "required": "pass", + "expected": "Required Pass" + }, + "connection.network.dhcp_short": { + "category": "Connection", + "required": "pass", + "expected": "Required Pass" + }, "connection.network.dhcp_long": { "category": "Connection", "required": "pass", diff --git a/resources/setups/remediation/system_module_config.json b/resources/setups/remediation/system_module_config.json index e7542de45d..3e215677ac 100644 --- a/resources/setups/remediation/system_module_config.json +++ b/resources/setups/remediation/system_module_config.json @@ -71,6 +71,16 @@ "required": "pass", "expected": "Required Pass" }, + "connection.dhcp.private_address": { + "category": "Connection", + "required": "pass", + "expected": "Required Pass" + }, + "connection.network.dhcp_short": { + "category": "Connection", + "required": "pass", + "expected": "Required Pass" + }, "connection.network.dhcp_long": { "category": "Connection", "required": "pass", diff --git a/subset/ipaddr/dhcp_tests.py b/subset/ipaddr/dhcp_tests.py index 444c72119f..4d357690f1 100644 --- a/subset/ipaddr/dhcp_tests.py +++ b/subset/ipaddr/dhcp_tests.py @@ -1,6 +1,7 @@ from __future__ import absolute_import import sys -from scapy.all import DHCP +import json +from scapy.all import rdpcap, DHCP TEST_REQUEST = str(sys.argv[1]) DHCP_REQUEST = 3 @@ -8,16 +9,23 @@ def main(): """main""" + scan_file = '/scans/test_ipaddr.pcap' ipaddr_log = '/tmp/activate.log' + module_config_file = '/config/device/module_config.json' + dhcp_ranges = [] report_filename = 'report.txt' dash_break_line = '--------------------\n' description_dhcp_short = 'Reconnect device and check for DHCP request.' - description_dhcp_long = 'Wait for lease expiry and check for DHCP request.' + description_private_address = 'Device supports all private address ranges.' running_port_toggle = 'Running dhcp port_toggle test' ip_notification = 'ip notification' result = None summary = None + with open(module_config_file) as json_file: + json_data = json.load(json_file) + dhcp_ranges = json_data['modules']['ipaddr']['dhcp_ranges'] + def _write_report(string_to_append): with open(report_filename, 'a+') as file_open: file_open.write(string_to_append) @@ -39,6 +47,25 @@ def _get_dhcp_option(packet, option): return opt[1] return None + def _to_ipv4(ip): + return tuple(int(n) for n in ip.split('.')) + + def _in_range(ip, start, end): + return _to_ipv4(start) < _to_ipv4(ip) < _to_ipv4(end) + + def _supports_range(capture, start, end): + found_request = False + for packet in capture: + if DHCP not in packet: + continue + if not packet[DHCP].options[0][1] == DHCP_REQUEST: + continue + if _get_dhcp_option(packet, 'requested_addr') is None: + continue + if _in_range(_get_dhcp_option(packet, 'requested_addr'), start, end): + found_request = True + return found_request + def _test_dhcp_short(): fd = open(ipaddr_log, 'r') run_dhcp_short = False @@ -52,11 +79,26 @@ def _test_dhcp_short(): fd.close() return 'fail', 'No DHCP request received.' + def _test_private_address(): + if len(dhcp_ranges) == 0: + return 'skip', 'No private address ranges were specified.' + capture = rdpcap(scan_file) + passing = True + for dhcp_range in dhcp_ranges: + if not _supports_range(capture, dhcp_range['start'], dhcp_range['end']): + passing = False + if passing: + return 'pass', 'All private address ranges are supported.' + return 'fail', 'Not all private address ranges are supported.' + _write_report("{b}{t}\n{b}".format(b=dash_break_line, t=TEST_REQUEST)) if TEST_REQUEST == 'connection.network.dhcp_short': result, summary = _test_dhcp_short() _write_report("{d}\n{b}".format(b=dash_break_line, d=description_dhcp_short)) + elif TEST_REQUEST == 'connection.dhcp.private_address': + result, summary = _test_private_address() + _write_report("{d}\n{b}".format(b=dash_break_line, d=description_private_address)) _write_report("RESULT {r} {t} {s}\n".format(r=result, t=TEST_REQUEST, s=summary)) diff --git a/subset/ipaddr/test_dhcp b/subset/ipaddr/test_dhcp index 2f16fbb3bd..c8a975f879 100755 --- a/subset/ipaddr/test_dhcp +++ b/subset/ipaddr/test_dhcp @@ -3,5 +3,6 @@ source reporting.sh REPORT=/tmp/report.txt python dhcp_tests.py connection.network.dhcp_short +python dhcp_tests.py connection.dhcp.private_address cat report.txt >> $REPORT From b1a4ff00f65e6013f6e4f4c49b5932d45524b3aa Mon Sep 17 00:00:00 2001 From: jhughesbiot <50999916+jhughesbiot@users.noreply.github.com> Date: Wed, 30 Sep 2020 10:11:53 -0700 Subject: [PATCH 152/212] Tls timeout fix (#651) * move timeout into constant --- subset/security/tlstest/src/main/java/Server.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/subset/security/tlstest/src/main/java/Server.java b/subset/security/tlstest/src/main/java/Server.java index 8cc340b3e2..9825aaf5ab 100644 --- a/subset/security/tlstest/src/main/java/Server.java +++ b/subset/security/tlstest/src/main/java/Server.java @@ -2,6 +2,7 @@ import org.bouncycastle.openssl.PEMWriter; import java.io.*; +import java.net.InetSocketAddress; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; @@ -17,6 +18,7 @@ public class Server { private final int port; private final String tlsVersion; private final String caFile; + private static final int CONNECT_TIMEOUT_MS = 10000; private CertificateStatus serverCertStatus = CertificateStatus.CERTIFICATE_INVALID; private KeyLengthStatus serverKeyLengthStatus = KeyLengthStatus.PUBLIC_KEY_INVALID_LENGTH; @@ -508,10 +510,9 @@ private String getSessionCipher(SSLSocket socket) throws IOException { private SSLSocket makeSSLSocket(String host, int port, String protocol) throws NoSuchAlgorithmException, KeyManagementException, IOException { SSLSocketFactory factory = makeSSLFactory(trustAllManager(), protocol); - - SSLSocket socket = (SSLSocket) factory.createSocket(host, port); + SSLSocket socket = (SSLSocket)factory.createSocket(); + socket.connect(new InetSocketAddress(host, port), CONNECT_TIMEOUT_MS); socket.setEnabledProtocols(new String[] {protocol}); - //socket.setEnabledCipherSuites(getSupportedCiphers()); return socket; } From 38d173361698453c0f778a848440a5cb056be3e9 Mon Sep 17 00:00:00 2001 From: Noureddine Date: Thu, 1 Oct 2020 13:40:26 +0100 Subject: [PATCH 153/212] Add manual tests to resource config (#621) * add manual tests to reference configuration for qualification --- .../manual_tests_module_config.json | 44 +++++++++++++++++ .../qualification/system_module_config.json | 48 +++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 resources/setups/qualification/manual_tests_module_config.json diff --git a/resources/setups/qualification/manual_tests_module_config.json b/resources/setups/qualification/manual_tests_module_config.json new file mode 100644 index 0000000000..57c682a89b --- /dev/null +++ b/resources/setups/qualification/manual_tests_module_config.json @@ -0,0 +1,44 @@ +{ + "tests": { + "security.manual.java_interface": { + "outcome": "", + "summary": "", + "test_log": "" + }, + "security.manual.flash_interface": { + "outcome": "", + "summary": "", + "test_log": "" + }, + "security.manual.flash_functionality": { + "outcome": "", + "summary": "", + "test_log": "" + }, + "security.manual.http": { + "outcome": "", + "summary": "", + "test_log": "" + }, + "security.manual.web_passwords": { + "outcome": "", + "summary": "", + "test_log": "" + }, + "connection.manual.comms_down": { + "outcome": "", + "summary": "", + "test_log": "" + }, + "connection.manual.sec_eth_port": { + "outcome": "", + "summary": "", + "test_log": "" + }, + "connection.manual.sec_eth_port_no_ip": { + "outcome": "", + "summary": "", + "test_log": "" + } + } +} diff --git a/resources/setups/qualification/system_module_config.json b/resources/setups/qualification/system_module_config.json index 5a5ddd90fb..c06d3ab4f3 100644 --- a/resources/setups/qualification/system_module_config.json +++ b/resources/setups/qualification/system_module_config.json @@ -184,6 +184,54 @@ "category": "Security", "required": "info", "expected": "Information" + }, + "security.manual.java_interface": { + "category": "Security", + "required": "pass", + "expected": "Required Pass", + "type": "manual" + }, + "security.manual.flash_interface": { + "category": "Security", + "required": "pass", + "expected": "Required Pass", + "type": "manual" + }, + "security.manual.flash_functionality": { + "category": "Security", + "required": "pass", + "expected": "Required Pass", + "type": "manual" + }, + "security.manual.http": { + "category": "Security", + "required": "pass", + "expected": "Required Pass", + "type": "manual" + }, + "security.manual.web_passwords": { + "category": "Security", + "required": "pass", + "expected": "Required Pass", + "type": "manual" + }, + "connection.manual.comms_down": { + "category": "Connection", + "required": "pass", + "expected": "Recommended Pass", + "type": "manual" + }, + "connection.manual.sec_eth_port": { + "category": "Connection", + "required": "pass", + "expected": "Recommended Pass", + "type": "manual" + }, + "connection.manual.sec_eth_port_no_ip": { + "category": "Connection", + "required": "pass", + "expected": "Recommended Pass", + "type": "manual" } } } From c9285cee0f5305a3ef67511713bd828f513e273f Mon Sep 17 00:00:00 2001 From: henry54809 Date: Fri, 2 Oct 2020 19:49:15 -0700 Subject: [PATCH 154/212] gateway refactoring (#662) --- daq/{gateway.py => base_gateway.py} | 126 ++++-------- daq/container_gateway.py | 105 ++++++++++ daq/dhcp_monitor.py | 16 +- daq/external_gateway.py | 12 ++ daq/host.py | 19 +- daq/runner.py | 19 +- daq/test_modules/ipaddr_module.py | 3 +- daq/topology.py | 6 +- firebase/public/protos.hash | 2 +- firebase/public/protos.html | 45 +++++ libs/proto/system_config_pb2.py | 43 +++- libs/proto/usi_pb2.py | 296 +++++++++++++++++++++------- proto/system_config.proto | 8 + testing/test_dhcp.sh | 2 +- 14 files changed, 515 insertions(+), 187 deletions(-) rename daq/{gateway.py => base_gateway.py} (58%) create mode 100644 daq/container_gateway.py create mode 100644 daq/external_gateway.py diff --git a/daq/gateway.py b/daq/base_gateway.py similarity index 58% rename from daq/gateway.py rename to daq/base_gateway.py index 081b488ae7..ed0e998074 100644 --- a/daq/gateway.py +++ b/daq/base_gateway.py @@ -3,17 +3,14 @@ import datetime import os import shutil +from abc import ABC, abstractmethod -from clib import docker_host -from clib import tcpdump_helper - -import dhcp_monitor import logger LOGGER = logger.get_logger('gateway') -class Gateway(): +class BaseGateway(ABC): """Gateway collection class for managing testing services""" GATEWAY_OFFSET = 0 @@ -25,13 +22,11 @@ class Gateway(): TEST_IP_FORMAT = '192.168.84.%d' - def __init__(self, runner, name, port_set, network): + def __init__(self, runner, name, port_set): self.name = name self.runner = runner assert port_set > 0, 'port_set %d, must be > 0' % port_set self.port_set = port_set - self.network = network - self.dhcp_monitor = None self.fake_target = None self.host = None self.host_intf = None @@ -42,33 +37,32 @@ def __init__(self, runner, name, port_set, network): self.ready = set() self.activated = False self.result_linger = False - self._scan_monitor = None + self.dhcp_monitor = None def initialize(self): """Initialize the gateway host""" try: self._initialize() except Exception as e: - LOGGER.error('Gateway initialization failed, terminating: %s', str(e)) + LOGGER.error( + 'Gateway initialization failed, terminating: %s', str(e)) self.terminate() raise def _initialize(self): host_name = 'gw%02d' % self.port_set host_port = self._switch_port(self.GATEWAY_OFFSET) - LOGGER.info('Initializing gateway %s as %s/%d', self.name, host_name, host_port) + LOGGER.info('Initializing gateway %s as %s/%d', + self.name, host_name, host_port) self.tmpdir = self._setup_tmpdir(host_name) - cls = docker_host.make_docker_host('daqf/networking', prefix='daq', network='bridge') - # Work around an instability in the faucet/clib/docker library, b/152520627. - if getattr(cls, 'pullImage'): - setattr(cls, 'pullImage', lambda x: True) + cls = self._get_host_class() vol_maps = [os.path.abspath('inst/config') + ':/config/inst'] - host = self.runner.add_host(host_name, port=host_port, cls=cls, tmpdir=self.tmpdir, - vol_maps=vol_maps) + host = self.runner.add_host( + host_name, port=host_port, cls=cls, tmpdir=self.tmpdir, vol_maps=vol_maps) host.activate() self.host = host - self._change_lease_time(self.runner.config.get('initial_dhcp_lease_time')) - LOGGER.info("Added networking host %s on port %d at %s", host_name, host_port, host.IP()) + LOGGER.info("Added networking host %s on port %d at %s", + host_name, host_port, host.IP()) dummy_name = 'dummy%02d' % self.port_set dummy_port = self._switch_port(self.DUMMY_OFFSET) @@ -76,74 +70,39 @@ def _initialize(self): # Dummy does not use DHCP, so need to set default route manually. dummy.cmd('route add -net 0.0.0.0 gw %s' % host.IP()) self.dummy = dummy - LOGGER.info("Added dummy target %s on port %d at %s", dummy_name, dummy_port, dummy.IP()) + LOGGER.info("Added dummy target %s on port %d at %s", + dummy_name, dummy_port, dummy.IP()) self.fake_target = self.TEST_IP_FORMAT % self.port_set self.host_intf = self.runner.get_host_interface(host) - LOGGER.debug('Adding fake target at %s to %s', self.fake_target, self.host_intf) + LOGGER.debug('Adding fake target at %s to %s', + self.fake_target, self.host_intf) host.cmd('ip addr add %s dev %s' % (self.fake_target, self.host_intf)) - - self._startup_scan(host) - log_file = os.path.join(self.tmpdir, 'dhcp_monitor.txt') - self.dhcp_monitor = dhcp_monitor.DhcpMonitor(self.runner, host, - self._dhcp_callback, log_file) - self.dhcp_monitor.start() - ping_retry = self._PING_RETRY_COUNT - while not self._ping_test(host, dummy): + while not self._ping_test(self.host, self.dummy): ping_retry -= 1 LOGGER.info('Gateway %s warmup failed at %s with %d', host_name, datetime.datetime.now(), ping_retry) assert ping_retry, 'warmup ping failure' - assert self._ping_test(host, dummy), 'dummy ping failed' + assert self._ping_test(self.host, dummy), 'dummy ping failed' assert self._ping_test(dummy, host), 'host ping failed' assert self._ping_test(dummy, self.fake_target), 'fake ping failed' - assert self._ping_test(host, dummy, src_addr=self.fake_target), 'reverse ping failed' + assert self._ping_test( + self.host, dummy, src_addr=self.fake_target), 'reverse ping failed' + + @abstractmethod + def _get_host_class(self): + pass def activate(self): """Mark this gateway as activated once all hosts are present""" - self._change_lease_time(self.runner.config.get("dhcp_lease_time")) self.activated = True - self._scan_finalize() def get_base_dir(self): """Return the gateways base directory for instance files""" return os.path.abspath(self.tmpdir) - def _change_lease_time(self, lease_time): - LOGGER.info('Gateway %s change lease time to %s', self.port_set, lease_time) - self.execute_script('change_lease_time', lease_time) - - def _scan_finalize(self, forget=True): - if self._scan_monitor: - active = self._scan_monitor.stream() and not self._scan_monitor.stream().closed - assert active == forget, 'forget and active mismatch' - if forget: - self.runner.monitor_forget(self._scan_monitor.stream()) - self._scan_monitor.terminate() - self._scan_monitor = None - - def execute_script(self, action, *args): - """Generic function for executing scripts on gateway""" - self.host.cmd(('./%s' + len(args) * ' %s') % (action, *args)) - - def request_new_ip(self, mac): - """Requests a new ip for the device""" - self.execute_script('new_ip', mac) - - def change_dhcp_response_time(self, mac, time): - """Change dhcp response time for device mac""" - self.execute_script('change_dhcp_response_time', mac, time) - - def stop_dhcp_response(self, mac): - """Stops DHCP response for the device""" - self.change_dhcp_response_time(mac, -1) - - def change_dhcp_range(self, start, end, prefix_length): - """Change dhcp range for devices""" - self.execute_script('change_dhcp_range', start, end, prefix_length) - def allocate_test_port(self): """Get the test port to use for this gateway setup""" test_port = self._switch_port(self.TEST_OFFSET_START) @@ -154,28 +113,6 @@ def allocate_test_port(self): self.test_ports.add(test_port) return test_port - def _startup_scan(self, host): - assert not self._scan_monitor, 'startup_scan already active' - startup_file = '/tmp/gateway.pcap' - LOGGER.info('Gateway %s startup capture %s in container\'s %s', self.port_set, - self.host_intf, startup_file) - tcp_filter = '' - helper = tcpdump_helper.TcpdumpHelper(host, tcp_filter, packets=None, - intf_name=self.host_intf, timeout=None, - pcap_out=startup_file, blocking=False) - self._scan_monitor = helper - self.runner.monitor_stream('start%d' % self.port_set, helper.stream(), - helper.next_line, hangup=self._scan_complete, - error=self._scan_error) - - def _scan_complete(self): - LOGGER.info('Gateway %d scan complete', self.port_set) - self._scan_finalize(forget=False) - - def _scan_error(self, e): - LOGGER.error('Gateway %d monitor error: %s', self.port_set, e) - self._scan_finalize() - def release_test_port(self, test_port): """Release the given port from the gateway""" assert test_port in self.test_ports, 'test port not allocated' @@ -190,7 +127,8 @@ def _is_target_expected(self, target): target_mac = target['mac'] if target_mac in self.targets: return True - LOGGER.warning('No target match found for %s in %s', target_mac, self.name) + LOGGER.warning('No target match found for %s in %s', + target_mac, self.name) return False def _dhcp_callback(self, state, target, exception=None): @@ -209,7 +147,8 @@ def _setup_tmpdir(self, base_name): def attach_target(self, device): """Attach the given target to this gateway; return number of attached targets.""" assert device.mac not in self.targets, 'target %s already attached to gw' % device - LOGGER.info('Attaching target %s to gateway group %s', device, self.name) + LOGGER.info('Attaching target %s to gateway group %s', + device, self.name) self.targets[device.mac] = device return len(self.targets) @@ -224,7 +163,8 @@ def detach_target(self, device): def target_ready(self, device): """Mark a target ready, and return set of ready targets""" if device not in self.ready: - LOGGER.info('Ready target %s from gateway group %s', device, self.name) + LOGGER.info('Ready target %s from gateway group %s', + device, self.name) self.ready.add(device) return self.ready @@ -234,11 +174,11 @@ def get_targets(self): def terminate(self): """Terminate this instance""" - assert not self.targets, 'gw %s has targets %s' % (self.name, self.targets) + assert not self.targets, 'gw %s has targets %s' % ( + self.name, self.targets) LOGGER.info('Terminating gateway %d/%s', self.port_set, self.name) if self.dhcp_monitor: self.dhcp_monitor.cleanup() - self._scan_finalize() if self.host: try: self.host.terminate() diff --git a/daq/container_gateway.py b/daq/container_gateway.py new file mode 100644 index 0000000000..9e3e374408 --- /dev/null +++ b/daq/container_gateway.py @@ -0,0 +1,105 @@ +"""Gateway module for device testing""" + +import os + +from clib import docker_host +from clib import tcpdump_helper + +import dhcp_monitor +import logger +from base_gateway import BaseGateway + +LOGGER = logger.get_logger('gateway') + + +class ContainerGateway(BaseGateway): + """Gateway collection class for managing testing services""" + + def __init__(self, *args): + super().__init__(*args) + self._scan_monitor = None + self.dhcp_monitor = None + + def _initialize(self): + super()._initialize() + self._change_lease_time( + self.runner.config.get('initial_dhcp_lease_time')) + self._startup_scan(self.host) + log_file = os.path.join(self.tmpdir, 'dhcp_monitor.txt') + self.dhcp_monitor = dhcp_monitor.DhcpMonitor(self.runner, self.host, + self._dhcp_callback, log_file=log_file) + self.dhcp_monitor.start() + + def _get_host_class(self): + cls = docker_host.make_docker_host( + 'daqf/networking', prefix='daq', network='bridge') + # Work around an instability in the faucet/clib/docker library, b/152520627. + if getattr(cls, 'pullImage'): + setattr(cls, 'pullImage', lambda x: True) + return cls + + def activate(self): + """Mark this gateway as activated once all hosts are present""" + super().activate() + self._change_lease_time(self.runner.config.get("dhcp_lease_time")) + self._scan_finalize() + + def _change_lease_time(self, lease_time): + LOGGER.info('Gateway %s change lease time to %s', self.port_set, lease_time) + self.execute_script('change_lease_time', lease_time) + + def _scan_finalize(self, forget=True): + if self._scan_monitor: + active = self._scan_monitor.stream() and not self._scan_monitor.stream().closed + assert active == forget, 'forget and active mismatch' + if forget: + self.runner.monitor_forget(self._scan_monitor.stream()) + self._scan_monitor.terminate() + self._scan_monitor = None + + def execute_script(self, action, *args): + """Generic function for executing scripts on gateway""" + self.host.cmd(('./%s' + len(args) * ' %s') % (action, *args)) + + def request_new_ip(self, mac): + """Requests a new ip for the device""" + self.execute_script('new_ip', mac) + + def change_dhcp_response_time(self, mac, time): + """Change dhcp response time for device mac""" + self.execute_script('change_dhcp_response_time', mac, time) + + def stop_dhcp_response(self, mac): + """Stops DHCP response for the device""" + self.change_dhcp_response_time(mac, -1) + + def change_dhcp_range(self, start, end, prefix_length): + """Change dhcp range for devices""" + self.execute_script('change_dhcp_range', start, end, prefix_length) + + def _startup_scan(self, host): + assert not self._scan_monitor, 'startup_scan already active' + startup_file = '/tmp/gateway.pcap' + LOGGER.info('Gateway %s startup capture %s in container\'s %s', self.port_set, + self.host_intf, startup_file) + tcp_filter = '' + helper = tcpdump_helper.TcpdumpHelper(host, tcp_filter, packets=None, + intf_name=self.host_intf, timeout=None, + pcap_out=startup_file, blocking=False) + self._scan_monitor = helper + self.runner.monitor_stream('start%d' % self.port_set, helper.stream(), + helper.next_line, hangup=self._scan_complete, + error=self._scan_error) + + def _scan_complete(self): + LOGGER.info('Gateway %d scan complete', self.port_set) + self._scan_finalize(forget=False) + + def _scan_error(self, e): + LOGGER.error('Gateway %d monitor error: %s', self.port_set, e) + self._scan_finalize() + + def terminate(self): + """Terminate this instance""" + super().terminate() + self._scan_finalize() diff --git a/daq/dhcp_monitor.py b/daq/dhcp_monitor.py index 4c312cb89b..8896ce91e2 100644 --- a/daq/dhcp_monitor.py +++ b/daq/dhcp_monitor.py @@ -9,7 +9,8 @@ LOGGER = logger.get_logger('dhcp') -class DhcpMonitor(): + +class DhcpMonitor: """Class to handle DHCP monitoring""" DHCP_IP_PATTERN = 'Your-IP ([0-9.]+)' @@ -18,15 +19,17 @@ class DhcpMonitor(): DHCP_PATTERN = '(%s)|(%s)|(%s)' % (DHCP_IP_PATTERN, DHCP_TYPE_PATTERN, DHCP_MAC_PATTERN) DHCP_THRESHHOLD_SEC = 80 - def __init__(self, runner, host, callback, log_file=None): + # pylint: disable=too-many-arguments + def __init__(self, runner, host, callback, log_file=None, intf_name=None): self.runner = runner self.callback = callback self.host = host + self.intf_name = intf_name if intf_name else host.intf().name self.name = host.name self.log_file = log_file self.dhcp_traffic = None - self.intf_name = None self.scan_start = None + self.device_dhcps = {} self.target_ip = None self.target_mac = None self.dhcp_log = None @@ -41,7 +44,8 @@ def start(self): # Because there's buffering somewhere, can't reliably filter out DHCP with "src port 67" tcp_filter = "" helper = tcpdump_helper.TcpdumpHelper(self.host, tcp_filter, packets=None, - timeout=None, blocking=False) + timeout=None, blocking=False, + intf_name=self.intf_name) self.dhcp_traffic = helper self.runner.monitor_stream(self.name, self.dhcp_traffic.stream(), self._dhcp_line, hangup=self._dhcp_hangup, @@ -77,7 +81,7 @@ def cleanup(self): def _dhcp_success(self): assert self.target_ip, 'dhcp ACK missing ip address' assert self.target_mac, 'dhcp ACK missing mac address' - delta = int(time.time()) - self.scan_start + delta = int(time.time()) - self.device_dhcps.get(self.target_mac, self.scan_start) LOGGER.debug('DHCP monitor %s received reply after %ds: %s/%s', self.name, delta, self.target_ip, self.target_mac) mode = MODE.LONG if delta > self.DHCP_THRESHHOLD_SEC else MODE.DONE @@ -86,7 +90,7 @@ def _dhcp_success(self): 'mac': self.target_mac, 'delta': delta } - self.scan_start = int(time.time()) + self.device_dhcps[self.target_mac] = int(time.time()) self.callback(mode, target) self.target_ip = None self.target_mac = None diff --git a/daq/external_gateway.py b/daq/external_gateway.py new file mode 100644 index 0000000000..2cc35f00df --- /dev/null +++ b/daq/external_gateway.py @@ -0,0 +1,12 @@ +"""Gateway module for device testing""" +from __future__ import absolute_import + +import logger +from container_gateway import ContainerGateway + +LOGGER = logger.get_logger('external_gateway') + + +class ExternalGateway(ContainerGateway): + """Gateway collection class for managing testing services""" + # TODO diff --git a/daq/host.py b/daq/host.py index e1d078f104..74ba2ae9b5 100644 --- a/daq/host.py +++ b/daq/host.py @@ -12,13 +12,13 @@ from report import ResultType, ReportGenerator from proto import usi_pb2 as usi from proto import usi_pb2_grpc as usi_service +from proto.system_config_pb2 import DHCPMode import configurator from test_modules import DockerModule, IpAddrModule, NativeModule import gcp import logger - class _STATE: """Host state enum for testing cycle""" ERROR = 'Error condition' @@ -206,7 +206,8 @@ def _get_static_ip(self): return self._loaded_config.get('static_ip') def _get_dhcp_mode(self): - return self._loaded_config['modules'].get('ipaddr', {}).get('dhcp_mode', 'normal') + mode_str = self._loaded_config['modules'].get('ipaddr', {}).get('dhcp_mode', "NORMAL") + return DHCPMode.Value(mode_str) def _get_unique_upload_path(self, file_name): base = os.path.basename(file_name) @@ -356,6 +357,7 @@ def _prepare(self): static_ip = self._get_static_ip() if static_ip: self.logger.info('Target device %s using static ip', self) + self.device.dhcp_mode = DHCPMode.STATIC_IP time.sleep(self._STARTUP_MIN_TIME_SEC) self.runner.ip_notify(MODE.NOPE, { 'mac': self.target_mac, @@ -363,13 +365,16 @@ def _prepare(self): 'delta': -1 }, self.gateway) else: - dhcp_mode = self._get_dhcp_mode() + if not self.device.dhcp_mode: + dhcp_mode = self._get_dhcp_mode() + self.device.dhcp_mode = dhcp_mode # enables dhcp response for this device wait_time = self.runner.config.get("long_dhcp_response_sec") \ - if dhcp_mode == 'long_response' else 0 + if self.device.dhcp_mode == DHCPMode.LONG_RESPONSE else 0 self.logger.info('Target device %s using %s DHCP mode, wait %s', - self, dhcp_mode, wait_time) - self.gateway.change_dhcp_response_time(self.target_mac, wait_time) + self, DHCPMode.Name(self.device.dhcp_mode), wait_time) + if self.device.dhcp_mode != DHCPMode.EXTERNAL: + self.gateway.change_dhcp_response_time(self.target_mac, wait_time) _ = [listener(self.device) for listener in self._dhcp_listeners] def _aux_module_timeout_handler(self): @@ -460,7 +465,7 @@ def trigger_ready(self): delta_t = datetime.now() - self._startup_time if delta_t < timedelta(seconds=self._STARTUP_MIN_TIME_SEC): return False - if self._get_dhcp_mode() == "ip_change": + if self._get_dhcp_mode() == DHCPMode.IP_CHANGE: return len(set(map(lambda ip: ip["ip"], self._all_ips))) > 1 return True diff --git a/daq/runner.py b/daq/runner.py index 993d66afb6..f6339fa27e 100644 --- a/daq/runner.py +++ b/daq/runner.py @@ -13,17 +13,19 @@ import configurator import faucet_event_client -import gateway as gateway_manager +import container_gateway + +import external_gateway import gcp import host as connected_host import network import stream_monitor from wrappers import DaqException import logger +from proto.system_config_pb2 import DHCPMode LOGGER = logger.get_logger('runner') - class PortInfo: """Simple container for device port info""" active = False @@ -47,6 +49,7 @@ def __init__(self): self.group = None self.port = None self.dhcp_ready = False + self.dhcp_mode = None self.ip_info = IpInfo() self.set_id = None @@ -339,6 +342,7 @@ def _handle_device_learn(self, vid, target_mac): device = self._devices.new_device(target_mac) else: device = self._devices.get(target_mac) + device.dhcp_mode = DHCPMode.EXTERNAL self._target_set_trigger(device) def _queue_callback(self, callback): @@ -480,7 +484,8 @@ def _target_set_trigger(self, device): # Stops all DHCP response initially # Selectively enables dhcp response at ipaddr stage based on dhcp mode - gateway.stop_dhcp_response(device.mac) + if device.dhcp_mode != DHCPMode.EXTERNAL: + gateway.stop_dhcp_response(device.mac) gateway.attach_target(device) device.gateway = gateway try: @@ -572,7 +577,13 @@ def _activate_device_group(self, device): set_num = self._find_gateway_set(device) LOGGER.info('Gateway for device group %s not found, initializing base %d...', device.group, set_num) - gateway = gateway_manager.Gateway(self, group_name, set_num, self.network) + if device.dhcp_mode == DHCPMode.EXTERNAL: + # TODO to be removed. + device.dhcp_mode = None + gateway = external_gateway.ExternalGateway(self, group_name, set_num) + else: + gateway = container_gateway.ContainerGateway(self, group_name, set_num) + try: gateway.initialize() except Exception: diff --git a/daq/test_modules/ipaddr_module.py b/daq/test_modules/ipaddr_module.py index 53a93a276a..7889f3c8d5 100644 --- a/daq/test_modules/ipaddr_module.py +++ b/daq/test_modules/ipaddr_module.py @@ -9,8 +9,8 @@ import copy import logger from .docker_module import DockerModule - from .base_module import HostModule +from proto.system_config_pb2 import DHCPMode _LOG_FORMAT = "%(asctime)s %(levelname)-7s %(message)s" LEASE_TIME_UNITS_CONVERTER = { @@ -51,6 +51,7 @@ def __init__(self, host, tmpdir, test_name, module_config): def start(self, port, params, callback, finish_hook): """Start the ip-addr tests""" super().start(port, params, callback, finish_hook) + assert self.host.device.dhcp_mode != DHCPMode.EXTERNAL, "device DHCP is not enabled." self._logger.debug('Target device %s starting ipaddr test %s', self.device, self.test_name) self._next_test() diff --git a/daq/topology.py b/daq/topology.py index 2cda43ebe4..0e0e725940 100644 --- a/daq/topology.py +++ b/daq/topology.py @@ -5,7 +5,7 @@ import time import yaml -from gateway import Gateway +from base_gateway import BaseGateway import logger @@ -271,8 +271,8 @@ def _generate_acls(self): self._generate_port_acls() def _get_gw_ports(self, port_set): - base_port = Gateway.SET_SPACING * port_set - end_port = base_port + Gateway.NUM_SET_PORTS + base_port = BaseGateway.SET_SPACING * port_set + end_port = base_port + BaseGateway.NUM_SET_PORTS return list(range(base_port, end_port)) def _get_bcast_ports(self, port_set): diff --git a/firebase/public/protos.hash b/firebase/public/protos.hash index b3f399d5be..370f8918da 100644 --- a/firebase/public/protos.hash +++ b/firebase/public/protos.hash @@ -1 +1 @@ -12f895d37a4ea85e15100a3edfcad250bdb001bd proto/system_config.proto +de57653a297ec1c4104f481d770103578cfee2ff proto/system_config.proto diff --git a/firebase/public/protos.html b/firebase/public/protos.html index 9b254ac69c..0a4ef91b4b 100644 --- a/firebase/public/protos.html +++ b/firebase/public/protos.html @@ -203,6 +203,10 @@

      Table of Contents

      +
    • + EDHCPMode +
    • +
    • ERunTriggerType
    • @@ -755,6 +759,47 @@

      USISetup

      +

      DHCPMode

      +

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      NameNumberDescription
      NORMAL0

      STATIC_IP1

      EXTERNAL2

      LONG_RESPONSE3

      IP_CHANGE4

      +

      RunTriggerType

      diff --git a/libs/proto/system_config_pb2.py b/libs/proto/system_config_pb2.py index c8e7206997..a42dad982a 100644 --- a/libs/proto/system_config_pb2.py +++ b/libs/proto/system_config_pb2.py @@ -20,7 +20,7 @@ package='', syntax='proto3', serialized_options=None, - serialized_pb=_b('\n\x1d\x64\x61q/proto/system_config.proto\"\xf1\x08\n\tDaqConfig\x12\x18\n\x10site_description\x18\x01 \x01(\t\x12\x18\n\x10monitor_scan_sec\x18\x02 \x01(\x05\x12\x1b\n\x13\x64\x65\x66\x61ult_timeout_sec\x18\x03 \x01(\x05\x12\x12\n\nsettle_sec\x18& \x01(\x05\x12\x11\n\tbase_conf\x18\x04 \x01(\t\x12\x11\n\tsite_path\x18\x05 \x01(\t\x12\x1f\n\x17initial_dhcp_lease_time\x18\x06 \x01(\t\x12\x17\n\x0f\x64hcp_lease_time\x18\x07 \x01(\t\x12\x19\n\x11\x64hcp_response_sec\x18\' \x01(\x05\x12\x1e\n\x16long_dhcp_response_sec\x18\x08 \x01(\x05\x12\"\n\x0cswitch_setup\x18\t \x01(\x0b\x32\x0c.SwitchSetup\x12\x12\n\nhost_tests\x18\x10 \x01(\t\x12\x13\n\x0b\x62uild_tests\x18$ \x01(\x08\x12\x11\n\trun_limit\x18\x11 \x01(\x05\x12\x11\n\tfail_mode\x18\x12 \x01(\x08\x12\x13\n\x0bsingle_shot\x18\" \x01(\x08\x12\x15\n\rresult_linger\x18\x13 \x01(\x08\x12\x0f\n\x07no_test\x18\x14 \x01(\x08\x12\x11\n\tkeep_hold\x18( \x01(\x08\x12\x14\n\x0c\x64\x61q_loglevel\x18\x15 \x01(\t\x12\x18\n\x10mininet_loglevel\x18\x16 \x01(\t\x12\x13\n\x0b\x66inish_hook\x18# \x01(\t\x12\x10\n\x08gcp_cred\x18\x17 \x01(\t\x12\x11\n\tgcp_topic\x18\x18 \x01(\t\x12\x13\n\x0bschema_path\x18\x19 \x01(\t\x12\x11\n\tmud_files\x18\x1a \x01(\t\x12\x14\n\x0c\x64\x65vice_specs\x18\x1b \x01(\t\x12\x13\n\x0btest_config\x18\x1c \x01(\t\x12\x19\n\x11port_debounce_sec\x18\x1d \x01(\x05\x12\x15\n\rtopology_hook\x18\x1e \x01(\t\x12\x17\n\x0f\x64\x65vice_template\x18\x1f \x01(\t\x12\x14\n\x0csite_reports\x18 \x01(\t\x12\x1f\n\x17run_data_retention_days\x18! \x01(\x02\x12.\n\ninterfaces\x18% \x03(\x0b\x32\x1a.DaqConfig.InterfacesEntry\x12/\n\x0b\x66\x61il_module\x18/ \x03(\x0b\x32\x1a.DaqConfig.FailModuleEntry\x12\x1d\n\x15port_flap_timeout_sec\x18\x30 \x01(\x05\x12\x1c\n\tusi_setup\x18\x31 \x01(\x0b\x32\t.USISetup\x12)\n\x10run_trigger_type\x18\x32 \x01(\x0e\x32\x0f.RunTriggerType\x12\x12\n\ndebug_mode\x18\x33 \x01(\x08\x12\x13\n\x0buse_console\x18\x34 \x01(\x08\x1a=\n\x0fInterfacesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x19\n\x05value\x18\x02 \x01(\x0b\x32\n.Interface:\x02\x38\x01\x1a\x31\n\x0f\x46\x61ilModuleEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"0\n\x08USISetup\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x17\n\x0frpc_timeout_sec\x18\x02 \x01(\x05\"\xf4\x01\n\x0bSwitchSetup\x12\x11\n\tctrl_intf\x18\t \x01(\t\x12\x0f\n\x07ip_addr\x18\x0b \x01(\t\x12\x13\n\x0buplink_port\x18\r \x01(\x05\x12\x0f\n\x07lo_port\x18\x0e \x01(\x05\x12\x10\n\x08\x61lt_port\x18\x10 \x01(\x05\x12\x0f\n\x07lo_addr\x18\x12 \x01(\t\x12\x11\n\tmods_addr\x18\x14 \x01(\t\x12\x0f\n\x07of_dpid\x18) \x01(\t\x12\x11\n\tdata_intf\x18* \x01(\t\x12\x0e\n\x06\x65xt_br\x18+ \x01(\t\x12\r\n\x05model\x18, \x01(\t\x12\x10\n\x08username\x18- \x01(\t\x12\x10\n\x08password\x18. \x01(\t\"\'\n\tInterface\x12\x0c\n\x04opts\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05*$\n\x0eRunTriggerType\x12\x08\n\x04PORT\x10\x00\x12\x08\n\x04VLAN\x10\x01\x62\x06proto3') + serialized_pb=_b('\n\x1d\x64\x61q/proto/system_config.proto\"\xf1\x08\n\tDaqConfig\x12\x18\n\x10site_description\x18\x01 \x01(\t\x12\x18\n\x10monitor_scan_sec\x18\x02 \x01(\x05\x12\x1b\n\x13\x64\x65\x66\x61ult_timeout_sec\x18\x03 \x01(\x05\x12\x12\n\nsettle_sec\x18& \x01(\x05\x12\x11\n\tbase_conf\x18\x04 \x01(\t\x12\x11\n\tsite_path\x18\x05 \x01(\t\x12\x1f\n\x17initial_dhcp_lease_time\x18\x06 \x01(\t\x12\x17\n\x0f\x64hcp_lease_time\x18\x07 \x01(\t\x12\x19\n\x11\x64hcp_response_sec\x18\' \x01(\x05\x12\x1e\n\x16long_dhcp_response_sec\x18\x08 \x01(\x05\x12\"\n\x0cswitch_setup\x18\t \x01(\x0b\x32\x0c.SwitchSetup\x12\x12\n\nhost_tests\x18\x10 \x01(\t\x12\x13\n\x0b\x62uild_tests\x18$ \x01(\x08\x12\x11\n\trun_limit\x18\x11 \x01(\x05\x12\x11\n\tfail_mode\x18\x12 \x01(\x08\x12\x13\n\x0bsingle_shot\x18\" \x01(\x08\x12\x15\n\rresult_linger\x18\x13 \x01(\x08\x12\x0f\n\x07no_test\x18\x14 \x01(\x08\x12\x11\n\tkeep_hold\x18( \x01(\x08\x12\x14\n\x0c\x64\x61q_loglevel\x18\x15 \x01(\t\x12\x18\n\x10mininet_loglevel\x18\x16 \x01(\t\x12\x13\n\x0b\x66inish_hook\x18# \x01(\t\x12\x10\n\x08gcp_cred\x18\x17 \x01(\t\x12\x11\n\tgcp_topic\x18\x18 \x01(\t\x12\x13\n\x0bschema_path\x18\x19 \x01(\t\x12\x11\n\tmud_files\x18\x1a \x01(\t\x12\x14\n\x0c\x64\x65vice_specs\x18\x1b \x01(\t\x12\x13\n\x0btest_config\x18\x1c \x01(\t\x12\x19\n\x11port_debounce_sec\x18\x1d \x01(\x05\x12\x15\n\rtopology_hook\x18\x1e \x01(\t\x12\x17\n\x0f\x64\x65vice_template\x18\x1f \x01(\t\x12\x14\n\x0csite_reports\x18 \x01(\t\x12\x1f\n\x17run_data_retention_days\x18! \x01(\x02\x12.\n\ninterfaces\x18% \x03(\x0b\x32\x1a.DaqConfig.InterfacesEntry\x12/\n\x0b\x66\x61il_module\x18/ \x03(\x0b\x32\x1a.DaqConfig.FailModuleEntry\x12\x1d\n\x15port_flap_timeout_sec\x18\x30 \x01(\x05\x12\x1c\n\tusi_setup\x18\x31 \x01(\x0b\x32\t.USISetup\x12)\n\x10run_trigger_type\x18\x32 \x01(\x0e\x32\x0f.RunTriggerType\x12\x12\n\ndebug_mode\x18\x33 \x01(\x08\x12\x13\n\x0buse_console\x18\x34 \x01(\x08\x1a=\n\x0fInterfacesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x19\n\x05value\x18\x02 \x01(\x0b\x32\n.Interface:\x02\x38\x01\x1a\x31\n\x0f\x46\x61ilModuleEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"0\n\x08USISetup\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x17\n\x0frpc_timeout_sec\x18\x02 \x01(\x05\"\xf4\x01\n\x0bSwitchSetup\x12\x11\n\tctrl_intf\x18\t \x01(\t\x12\x0f\n\x07ip_addr\x18\x0b \x01(\t\x12\x13\n\x0buplink_port\x18\r \x01(\x05\x12\x0f\n\x07lo_port\x18\x0e \x01(\x05\x12\x10\n\x08\x61lt_port\x18\x10 \x01(\x05\x12\x0f\n\x07lo_addr\x18\x12 \x01(\t\x12\x11\n\tmods_addr\x18\x14 \x01(\t\x12\x0f\n\x07of_dpid\x18) \x01(\t\x12\x11\n\tdata_intf\x18* \x01(\t\x12\x0e\n\x06\x65xt_br\x18+ \x01(\t\x12\r\n\x05model\x18, \x01(\t\x12\x10\n\x08username\x18- \x01(\t\x12\x10\n\x08password\x18. \x01(\t\"\'\n\tInterface\x12\x0c\n\x04opts\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05*$\n\x0eRunTriggerType\x12\x08\n\x04PORT\x10\x00\x12\x08\n\x04VLAN\x10\x01*U\n\x08\x44HCPMode\x12\n\n\x06NORMAL\x10\x00\x12\r\n\tSTATIC_IP\x10\x01\x12\x0c\n\x08\x45XTERNAL\x10\x02\x12\x11\n\rLONG_RESPONSE\x10\x03\x12\r\n\tIP_CHANGE\x10\x04\x62\x06proto3') ) _RUNTRIGGERTYPE = _descriptor.EnumDescriptor( @@ -46,8 +46,48 @@ _sym_db.RegisterEnumDescriptor(_RUNTRIGGERTYPE) RunTriggerType = enum_type_wrapper.EnumTypeWrapper(_RUNTRIGGERTYPE) +_DHCPMODE = _descriptor.EnumDescriptor( + name='DHCPMode', + full_name='DHCPMode', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='NORMAL', index=0, number=0, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='STATIC_IP', index=1, number=1, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='EXTERNAL', index=2, number=2, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='LONG_RESPONSE', index=3, number=3, + serialized_options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='IP_CHANGE', index=4, number=4, + serialized_options=None, + type=None), + ], + containing_type=None, + serialized_options=None, + serialized_start=1549, + serialized_end=1634, +) +_sym_db.RegisterEnumDescriptor(_DHCPMODE) + +DHCPMode = enum_type_wrapper.EnumTypeWrapper(_DHCPMODE) PORT = 0 VLAN = 1 +NORMAL = 0 +STATIC_IP = 1 +EXTERNAL = 2 +LONG_RESPONSE = 3 +IP_CHANGE = 4 @@ -632,6 +672,7 @@ DESCRIPTOR.message_types_by_name['SwitchSetup'] = _SWITCHSETUP DESCRIPTOR.message_types_by_name['Interface'] = _INTERFACE DESCRIPTOR.enum_types_by_name['RunTriggerType'] = _RUNTRIGGERTYPE +DESCRIPTOR.enum_types_by_name['DHCPMode'] = _DHCPMODE _sym_db.RegisterFileDescriptor(DESCRIPTOR) DaqConfig = _reflection.GeneratedProtocolMessageType('DaqConfig', (_message.Message,), dict( diff --git a/libs/proto/usi_pb2.py b/libs/proto/usi_pb2.py index 780ac2e1c2..c96202d031 100644 --- a/libs/proto/usi_pb2.py +++ b/libs/proto/usi_pb2.py @@ -20,7 +20,7 @@ syntax='proto3', serialized_options=b'\n\004grpcB\010USIProtoP\001', create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\tusi.proto\x12\x03usi\"\'\n\x14SwitchActionResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\"\xc9\x01\n\rPowerResponse\x12!\n\x19\x63urrent_power_consumption\x18\x01 \x01(\x02\x12\x1d\n\x15max_power_consumption\x18\x02 \x01(\x02\x12$\n\x0bpoe_support\x18\x03 \x01(\x0e\x32\x0f.usi.POESupport\x12\"\n\npoe_status\x18\x04 \x01(\x0e\x32\x0e.usi.POEStatus\x12,\n\x0fpoe_negotiation\x18\x05 \x01(\x0e\x32\x13.usi.POENegotiation\"]\n\x11InterfaceResponse\x12$\n\x0blink_status\x18\x01 \x01(\x0e\x32\x0f.usi.LinkStatus\x12\x12\n\nlink_speed\x18\x02 \x01(\x05\x12\x0e\n\x06\x64uplex\x18\x03 \x01(\t\"w\n\nSwitchInfo\x12\x0f\n\x07ip_addr\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65vice_port\x18\x03 \x01(\x05\x12\x1f\n\x05model\x18\x04 \x01(\x0e\x32\x10.usi.SwitchModel\x12\x10\n\x08username\x18\x05 \x01(\t\x12\x10\n\x08password\x18\x06 \x01(\t*F\n\x0bSwitchModel\x12\x17\n\x13\x41LLIED_TELESIS_X230\x10\x00\x12\x0e\n\nCISCO_9300\x10\x01\x12\x0e\n\nOVS_SWITCH\x10\x02*\x1e\n\nLinkStatus\x12\x06\n\x02UP\x10\x00\x12\x08\n\x04\x44OWN\x10\x01*\'\n\nPOESupport\x12\x0b\n\x07\x45NABLED\x10\x00\x12\x0c\n\x08\x44ISABLED\x10\x01*1\n\tPOEStatus\x12\x06\n\x02ON\x10\x00\x12\x07\n\x03OFF\x10\x01\x12\t\n\x05\x46\x41ULT\x10\x02\x12\x08\n\x04\x44\x45NY\x10\x03*C\n\x0ePOENegotiation\x12\x17\n\x13NEGOTIATION_ENABLED\x10\x00\x12\x18\n\x14NEGOTIATION_DISABLED\x10\x01\x32\xef\x01\n\nUSIService\x12\x31\n\x08GetPower\x12\x0f.usi.SwitchInfo\x1a\x12.usi.PowerResponse\"\x00\x12\x39\n\x0cGetInterface\x12\x0f.usi.SwitchInfo\x1a\x16.usi.InterfaceResponse\"\x00\x12:\n\ndisconnect\x12\x0f.usi.SwitchInfo\x1a\x19.usi.SwitchActionResponse\"\x00\x12\x37\n\x07\x63onnect\x12\x0f.usi.SwitchInfo\x1a\x19.usi.SwitchActionResponse\"\x00\x42\x12\n\x04grpcB\x08USIProtoP\x01\x62\x06proto3' + serialized_pb=b'\n\tusi.proto\x12\x03usi\"\'\n\x14SwitchActionResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\"\xef\x01\n\rPowerResponse\x12!\n\x19\x63urrent_power_consumption\x18\x01 \x01(\x02\x12\x1d\n\x15max_power_consumption\x18\x02 \x01(\x02\x12*\n\x0bpoe_support\x18\x03 \x01(\x0e\x32\x15.usi.POESupport.State\x12(\n\npoe_status\x18\x04 \x01(\x0e\x32\x14.usi.POEStatus.State\x12\x32\n\x0fpoe_negotiation\x18\x05 \x01(\x0e\x32\x19.usi.POENegotiation.State\x12\x12\n\nraw_output\x18\x06 \x01(\t\"w\n\x11InterfaceResponse\x12*\n\x0blink_status\x18\x01 \x01(\x0e\x32\x15.usi.LinkStatus.State\x12\x12\n\nlink_speed\x18\x02 \x01(\x05\x12\x0e\n\x06\x64uplex\x18\x03 \x01(\t\x12\x12\n\nraw_output\x18\x04 \x01(\t\"4\n\nLinkStatus\"&\n\x05State\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x08\n\x04\x44OWN\x10\x01\x12\x06\n\x02UP\x10\x02\"=\n\nPOESupport\"/\n\x05State\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x0b\n\x07\x45NABLED\x10\x01\x12\x0c\n\x08\x44ISABLED\x10\x02\"G\n\tPOEStatus\":\n\x05State\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x06\n\x02ON\x10\x01\x12\x07\n\x03OFF\x10\x02\x12\t\n\x05\x46\x41ULT\x10\x03\x12\x08\n\x04\x44\x45NY\x10\x04\"A\n\x0ePOENegotiation\"/\n\x05State\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x0b\n\x07\x45NABLED\x10\x01\x12\x0c\n\x08\x44ISABLED\x10\x02\"w\n\nSwitchInfo\x12\x0f\n\x07ip_addr\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65vice_port\x18\x03 \x01(\x05\x12\x1f\n\x05model\x18\x04 \x01(\x0e\x32\x10.usi.SwitchModel\x12\x10\n\x08username\x18\x05 \x01(\t\x12\x10\n\x08password\x18\x06 \x01(\t*F\n\x0bSwitchModel\x12\x17\n\x13\x41LLIED_TELESIS_X230\x10\x00\x12\x0e\n\nCISCO_9300\x10\x01\x12\x0e\n\nOVS_SWITCH\x10\x02\x32\xef\x01\n\nUSIService\x12\x31\n\x08GetPower\x12\x0f.usi.SwitchInfo\x1a\x12.usi.PowerResponse\"\x00\x12\x39\n\x0cGetInterface\x12\x0f.usi.SwitchInfo\x1a\x16.usi.InterfaceResponse\"\x00\x12:\n\ndisconnect\x12\x0f.usi.SwitchInfo\x1a\x19.usi.SwitchActionResponse\"\x00\x12\x37\n\x07\x63onnect\x12\x0f.usi.SwitchInfo\x1a\x19.usi.SwitchActionResponse\"\x00\x42\x12\n\x04grpcB\x08USIProtoP\x01\x62\x06proto3' ) _SWITCHMODEL = _descriptor.EnumDescriptor( @@ -48,21 +48,26 @@ ], containing_type=None, serialized_options=None, - serialized_start=479, - serialized_end=549, + serialized_start=800, + serialized_end=870, ) _sym_db.RegisterEnumDescriptor(_SWITCHMODEL) SwitchModel = enum_type_wrapper.EnumTypeWrapper(_SWITCHMODEL) -_LINKSTATUS = _descriptor.EnumDescriptor( - name='LinkStatus', - full_name='usi.LinkStatus', +ALLIED_TELESIS_X230 = 0 +CISCO_9300 = 1 +OVS_SWITCH = 2 + + +_LINKSTATUS_STATE = _descriptor.EnumDescriptor( + name='State', + full_name='usi.LinkStatus.State', filename=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key, values=[ _descriptor.EnumValueDescriptor( - name='UP', index=0, number=0, + name='UNKNOWN', index=0, number=0, serialized_options=None, type=None, create_key=_descriptor._internal_create_key), @@ -71,117 +76,118 @@ serialized_options=None, type=None, create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='UP', index=2, number=2, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), ], containing_type=None, serialized_options=None, - serialized_start=551, - serialized_end=581, + serialized_start=436, + serialized_end=474, ) -_sym_db.RegisterEnumDescriptor(_LINKSTATUS) +_sym_db.RegisterEnumDescriptor(_LINKSTATUS_STATE) -LinkStatus = enum_type_wrapper.EnumTypeWrapper(_LINKSTATUS) -_POESUPPORT = _descriptor.EnumDescriptor( - name='POESupport', - full_name='usi.POESupport', +_POESUPPORT_STATE = _descriptor.EnumDescriptor( + name='State', + full_name='usi.POESupport.State', filename=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key, values=[ _descriptor.EnumValueDescriptor( - name='ENABLED', index=0, number=0, + name='UNKNOWN', index=0, number=0, serialized_options=None, type=None, create_key=_descriptor._internal_create_key), _descriptor.EnumValueDescriptor( - name='DISABLED', index=1, number=1, + name='ENABLED', index=1, number=1, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='DISABLED', index=2, number=2, serialized_options=None, type=None, create_key=_descriptor._internal_create_key), ], containing_type=None, serialized_options=None, - serialized_start=583, - serialized_end=622, + serialized_start=490, + serialized_end=537, ) -_sym_db.RegisterEnumDescriptor(_POESUPPORT) +_sym_db.RegisterEnumDescriptor(_POESUPPORT_STATE) -POESupport = enum_type_wrapper.EnumTypeWrapper(_POESUPPORT) -_POESTATUS = _descriptor.EnumDescriptor( - name='POEStatus', - full_name='usi.POEStatus', +_POESTATUS_STATE = _descriptor.EnumDescriptor( + name='State', + full_name='usi.POEStatus.State', filename=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key, values=[ _descriptor.EnumValueDescriptor( - name='ON', index=0, number=0, + name='UNKNOWN', index=0, number=0, serialized_options=None, type=None, create_key=_descriptor._internal_create_key), _descriptor.EnumValueDescriptor( - name='OFF', index=1, number=1, + name='ON', index=1, number=1, serialized_options=None, type=None, create_key=_descriptor._internal_create_key), _descriptor.EnumValueDescriptor( - name='FAULT', index=2, number=2, + name='OFF', index=2, number=2, serialized_options=None, type=None, create_key=_descriptor._internal_create_key), _descriptor.EnumValueDescriptor( - name='DENY', index=3, number=3, + name='FAULT', index=3, number=3, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='DENY', index=4, number=4, serialized_options=None, type=None, create_key=_descriptor._internal_create_key), ], containing_type=None, serialized_options=None, - serialized_start=624, - serialized_end=673, + serialized_start=552, + serialized_end=610, ) -_sym_db.RegisterEnumDescriptor(_POESTATUS) +_sym_db.RegisterEnumDescriptor(_POESTATUS_STATE) -POEStatus = enum_type_wrapper.EnumTypeWrapper(_POESTATUS) -_POENEGOTIATION = _descriptor.EnumDescriptor( - name='POENegotiation', - full_name='usi.POENegotiation', +_POENEGOTIATION_STATE = _descriptor.EnumDescriptor( + name='State', + full_name='usi.POENegotiation.State', filename=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key, values=[ _descriptor.EnumValueDescriptor( - name='NEGOTIATION_ENABLED', index=0, number=0, + name='UNKNOWN', index=0, number=0, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='ENABLED', index=1, number=1, serialized_options=None, type=None, create_key=_descriptor._internal_create_key), _descriptor.EnumValueDescriptor( - name='NEGOTIATION_DISABLED', index=1, number=1, + name='DISABLED', index=2, number=2, serialized_options=None, type=None, create_key=_descriptor._internal_create_key), ], containing_type=None, serialized_options=None, - serialized_start=675, - serialized_end=742, + serialized_start=490, + serialized_end=537, ) -_sym_db.RegisterEnumDescriptor(_POENEGOTIATION) - -POENegotiation = enum_type_wrapper.EnumTypeWrapper(_POENEGOTIATION) -ALLIED_TELESIS_X230 = 0 -CISCO_9300 = 1 -OVS_SWITCH = 2 -UP = 0 -DOWN = 1 -ENABLED = 0 -DISABLED = 1 -ON = 0 -OFF = 1 -FAULT = 2 -DENY = 3 -NEGOTIATION_ENABLED = 0 -NEGOTIATION_DISABLED = 1 - +_sym_db.RegisterEnumDescriptor(_POENEGOTIATION_STATE) _SWITCHACTIONRESPONSE = _descriptor.Descriptor( @@ -259,6 +265,13 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='raw_output', full_name='usi.PowerResponse.raw_output', index=5, + number=6, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), ], extensions=[ ], @@ -272,7 +285,7 @@ oneofs=[ ], serialized_start=60, - serialized_end=261, + serialized_end=299, ) @@ -305,11 +318,44 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='raw_output', full_name='usi.InterfaceResponse.raw_output', index=3, + number=4, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=301, + serialized_end=420, +) + + +_LINKSTATUS = _descriptor.Descriptor( + name='LinkStatus', + full_name='usi.LinkStatus', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ ], extensions=[ ], nested_types=[], enum_types=[ + _LINKSTATUS_STATE, ], serialized_options=None, is_extendable=False, @@ -317,8 +363,86 @@ extension_ranges=[], oneofs=[ ], - serialized_start=263, - serialized_end=356, + serialized_start=422, + serialized_end=474, +) + + +_POESUPPORT = _descriptor.Descriptor( + name='POESupport', + full_name='usi.POESupport', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _POESUPPORT_STATE, + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=476, + serialized_end=537, +) + + +_POESTATUS = _descriptor.Descriptor( + name='POEStatus', + full_name='usi.POEStatus', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _POESTATUS_STATE, + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=539, + serialized_end=610, +) + + +_POENEGOTIATION = _descriptor.Descriptor( + name='POENegotiation', + full_name='usi.POENegotiation', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _POENEGOTIATION_STATE, + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=612, + serialized_end=677, ) @@ -377,24 +501,28 @@ extension_ranges=[], oneofs=[ ], - serialized_start=358, - serialized_end=477, + serialized_start=679, + serialized_end=798, ) -_POWERRESPONSE.fields_by_name['poe_support'].enum_type = _POESUPPORT -_POWERRESPONSE.fields_by_name['poe_status'].enum_type = _POESTATUS -_POWERRESPONSE.fields_by_name['poe_negotiation'].enum_type = _POENEGOTIATION -_INTERFACERESPONSE.fields_by_name['link_status'].enum_type = _LINKSTATUS +_POWERRESPONSE.fields_by_name['poe_support'].enum_type = _POESUPPORT_STATE +_POWERRESPONSE.fields_by_name['poe_status'].enum_type = _POESTATUS_STATE +_POWERRESPONSE.fields_by_name['poe_negotiation'].enum_type = _POENEGOTIATION_STATE +_INTERFACERESPONSE.fields_by_name['link_status'].enum_type = _LINKSTATUS_STATE +_LINKSTATUS_STATE.containing_type = _LINKSTATUS +_POESUPPORT_STATE.containing_type = _POESUPPORT +_POESTATUS_STATE.containing_type = _POESTATUS +_POENEGOTIATION_STATE.containing_type = _POENEGOTIATION _SWITCHINFO.fields_by_name['model'].enum_type = _SWITCHMODEL DESCRIPTOR.message_types_by_name['SwitchActionResponse'] = _SWITCHACTIONRESPONSE DESCRIPTOR.message_types_by_name['PowerResponse'] = _POWERRESPONSE DESCRIPTOR.message_types_by_name['InterfaceResponse'] = _INTERFACERESPONSE +DESCRIPTOR.message_types_by_name['LinkStatus'] = _LINKSTATUS +DESCRIPTOR.message_types_by_name['POESupport'] = _POESUPPORT +DESCRIPTOR.message_types_by_name['POEStatus'] = _POESTATUS +DESCRIPTOR.message_types_by_name['POENegotiation'] = _POENEGOTIATION DESCRIPTOR.message_types_by_name['SwitchInfo'] = _SWITCHINFO DESCRIPTOR.enum_types_by_name['SwitchModel'] = _SWITCHMODEL -DESCRIPTOR.enum_types_by_name['LinkStatus'] = _LINKSTATUS -DESCRIPTOR.enum_types_by_name['POESupport'] = _POESUPPORT -DESCRIPTOR.enum_types_by_name['POEStatus'] = _POESTATUS -DESCRIPTOR.enum_types_by_name['POENegotiation'] = _POENEGOTIATION _sym_db.RegisterFileDescriptor(DESCRIPTOR) SwitchActionResponse = _reflection.GeneratedProtocolMessageType('SwitchActionResponse', (_message.Message,), { @@ -418,6 +546,34 @@ }) _sym_db.RegisterMessage(InterfaceResponse) +LinkStatus = _reflection.GeneratedProtocolMessageType('LinkStatus', (_message.Message,), { + 'DESCRIPTOR' : _LINKSTATUS, + '__module__' : 'usi_pb2' + # @@protoc_insertion_point(class_scope:usi.LinkStatus) + }) +_sym_db.RegisterMessage(LinkStatus) + +POESupport = _reflection.GeneratedProtocolMessageType('POESupport', (_message.Message,), { + 'DESCRIPTOR' : _POESUPPORT, + '__module__' : 'usi_pb2' + # @@protoc_insertion_point(class_scope:usi.POESupport) + }) +_sym_db.RegisterMessage(POESupport) + +POEStatus = _reflection.GeneratedProtocolMessageType('POEStatus', (_message.Message,), { + 'DESCRIPTOR' : _POESTATUS, + '__module__' : 'usi_pb2' + # @@protoc_insertion_point(class_scope:usi.POEStatus) + }) +_sym_db.RegisterMessage(POEStatus) + +POENegotiation = _reflection.GeneratedProtocolMessageType('POENegotiation', (_message.Message,), { + 'DESCRIPTOR' : _POENEGOTIATION, + '__module__' : 'usi_pb2' + # @@protoc_insertion_point(class_scope:usi.POENegotiation) + }) +_sym_db.RegisterMessage(POENegotiation) + SwitchInfo = _reflection.GeneratedProtocolMessageType('SwitchInfo', (_message.Message,), { 'DESCRIPTOR' : _SWITCHINFO, '__module__' : 'usi_pb2' @@ -435,8 +591,8 @@ index=0, serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_start=745, - serialized_end=984, + serialized_start=873, + serialized_end=1112, methods=[ _descriptor.MethodDescriptor( name='GetPower', diff --git a/proto/system_config.proto b/proto/system_config.proto index 16e8316f6f..9a37076533 100644 --- a/proto/system_config.proto +++ b/proto/system_config.proto @@ -133,6 +133,14 @@ enum RunTriggerType { VLAN = 1; } +enum DHCPMode { + NORMAL = 0; + STATIC_IP = 1; + EXTERNAL = 2; + LONG_RESPONSE = 3; + IP_CHANGE = 4; +} + /** * USI paramters **/ diff --git a/testing/test_dhcp.sh b/testing/test_dhcp.sh index a60cff4159..00e5eae45f 100755 --- a/testing/test_dhcp.sh +++ b/testing/test_dhcp.sh @@ -25,7 +25,7 @@ cat < local/site/mac_addrs/$intf_mac/module_config.json "modules": { "ipaddr": { "timeout_sec": 320, - "dhcp_mode": "long_response" + "dhcp_mode": "LONG_RESPONSE" } } } From ccde0e4f7599ab4edc504b8b69e5b6a0d83ea16f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 5 Oct 2020 11:35:56 -0700 Subject: [PATCH 155/212] Update dependency commons-net:commons-net to v3.7.1 (#663) --- subset/switches/pom.xml | 2 +- usi/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subset/switches/pom.xml b/subset/switches/pom.xml index 4783c41d5a..44e1dc0bf8 100644 --- a/subset/switches/pom.xml +++ b/subset/switches/pom.xml @@ -33,7 +33,7 @@ commons-net commons-net - 3.6 + 3.7.1 io.grpc diff --git a/usi/pom.xml b/usi/pom.xml index 7f58f48325..7b5377a11a 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -33,7 +33,7 @@ commons-net commons-net - 3.7 + 3.7.1 io.grpc From c15c97b1edebc024ee54b9ade2cac7aafd790dd3 Mon Sep 17 00:00:00 2001 From: henry54809 Date: Tue, 6 Oct 2020 09:26:15 -0700 Subject: [PATCH 156/212] New "new ip" assignment (#666) --- config/system/default.yaml | 2 +- daq/host.py | 2 +- docker/include/network/scripts/change_dhcp_range | 1 + docker/include/network/scripts/new_ip | 13 +++++++++---- subset/switches/test_switch | 4 +++- testing/test_dhcp.out | 2 +- testing/test_dhcp.sh | 3 ++- 7 files changed, 18 insertions(+), 9 deletions(-) diff --git a/config/system/default.yaml b/config/system/default.yaml index 3b3746f6f4..f953d83f89 100644 --- a/config/system/default.yaml +++ b/config/system/default.yaml @@ -46,4 +46,4 @@ run_trigger_type: PORT # usi url for DAQ to connect to usi_setup: url: localhost:5000 - rpc_timeout_sec: 10 + rpc_timeout_sec: 20 diff --git a/daq/host.py b/daq/host.py index 74ba2ae9b5..de8a296dfc 100644 --- a/daq/host.py +++ b/daq/host.py @@ -68,7 +68,7 @@ class ConnectedHost: """Class managing a device-under-test""" _STARTUP_MIN_TIME_SEC = 5 - _RPC_TIMEOUT_SEC = 10 + _RPC_TIMEOUT_SEC = 20 _INST_DIR = "inst/" _DEVICE_PATH = "device/%s" _NETWORK_DIR = "inst/network" diff --git a/docker/include/network/scripts/change_dhcp_range b/docker/include/network/scripts/change_dhcp_range index 0c45cd6bae..2632b28f48 100755 --- a/docker/include/network/scripts/change_dhcp_range +++ b/docker/include/network/scripts/change_dhcp_range @@ -14,6 +14,7 @@ fi while [ $(cat /etc/dnsmasq.conf | egrep "^dhcp-range=" | wc -l) == 0 ]; do sleep 1 done +ip addr flush dev eth0 # Remove eth0 ip addr so there're no ip conflicts. ip addr add $range_start/$prefix_len dev $LOCAL_IF || true original=$(cat /etc/dnsmasq.conf | egrep "^dhcp-range=" | head -1) lease=$(echo $original | cut -d',' -f 3) diff --git a/docker/include/network/scripts/new_ip b/docker/include/network/scripts/new_ip index a91855d90c..8438697570 100755 --- a/docker/include/network/scripts/new_ip +++ b/docker/include/network/scripts/new_ip @@ -10,11 +10,16 @@ fi function get_next_ip() { cur_ip=$1 - prefix=$(echo $cur_ip | cut -d '.' -f 1,2) - subnet=$(echo $cur_ip | cut -d '.' -f 3) - new_subnet=$((($subnet + 1) % 256)) + prefix=$(echo $cur_ip | cut -d '.' -f 1,2,3) postfix=$(echo $cur_ip | cut -d '.' -f 4) - new_ip=$prefix.$new_subnet.$postfix + new_postfix=$((($postfix + 1) % 256)) + while [ $(grep $prefix.$new_postfix /var/lib/misc/dnsmasq.leases | wc -l) -gt 0 ]; do + if [ $new_postfix -eq $postfix ]; then + break + fi + new_postfix=$((($new_postfix + 1) % 256)) + done + new_ip=$prefix.$new_postfix } original=$(cat /etc/dnsmasq.conf | egrep "dhcp-host=$mac_addr,([0-9]{1,3}\.){3}[0-9]{1,3}" | head -1) diff --git a/subset/switches/test_switch b/subset/switches/test_switch index 0c89272866..1d58ab9ca2 100755 --- a/subset/switches/test_switch +++ b/subset/switches/test_switch @@ -26,7 +26,9 @@ if [ -n "$LOCAL_IP" ]; then echo Switch test with model $SWITCH_MODEL echo Switch test with ip:port $SWITCH_IP:$TARGET_PORT echo Switch test with username:password $SWITCH_USERNAME:$SWITCH_PASSWORD - ping -n -c 10 $SWITCH_IP + + # It may take up to 40 pings for it to go through for Cisco switch. Root cause is still unknown atm. + ping -n -c 100 $SWITCH_IP POE_ENABLED=`jq -r .modules.switch.poe.enabled $MODULE_CONFIG` java -jar switches/target/switchtest-0.0.1-jar-with-dependencies.jar $USI_URL $RPC_TIMEOUT $SWITCH_IP $TARGET_PORT $POE_ENABLED $SWITCH_MODEL $SWITCH_USERNAME $SWITCH_PASSWORD diff --git a/testing/test_dhcp.out b/testing/test_dhcp.out index 1b57cd6c4f..c9ab0bfb43 100644 --- a/testing/test_dhcp.out +++ b/testing/test_dhcp.out @@ -10,7 +10,7 @@ Device 1 ip triggers: 1 0 Device 2 ip triggers: 0 0 Device 3 long ip triggers: 1 Device 4 ip triggers: 1 -Device 4 subnet 1 ip: 1 subnet 2 ip: 1 subnet 3 ip: 2 +Device 4 subnet 1 ip: 1 subnet 2 ip: 1 subnet 3 ip: 2 ip_changed: 1 Device 5 ip triggers: 1 Device 5 num of ips: 2 DHCP timeouts: 1 diff --git a/testing/test_dhcp.sh b/testing/test_dhcp.sh index 00e5eae45f..b3796c53de 100755 --- a/testing/test_dhcp.sh +++ b/testing/test_dhcp.sh @@ -108,7 +108,8 @@ for iface in $(seq 1 5); do subnet_ip=$(fgrep "ip notification 192.168" inst/run-*/nodes/ipaddr*/tmp/activate.log | wc -l) subnet2_ip=$(fgrep "ip notification 10.255.255" inst/run-*/nodes/ipaddr*/tmp/activate.log | wc -l) subnet3_ip=$(fgrep "ip notification 172.16.0" inst/run-*/nodes/ipaddr*/tmp/activate.log | wc -l) - echo "Device $iface subnet 1 ip: $subnet_ip subnet 2 ip: $subnet2_ip subnet 3 ip: $subnet3_ip" | tee -a $TEST_RESULTS + subnet_ip_change=$(fgrep "ip notification 172.16.0" inst/run-*/nodes/ipaddr*/tmp/activate.log | awk '{print $6}' | uniq | wc -l) + echo "Device $iface subnet 1 ip: $subnet_ip subnet 2 ip: $subnet2_ip subnet 3 ip: $subnet3_ip ip_changed: $((subnet_ip_change > 1))" | tee -a $TEST_RESULTS elif [ $iface == 3 ]; then echo "Device $iface long ip triggers: $((long_triggers > 0))" | tee -a $TEST_RESULTS else From a245e35a3f7a5ba18c5624d6648581c9536553b9 Mon Sep 17 00:00:00 2001 From: puneet Date: Tue, 6 Oct 2020 10:53:20 -0700 Subject: [PATCH 157/212] 1.9.8 release --- docs/changelog.md | 34 +++++++++++++++++++++++++++ etc/docker_images.txt | 54 ++++++++++++++++++++++--------------------- etc/docker_images.ver | 2 +- 3 files changed, 63 insertions(+), 27 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index c89e4488db..fcd6b8c867 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,4 +1,38 @@ # Changelog +* 1.9.8 + * New "new ip" assignment, extend rpc_timeout_sec and ping counts for Cisco switches (#666) + * Update dependency commons-net:commons-net to v3.7.1 (#663) + * gateway refactoring (#662) + * Add manual tests to resource config (#621) + * Tls timeout fix and ohter updates (#651, #626) + * Private Address (6) (#584) + * DHCP Short (9) (#579) + * Cisco switch more expected table output (#657) + * Pin dependency node-forge to 0.10.0 (#653) + * Basic UDMI provisioner test (#648) + * Update dependency node-forge to v0.10.0 [SECURITY] (#650) + * ipaddr DHCP timeout behavior change (#652) + * Adding node-forge upgrade (#649) + * fix no_test option (#647) + * granular dhcp test timeouts. (#645) + * Update UDMI version to 1.2.0 (#646) + * Disable stickler print-function check (#637) + * Clear out port_acls directory for local test runs. (#640) + * Feature/native tests (#625) + * Update dependency jsoneditor to v9.1.0 (#642) + * Update dependency firebase-admin to v9.2.0 (#641) + * switch config files (#633) + * Add DNS hostname resolution test (#638) + * Update dependency org.junit.jupiter:junit-jupiter to v5.7.0 (#639) + * Bump node-fetch from 2.6.0 to 2.6.1 in /firebase/functions (#635) + * add raw output from usi. (#636) + * Merging ipaddr and dhcp (#634) + * Update dependency io.grpc:grpc-protobuf to v1.32.1 (#630) + * Update dependency io.grpc:grpc-bom to v1.32.1 (#631) + * Update dependency io.grpc:grpc-stub to v1.32.1 (#632) + * Update dependency io.grpc:grpc-netty-shaded to v1.32.1 (#629) + * Update dependency jsoneditor to v9.0.5 (#628) + * Adding timestamps to ipaddr test log messages. (#627) * 1.9.6 * Switch poe updates (#605) - Alignment of PoE test to test plan. * Cisco Switches parsing fix (#623) diff --git a/etc/docker_images.txt b/etc/docker_images.txt index 588b6828a6..e886b3759d 100644 --- a/etc/docker_images.txt +++ b/etc/docker_images.txt @@ -1,26 +1,28 @@ -daqf/aardvark 59b11e4809cf -daqf/default 784a86bc573f -daqf/faucet dca9d4fa2d90 -daqf/faux1 7962ab064630 -daqf/faux2 0a83fd163f62 -daqf/gauge d5724dd3c0a1 -daqf/networking c5de092a7471 -daqf/switch 225dc0542c1c -daqf/test_bacext e252d1b60c9e -daqf/test_bacnet 62522aca2f39 -daqf/test_brute 7700dcc75d0e -daqf/test_discover 1317ab4bdb67 -daqf/test_fail 289a7f90d24d -daqf/test_hold c3661ceeeff9 -daqf/test_manual c1a5eba7e164 -daqf/test_mudgee ac8f82de77c5 -daqf/test_network 30fd818cef6b -daqf/test_nmap 132eb91672c1 -daqf/test_pass 6dd331d8ca3f -daqf/test_password ba91ccab59b2 -daqf/test_ping 5cd777ab4180 -daqf/test_ssh 49b8200b3ffa -daqf/test_switch b47518a8e1d8 -daqf/test_tls fd4a5ffd4372 -daqf/test_udmi 4af41d1276d8 -daqf/usi d70f829f1050 +daqf/aardvark2 ba31f0cdb571 +daqf/aardvark 52c88e3e29e9 +daqf/default 1f85c8cfd8b8 +daqf/faucet fa7367da86db +daqf/faux1 ddeff0fb4754 +daqf/faux2 1b77f7e85617 +daqf/gauge d4d9bfe1dce4 +daqf/networking 959f29a0882e +daqf/switch 2b0aa3afdf68 +daqf/test_bacext 974ccaf9bf18 +daqf/test_bacnet 08947e647db6 +daqf/test_brute 87ecefddf2ac +daqf/test_discover a8b5185faefe +daqf/test_fail 950817b0746f +daqf/test_hold 9ae60191b01f +daqf/test_ipaddr 2062d59c6a00 +daqf/test_manual 5bf34aaa9022 +daqf/test_mudgee 6d69223fc470 +daqf/test_network 875fa4a8ee38 +daqf/test_nmap 8c5de302c83a +daqf/test_pass 94139c33b754 +daqf/test_password 681129401c9d +daqf/test_ping c5967970fe7c +daqf/test_ssh 95069cbe6986 +daqf/test_switch 3f9467a6b64e +daqf/test_tls 5579450357a9 +daqf/test_udmi f6b132ae1c61 +daqf/usi a62f71285240 diff --git a/etc/docker_images.ver b/etc/docker_images.ver index 7bc1c40470..66beabb579 100644 --- a/etc/docker_images.ver +++ b/etc/docker_images.ver @@ -1 +1 @@ -1.9.6 +1.9.8 From 60631d06101e27d56ecb8e672cfd6a347174dcdc Mon Sep 17 00:00:00 2001 From: henry54809 Date: Tue, 6 Oct 2020 17:52:49 -0700 Subject: [PATCH 158/212] Rename startup script (#669) --- daq/host.py | 4 ++-- daq/runner.py | 4 ++-- daq/test_modules/native_host.py | 12 ++++++------ daq/test_modules/native_module.py | 6 +++--- subset/fail/fail.daqmodule | 2 +- subset/pass/pass.daqmodule | 2 +- subset/pentests/nmap/nmap.daqmodule | 2 +- subset/ping/ping.daqmodule | 2 +- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/daq/host.py b/daq/host.py index de8a296dfc..5a8ff66d58 100644 --- a/daq/host.py +++ b/daq/host.py @@ -626,7 +626,7 @@ def _device_aux_path(self): def _new_test(self, test_name): if test_name in self.config['test_metadata']: metadatum = self.config['test_metadata'][test_name] - startup_script = metadatum['startup_script'] + startup_cmd = metadatum['startup_cmd'] basedir = os.path.abspath(metadatum['basedir']) new_root = os.path.abspath(os.path.join(self.devdir, 'test_root')) if os.path.isdir(new_root): @@ -636,7 +636,7 @@ def _new_test(self, test_name): src_full = os.path.join(basedir, src_file) os.symlink(src_full, os.path.join(new_root, src_file)) return NativeModule(self, self.devdir, test_name, self._loaded_config, new_root, - startup_script) + startup_cmd) clazz = IpAddrModule if test_name == 'ipaddr' else DockerModule return clazz(self, self.devdir, test_name, self._loaded_config) diff --git a/daq/runner.py b/daq/runner.py index f6339fa27e..9da74b3037 100644 --- a/daq/runner.py +++ b/daq/runner.py @@ -556,11 +556,11 @@ def _get_test_metadata(self, extension=".daqmodule", root="."): continue with open(meta_file) as fd: metadatum = json.loads(fd.read()) - assert "name" in metadatum and "startup_script" in metadatum + assert "name" in metadatum and "startup_cmd" in metadatum module = metadatum["name"] assert module not in metadata, "Duplicate module definition for %s" % module metadata[module] = { - "startup_script": metadatum["startup_script"], + "startup_cmd": metadatum["startup_cmd"], "basedir": meta_file.parent } return metadata diff --git a/daq/test_modules/native_host.py b/daq/test_modules/native_host.py index 1d3b5203bc..fe15ec1609 100644 --- a/daq/test_modules/native_host.py +++ b/daq/test_modules/native_host.py @@ -19,7 +19,7 @@ class NativeHost(Host): # pylint: disable=too-many-arguments def __init__(self, name, basedir=None, tmpdir=None, env_vars=None, vol_maps=None, - startup_script='entrypoint', **kwargs): + startup_cmd='entrypoint', **kwargs): self.basedir = basedir self.tmpdir = tmpdir self.env_vars = env_vars if env_vars is not None else [] @@ -27,8 +27,8 @@ def __init__(self, name, basedir=None, tmpdir=None, env_vars=None, vol_maps=None self.vol_maps.append((os.path.abspath(os.path.join(self.tmpdir, 'tmp')), os.path.join(self.basedir, 'tmp'))) self.name = name - script_full_path = os.path.join(self.basedir, startup_script) - self.startup_script = startup_script if startup_script.startswith('/') else script_full_path + script_full_path = os.path.join(self.basedir, startup_cmd) + self.startup_cmd = startup_cmd if startup_cmd.startswith('/') else script_full_path self.active_pipe = None self.active_log = None Host.__init__(self, name, **kwargs) @@ -53,7 +53,7 @@ def activate(self, log_name='activate.log'): stdout = PIPE self.active_log = None - self.active_pipe = self.popen(self.startup_script, stdin=DEVNULL, stdout=stdout, + self.active_pipe = self.popen(self.startup_cmd, stdin=DEVNULL, stdout=stdout, stderr=STDOUT, env=env) pipe_out = self.active_pipe.stdout out_fd = pipe_out.fileno() if pipe_out else None @@ -86,7 +86,7 @@ def terminate(self): return active_pipe_returncode -def make_native_host(basedir, startup_script): +def make_native_host(basedir, startup_cmd): """Utility function to create a native-host class that can be passed to mininet""" class _NativeHost(NativeHost): @@ -97,7 +97,7 @@ def __init__(self, *args, **kwargs): assert kwargs['tmpdir'], 'tmpdir required for native host' kwargs['tmpdir'] = os.path.join(kwargs['tmpdir'], host_name) kwargs['basedir'] = basedir - kwargs['startup_script'] = startup_script + kwargs['startup_cmd'] = startup_cmd super(_NativeHost, self).__init__(*args, **kwargs) return _NativeHost diff --git a/daq/test_modules/native_module.py b/daq/test_modules/native_module.py index 892e5a5431..9e9caffb70 100644 --- a/daq/test_modules/native_module.py +++ b/daq/test_modules/native_module.py @@ -15,9 +15,9 @@ class NativeModule(ExternalModule): """Class for running native tests""" # pylint: disable=too-many-arguments - def __init__(self, host, tmpdir, test_name, module_config, basedir, startup_script): + def __init__(self, host, tmpdir, test_name, module_config, basedir, startup_cmd): super().__init__(host, tmpdir, test_name, module_config, basedir=basedir) - self.startup_script = startup_script + self.startup_cmd = startup_cmd def start(self, port, params, callback, finish_hook): """Start the native test""" @@ -40,4 +40,4 @@ def _get_vol_maps(self, params): def _get_module_class(self): LOGGER.debug("%s running native test %s", self, self.test_name) - return make_native_host(self.basedir, self.startup_script) + return make_native_host(self.basedir, self.startup_cmd) diff --git a/subset/fail/fail.daqmodule b/subset/fail/fail.daqmodule index 9d0c04be50..6b7cc50100 100644 --- a/subset/fail/fail.daqmodule +++ b/subset/fail/fail.daqmodule @@ -1,4 +1,4 @@ { "name": "fail", - "startup_script": "/bin/false" + "startup_cmd": "/bin/false" } diff --git a/subset/pass/pass.daqmodule b/subset/pass/pass.daqmodule index f2f2c553a4..488f879e3f 100644 --- a/subset/pass/pass.daqmodule +++ b/subset/pass/pass.daqmodule @@ -1,4 +1,4 @@ { "name": "pass", - "startup_script": "/bin/true" + "startup_cmd": "/bin/true" } diff --git a/subset/pentests/nmap/nmap.daqmodule b/subset/pentests/nmap/nmap.daqmodule index 6e4e5de92f..1d239123ea 100644 --- a/subset/pentests/nmap/nmap.daqmodule +++ b/subset/pentests/nmap/nmap.daqmodule @@ -1,4 +1,4 @@ { "name": "nmap", - "startup_script": "test_nmap" + "startup_cmd": "test_nmap" } diff --git a/subset/ping/ping.daqmodule b/subset/ping/ping.daqmodule index cd2799228b..1b04c7848d 100644 --- a/subset/ping/ping.daqmodule +++ b/subset/ping/ping.daqmodule @@ -1,4 +1,4 @@ { "name": "ping", - "startup_script": "test_ping" + "startup_cmd": "test_ping" } From d6f3d7d22e996b86ad3840ef15d3bfe4e2bfb387 Mon Sep 17 00:00:00 2001 From: henry54809 Date: Tue, 6 Oct 2020 17:54:52 -0700 Subject: [PATCH 159/212] External Gateway (#664) * to work with externally managed DHCP servers. --- cmd/auto | 2 +- cmd/faux | 18 +++++----- config/faucet/faucet_alt-switch.yaml | 2 +- config/system/alt.yaml | 6 +++- daq/external_gateway.py | 34 ++++++++++++++++--- daq/runner.py | 3 +- .../network/scripts/autorestart_dnsmasq | 2 +- testing/test_base.out | 6 ++-- testing/test_base.sh | 12 ++++++- 9 files changed, 63 insertions(+), 22 deletions(-) diff --git a/cmd/auto b/cmd/auto index a86ead4eda..1f31eeb90c 100755 --- a/cmd/auto +++ b/cmd/auto @@ -41,7 +41,7 @@ egrep $regex $CFILE | while read iopt; do key=${BASH_REMATCH[2]} val=${BASH_REMATCH[3]} if [ "$key" = opts ]; then - start_faux $iface $(eval echo $val) + start_faux $iface $val elif [ "$key" = port ]; then autostart bin/bridge_link $switch_setup_ext_br $iface $val fi diff --git a/cmd/faux b/cmd/faux index dd4deb3eec..9180732935 100755 --- a/cmd/faux +++ b/cmd/faux @@ -15,9 +15,17 @@ build= cd $ROOT source etc/config_base.sh +# If the first argument is a number, then it's a port designation. +if [[ "$1" =~ ^[0-9]+$ ]]; then + port_num=$1 + postfix=-$port_num + intf_mac=9a:02:57:1e:8f:0$port_num + shift +fi + # If the argument is -n then create a networking container if [ "$1" == "-n" ]; then - networking=$1 + networking=1 shift fi @@ -46,14 +54,6 @@ if [ "${1#@}" != "$1" ]; then shift fi -# If the first argument is a number, then it's a port designation. -if [[ "$1" =~ ^[0-9]+$ ]]; then - port_num=$1 - postfix=-$port_num - intf_mac=9a:02:57:1e:8f:0$port_num - shift -fi - if [ "$1" == "alt" ]; then image=daqf/faux2 shift diff --git a/config/faucet/faucet_alt-switch.yaml b/config/faucet/faucet_alt-switch.yaml index 059233aa4b..0701657c14 100644 --- a/config/faucet/faucet_alt-switch.yaml +++ b/config/faucet/faucet_alt-switch.yaml @@ -7,7 +7,7 @@ dps: 2: native_vlan: 1001 3: - native_vlan: 1003 + native_vlan: 1001 4: native_vlan: 1004 5: diff --git a/config/system/alt.yaml b/config/system/alt.yaml index ab1f6945f2..76fc92a7fa 100644 --- a/config/system/alt.yaml +++ b/config/system/alt.yaml @@ -15,9 +15,13 @@ switch_setup: # Faux device connection for testing. interfaces: - faux: + faux-1: opts: port: 2 + faux-2: + opts: -n + port: 3 # use vlan trigger run_trigger_type: VLAN +default_timeout_sec: 120 diff --git a/daq/external_gateway.py b/daq/external_gateway.py index 2cc35f00df..333248c605 100644 --- a/daq/external_gateway.py +++ b/daq/external_gateway.py @@ -1,12 +1,38 @@ """Gateway module for device testing""" from __future__ import absolute_import +import os + +from mininet.node import Host + +import dhcp_monitor import logger -from container_gateway import ContainerGateway +from base_gateway import BaseGateway + +LOGGER = logger.get_logger('gateway') + -LOGGER = logger.get_logger('external_gateway') +class ExternalGatewayHost(Host): + """External Gateway Host class""" + def activate(self): + """To match other Host classes""" -class ExternalGateway(ContainerGateway): +class ExternalGateway(BaseGateway): """Gateway collection class for managing testing services""" - # TODO + + def __init__(self, *args): + super().__init__(*args) + self._scan_monitor = None + self.dhcp_monitor = None + + def _initialize(self): + super()._initialize() + log_file = os.path.join(self.tmpdir, 'dhcp_monitor.txt') + self.dhcp_monitor = dhcp_monitor.DhcpMonitor(self.runner, self.runner.network.pri, + self._dhcp_callback, log_file=log_file, + intf_name=self.runner.network.ext_intf) + self.dhcp_monitor.start() + + def _get_host_class(self): + return ExternalGatewayHost diff --git a/daq/runner.py b/daq/runner.py index 9da74b3037..80c9faf455 100644 --- a/daq/runner.py +++ b/daq/runner.py @@ -578,8 +578,7 @@ def _activate_device_group(self, device): LOGGER.info('Gateway for device group %s not found, initializing base %d...', device.group, set_num) if device.dhcp_mode == DHCPMode.EXTERNAL: - # TODO to be removed. - device.dhcp_mode = None + # Under vlan trigger, start a external gateway that doesn't utilize a DHCP server. gateway = external_gateway.ExternalGateway(self, group_name, set_num) else: gateway = container_gateway.ContainerGateway(self, group_name, set_num) diff --git a/docker/include/network/scripts/autorestart_dnsmasq b/docker/include/network/scripts/autorestart_dnsmasq index 43b37ec3ba..c9e997fdf1 100755 --- a/docker/include/network/scripts/autorestart_dnsmasq +++ b/docker/include/network/scripts/autorestart_dnsmasq @@ -28,7 +28,7 @@ while true; do fi checksum=$new_checksum echo Starting dnsmasq at $(date) - dnsmasq --log-facility=/tmp/dnsmasq.log --log-dhcp & + dnsmasq --dhcp-broadcast --log-facility=/tmp/dnsmasq.log --log-dhcp & while [ ! -f $PID_FILE ]; do echo Waiting for $PID_FILE... sleep 2 diff --git a/testing/test_base.out b/testing/test_base.out index abd51b8cda..caa0a23896 100644 --- a/testing/test_base.out +++ b/testing/test_base.out @@ -158,8 +158,10 @@ Switch test with target 192.0.2.138:2 Monolog processing base.switch.ping... switch ping 2 %%%%%%%%%%%%%%%%%%%%%% Alt switch tests -XXX runner INFO 9a:02:57:1e:8f:00 learned on vid 1001 -9a02571e8f00: ['9a02571e8f00:ping:1'] +XXX runner INFO 9a:02:57:1e:8f:01 learned on vid 1001 +Correct IP: 1 +9a02571e8f01: ['9a02571e8f01:ping:1'] +9a02571e8f02: ['9a02571e8f02:acquire:TimeoutError'] %%%%%%%%%%%%%%%%%%%%%% Mud profile tests result open 9a02571e8f01: [] 9a02571e8f02: [] 9a02571e8f03: [] device open 1 1 1 diff --git a/testing/test_base.sh b/testing/test_base.sh index 1abc50fa94..0d925d1393 100755 --- a/testing/test_base.sh +++ b/testing/test_base.sh @@ -55,8 +55,18 @@ echo switch ping $count | tee -a $TEST_RESULTS echo %%%%%%%%%%%%%%%%%%%%%% Alt switch tests | tee -a $TEST_RESULTS cp config/system/alt.yaml local/system.yaml # TODO: Replace this with proper test once VLAN-triggers are added. +function run_cmds { + docker exec daq-networking-2 ifconfig eth0 down + docker exec daq-networking-2 ifconfig faux-eth0 up + docker exec daq-networking-2 ip addr add 10.20.255.254/16 dev faux-eth0 + docker exec daq-networking-2 bash -c "echo dhcp-range=10.20.99.100,10.20.99.254 >> /etc/dnsmasq.conf" +} + +monitor_log "Added link faux-2 as port 3 on alt-switch" run_cmds +monitor_log "Target device 9a02571e8f01 waiting for ip" 'docker exec daq-networking-2 bash -c "./autorestart_dnsmasq &"' timeout 1200s cmd/run -s -fgrep '9a:02:57:1e:8f:00 learned on vid 1001' inst/cmdrun.log | head -1 | redact | tee -a $TEST_RESULTS +fgrep '9a:02:57:1e:8f:01 learned on vid 1001' inst/cmdrun.log | head -1 | redact | tee -a $TEST_RESULTS +echo Correct IP: $(fgrep '10.20.99' inst/run-9a02571e8f01/scans/ip_triggers.txt | wc -l) | tee -a $TEST_RESULTS cat inst/result.log | tee -a $TEST_RESULTS # ping test should fail since there are no dhcp packets captured echo %%%%%%%%%%%%%%%%%%%%%% Mud profile tests | tee -a $TEST_RESULTS rm -f local/system.yaml From aac036afe60798259f103d47b35432f8356cd807 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 8 Oct 2020 23:05:43 -0700 Subject: [PATCH 160/212] Update dependency jsoneditor to v9.1.1 (#654) --- firebase/public/config.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firebase/public/config.html b/firebase/public/config.html index 2d9a8dc601..097ede4b42 100644 --- a/firebase/public/config.html +++ b/firebase/public/config.html @@ -11,8 +11,8 @@ - - + +
      From 849555803f3cebb3e4763279985f02ccb6e37694 Mon Sep 17 00:00:00 2001 From: henry54809 Date: Fri, 9 Oct 2020 19:33:06 -0700 Subject: [PATCH 161/212] set gateway set vlan (#671) --- config/faucet/faucet_alt-switch.yaml | 6 +- config/system/alt.yaml | 7 +- config/system/default.yaml | 2 - daq/network.py | 8 ++ daq/runner.py | 18 +++-- daq/topology.py | 13 ++++ firebase/public/protos.hash | 2 +- firebase/public/protos.html | 68 +++++++++-------- libs/proto/system_config_pb2.py | 108 ++++++++++++++++----------- proto/system_config.proto | 19 +++-- testing/test_base.out | 3 +- testing/test_base.sh | 4 +- 12 files changed, 159 insertions(+), 99 deletions(-) diff --git a/config/faucet/faucet_alt-switch.yaml b/config/faucet/faucet_alt-switch.yaml index 0701657c14..5da1ea4a76 100644 --- a/config/faucet/faucet_alt-switch.yaml +++ b/config/faucet/faucet_alt-switch.yaml @@ -5,15 +5,15 @@ dps: 1: native_vlan: 1002 2: - native_vlan: 1001 + native_vlan: 2000 3: - native_vlan: 1001 + native_vlan: 2000 4: native_vlan: 1004 5: native_vlan: 1005 100: - tagged_vlans: [1001, 1002, 1003, 1004, 1005] + tagged_vlans: [1001, 1002, 1003, 1004, 1005, 2000] vlans: 1001: 1002: diff --git a/config/system/alt.yaml b/config/system/alt.yaml index 76fc92a7fa..678a1ab85a 100644 --- a/config/system/alt.yaml +++ b/config/system/alt.yaml @@ -22,6 +22,9 @@ interfaces: opts: -n port: 3 -# use vlan trigger -run_trigger_type: VLAN default_timeout_sec: 120 + +# use vlan trigger +run_trigger: + vlan_start: 2000 + vlan_end: 2050 diff --git a/config/system/default.yaml b/config/system/default.yaml index f953d83f89..f750b5a71f 100644 --- a/config/system/default.yaml +++ b/config/system/default.yaml @@ -41,8 +41,6 @@ finish_hook: bin/dump_network # topology hook: executed when device topology changes topology_hook: bin/dump_network -run_trigger_type: PORT - # usi url for DAQ to connect to usi_setup: url: localhost:5000 diff --git a/daq/network.py b/daq/network.py index 255a6bd259..06a668f44c 100644 --- a/daq/network.py +++ b/daq/network.py @@ -193,6 +193,14 @@ def direct_port_traffic(self, target_mac, port, target): self.faucitizer.process_faucet_config(self.topology.get_network_topology()) faucetizer.write_behavioral_config(self.faucitizer, self.OUTPUT_FAUCET_FILE) + def direct_vlan_traffic(self, port_set, vlan): + """Modify gateway set's vlan to match triggering vlan""" + LOGGER.info('Directing traffic for port set %s to vlan %s', port_set, vlan) + # TODO: Convert this to use faucitizer to change vlan + self.topology.direct_vlan_traffic(port_set, vlan) + self.faucitizer.process_faucet_config(self.topology.get_network_topology()) + faucetizer.write_behavioral_config(self.faucitizer, self.OUTPUT_FAUCET_FILE) + def _attach_switch_interface(self, switch_intf_name): switch_port = self.topology.switch_port() LOGGER.info('Attaching switch interface %s on port %s', switch_intf_name, switch_port) diff --git a/daq/runner.py b/daq/runner.py index 80c9faf455..d8ced2f1f1 100644 --- a/daq/runner.py +++ b/daq/runner.py @@ -51,6 +51,7 @@ def __init__(self): self.dhcp_ready = False self.dhcp_mode = None self.ip_info = IpInfo() + self.vlan = None self.set_id = None def __repr__(self): @@ -63,13 +64,14 @@ def __init__(self): self._devices = {} self._set_ids = set() - def new_device(self, mac, port_info=None): + def new_device(self, mac, port_info=None, vlan=None): """Adding a new device""" assert mac not in self._devices, "Device with mac: %s is already added." % mac device = Device() device.mac = mac self._devices[mac] = device device.port = port_info if port_info else PortInfo() + device.vlan = vlan port_no = device.port.port_no set_id = port_no if port_no else self._allocate_set_id() assert set_id not in self._set_ids, "Duplicate device set id %d" % set_id @@ -153,7 +155,7 @@ def __init__(self, config): self.faucet_events = None self.single_shot = config.get('single_shot', False) self.fail_mode = config.get('fail_mode', False) - self.run_trigger_type = config.get('run_trigger_type', 'PORT') + self.run_trigger = config.get('run_trigger', {}) self.run_tests = True self.stream_monitor = None self.exception = None @@ -271,10 +273,12 @@ def _handle_faucet_events(self): return (dpid, port, target_mac, vid) = self.faucet_events.as_port_learn(event) if dpid and port and vid: - if self.run_trigger_type == "PORT": + is_vlan = self.run_trigger.get("vlan_start") and self.run_trigger.get("vlan_end") + if is_vlan: + if self.network.is_system_port(dpid, port): + self._handle_device_learn(vid, target_mac) + else: self._handle_port_learn(dpid, port, vid, target_mac) - elif self.run_trigger_type == "VLAN" and self.network.is_system_port(dpid, port): - self._handle_device_learn(vid, target_mac) return (dpid, restart_type) = self.faucet_events.as_config_change(event) if dpid is not None: @@ -339,7 +343,7 @@ def _handle_port_learn(self, dpid, port, vid, target_mac): def _handle_device_learn(self, vid, target_mac): LOGGER.info('%s learned on vid %s', target_mac, vid) if not self._devices.get(target_mac): - device = self._devices.new_device(target_mac) + device = self._devices.new_device(target_mac, vlan=vid) else: device = self._devices.get(target_mac) device.dhcp_mode = DHCPMode.EXTERNAL @@ -504,6 +508,8 @@ def _target_set_trigger(self, device): 'mac': device.mac } self._direct_port_traffic(device.mac, device.port.port_no, target) + else: + self.network.direct_vlan_traffic(gateway.port_set, device.vlan) return True except Exception as e: self.target_set_error(device, e) diff --git a/daq/topology.py b/daq/topology.py index 0e0e725940..9faff2ae3a 100644 --- a/daq/topology.py +++ b/daq/topology.py @@ -11,6 +11,7 @@ LOGGER = logger.get_logger('topology') + class FaucetTopology: """Topology manager specific to FAUCET configs""" @@ -106,6 +107,12 @@ def get_device_intfs(self): device_intfs.append(intf_names[port-1] if named_port else default_name) return device_intfs + def direct_vlan_traffic(self, port_set, vlan): + """Modify gateway set's vlan to match triggering vlan""" + interfaces = self.topology['dps'][self.pri_name]['interfaces'] + for port in self._get_gw_ports(port_set): + interfaces[port]['native_vlan'] = vlan + def direct_port_traffic(self, target_mac, port_no, target): """Direct traffic from a port to specified port set""" if target is None and port_no in self._port_targets: @@ -189,6 +196,12 @@ def _make_sec_trunk_interface(self): return interface def _vlan_tags(self): + vlan_range_config = self.config.get("run_trigger", {}) + test_vlan_start = vlan_range_config.get("vlan_start") + test_vlan_end = vlan_range_config.get("vlan_end") + if test_vlan_start is not None and test_vlan_end is not None: + return [*range(self._VLAN_BASE, self._VLAN_BASE + self.sec_port), + *range(test_vlan_start, test_vlan_end + 1)] return list(range(self._VLAN_BASE, self._VLAN_BASE + self.sec_port)) def _make_default_acl_rules(self): diff --git a/firebase/public/protos.hash b/firebase/public/protos.hash index 370f8918da..69b691d3f2 100644 --- a/firebase/public/protos.hash +++ b/firebase/public/protos.hash @@ -1 +1 @@ -de57653a297ec1c4104f481d770103578cfee2ff proto/system_config.proto +66212fcc5d2f6ebb82cc0b25696a293e387b94cf proto/system_config.proto diff --git a/firebase/public/protos.html b/firebase/public/protos.html index 0a4ef91b4b..5dba0d178e 100644 --- a/firebase/public/protos.html +++ b/firebase/public/protos.html @@ -194,6 +194,10 @@

      Table of Contents

      MInterface +
    • + MRunTrigger +
    • +
    • MSwitchSetup
    • @@ -207,10 +211,6 @@

      Table of Contents

      EDHCPMode -
    • - ERunTriggerType -
    • - @@ -498,8 +498,8 @@

      DaqConfig

      - - + + @@ -618,6 +618,37 @@

      Interface

      +

      RunTrigger

      +

      Information for test vlan ranges.

      + + +
      run_trigger_typeRunTriggerTyperun_triggerRunTrigger

      Configures events that trigger a DAQ run

      + + + + + + + + + + + + + + + + + + + + +
      FieldTypeLabelDescription
      vlan_startint32

      start of vlan range

      vlan_endint32

      end of vlan range

      + + + + +

      SwitchSetup

      System configuraiton of the access switch. This is used by the system

      to setup and configure the switch itself.

      @@ -695,7 +726,7 @@

      SwitchSetup

      ext_br string -

      Name for external OVS bridge in liu of physical switch

      +

      Name for external OVS bridge in lieu of physical switch

      @@ -800,29 +831,6 @@

      DHCPMode

      -

      RunTriggerType

      -

      - - - - - - - - - - - - - - - - - - - -
      NameNumberDescription
      PORT0

      VLAN1

      - diff --git a/libs/proto/system_config_pb2.py b/libs/proto/system_config_pb2.py index a42dad982a..b34b291eb0 100644 --- a/libs/proto/system_config_pb2.py +++ b/libs/proto/system_config_pb2.py @@ -20,32 +20,9 @@ package='', syntax='proto3', serialized_options=None, - serialized_pb=_b('\n\x1d\x64\x61q/proto/system_config.proto\"\xf1\x08\n\tDaqConfig\x12\x18\n\x10site_description\x18\x01 \x01(\t\x12\x18\n\x10monitor_scan_sec\x18\x02 \x01(\x05\x12\x1b\n\x13\x64\x65\x66\x61ult_timeout_sec\x18\x03 \x01(\x05\x12\x12\n\nsettle_sec\x18& \x01(\x05\x12\x11\n\tbase_conf\x18\x04 \x01(\t\x12\x11\n\tsite_path\x18\x05 \x01(\t\x12\x1f\n\x17initial_dhcp_lease_time\x18\x06 \x01(\t\x12\x17\n\x0f\x64hcp_lease_time\x18\x07 \x01(\t\x12\x19\n\x11\x64hcp_response_sec\x18\' \x01(\x05\x12\x1e\n\x16long_dhcp_response_sec\x18\x08 \x01(\x05\x12\"\n\x0cswitch_setup\x18\t \x01(\x0b\x32\x0c.SwitchSetup\x12\x12\n\nhost_tests\x18\x10 \x01(\t\x12\x13\n\x0b\x62uild_tests\x18$ \x01(\x08\x12\x11\n\trun_limit\x18\x11 \x01(\x05\x12\x11\n\tfail_mode\x18\x12 \x01(\x08\x12\x13\n\x0bsingle_shot\x18\" \x01(\x08\x12\x15\n\rresult_linger\x18\x13 \x01(\x08\x12\x0f\n\x07no_test\x18\x14 \x01(\x08\x12\x11\n\tkeep_hold\x18( \x01(\x08\x12\x14\n\x0c\x64\x61q_loglevel\x18\x15 \x01(\t\x12\x18\n\x10mininet_loglevel\x18\x16 \x01(\t\x12\x13\n\x0b\x66inish_hook\x18# \x01(\t\x12\x10\n\x08gcp_cred\x18\x17 \x01(\t\x12\x11\n\tgcp_topic\x18\x18 \x01(\t\x12\x13\n\x0bschema_path\x18\x19 \x01(\t\x12\x11\n\tmud_files\x18\x1a \x01(\t\x12\x14\n\x0c\x64\x65vice_specs\x18\x1b \x01(\t\x12\x13\n\x0btest_config\x18\x1c \x01(\t\x12\x19\n\x11port_debounce_sec\x18\x1d \x01(\x05\x12\x15\n\rtopology_hook\x18\x1e \x01(\t\x12\x17\n\x0f\x64\x65vice_template\x18\x1f \x01(\t\x12\x14\n\x0csite_reports\x18 \x01(\t\x12\x1f\n\x17run_data_retention_days\x18! \x01(\x02\x12.\n\ninterfaces\x18% \x03(\x0b\x32\x1a.DaqConfig.InterfacesEntry\x12/\n\x0b\x66\x61il_module\x18/ \x03(\x0b\x32\x1a.DaqConfig.FailModuleEntry\x12\x1d\n\x15port_flap_timeout_sec\x18\x30 \x01(\x05\x12\x1c\n\tusi_setup\x18\x31 \x01(\x0b\x32\t.USISetup\x12)\n\x10run_trigger_type\x18\x32 \x01(\x0e\x32\x0f.RunTriggerType\x12\x12\n\ndebug_mode\x18\x33 \x01(\x08\x12\x13\n\x0buse_console\x18\x34 \x01(\x08\x1a=\n\x0fInterfacesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x19\n\x05value\x18\x02 \x01(\x0b\x32\n.Interface:\x02\x38\x01\x1a\x31\n\x0f\x46\x61ilModuleEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"0\n\x08USISetup\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x17\n\x0frpc_timeout_sec\x18\x02 \x01(\x05\"\xf4\x01\n\x0bSwitchSetup\x12\x11\n\tctrl_intf\x18\t \x01(\t\x12\x0f\n\x07ip_addr\x18\x0b \x01(\t\x12\x13\n\x0buplink_port\x18\r \x01(\x05\x12\x0f\n\x07lo_port\x18\x0e \x01(\x05\x12\x10\n\x08\x61lt_port\x18\x10 \x01(\x05\x12\x0f\n\x07lo_addr\x18\x12 \x01(\t\x12\x11\n\tmods_addr\x18\x14 \x01(\t\x12\x0f\n\x07of_dpid\x18) \x01(\t\x12\x11\n\tdata_intf\x18* \x01(\t\x12\x0e\n\x06\x65xt_br\x18+ \x01(\t\x12\r\n\x05model\x18, \x01(\t\x12\x10\n\x08username\x18- \x01(\t\x12\x10\n\x08password\x18. \x01(\t\"\'\n\tInterface\x12\x0c\n\x04opts\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05*$\n\x0eRunTriggerType\x12\x08\n\x04PORT\x10\x00\x12\x08\n\x04VLAN\x10\x01*U\n\x08\x44HCPMode\x12\n\n\x06NORMAL\x10\x00\x12\r\n\tSTATIC_IP\x10\x01\x12\x0c\n\x08\x45XTERNAL\x10\x02\x12\x11\n\rLONG_RESPONSE\x10\x03\x12\r\n\tIP_CHANGE\x10\x04\x62\x06proto3') + serialized_pb=_b('\n\x1d\x64\x61q/proto/system_config.proto\"\xe8\x08\n\tDaqConfig\x12\x18\n\x10site_description\x18\x01 \x01(\t\x12\x18\n\x10monitor_scan_sec\x18\x02 \x01(\x05\x12\x1b\n\x13\x64\x65\x66\x61ult_timeout_sec\x18\x03 \x01(\x05\x12\x12\n\nsettle_sec\x18& \x01(\x05\x12\x11\n\tbase_conf\x18\x04 \x01(\t\x12\x11\n\tsite_path\x18\x05 \x01(\t\x12\x1f\n\x17initial_dhcp_lease_time\x18\x06 \x01(\t\x12\x17\n\x0f\x64hcp_lease_time\x18\x07 \x01(\t\x12\x19\n\x11\x64hcp_response_sec\x18\' \x01(\x05\x12\x1e\n\x16long_dhcp_response_sec\x18\x08 \x01(\x05\x12\"\n\x0cswitch_setup\x18\t \x01(\x0b\x32\x0c.SwitchSetup\x12\x12\n\nhost_tests\x18\x10 \x01(\t\x12\x13\n\x0b\x62uild_tests\x18$ \x01(\x08\x12\x11\n\trun_limit\x18\x11 \x01(\x05\x12\x11\n\tfail_mode\x18\x12 \x01(\x08\x12\x13\n\x0bsingle_shot\x18\" \x01(\x08\x12\x15\n\rresult_linger\x18\x13 \x01(\x08\x12\x0f\n\x07no_test\x18\x14 \x01(\x08\x12\x11\n\tkeep_hold\x18( \x01(\x08\x12\x14\n\x0c\x64\x61q_loglevel\x18\x15 \x01(\t\x12\x18\n\x10mininet_loglevel\x18\x16 \x01(\t\x12\x13\n\x0b\x66inish_hook\x18# \x01(\t\x12\x10\n\x08gcp_cred\x18\x17 \x01(\t\x12\x11\n\tgcp_topic\x18\x18 \x01(\t\x12\x13\n\x0bschema_path\x18\x19 \x01(\t\x12\x11\n\tmud_files\x18\x1a \x01(\t\x12\x14\n\x0c\x64\x65vice_specs\x18\x1b \x01(\t\x12\x13\n\x0btest_config\x18\x1c \x01(\t\x12\x19\n\x11port_debounce_sec\x18\x1d \x01(\x05\x12\x15\n\rtopology_hook\x18\x1e \x01(\t\x12\x17\n\x0f\x64\x65vice_template\x18\x1f \x01(\t\x12\x14\n\x0csite_reports\x18 \x01(\t\x12\x1f\n\x17run_data_retention_days\x18! \x01(\x02\x12.\n\ninterfaces\x18% \x03(\x0b\x32\x1a.DaqConfig.InterfacesEntry\x12/\n\x0b\x66\x61il_module\x18/ \x03(\x0b\x32\x1a.DaqConfig.FailModuleEntry\x12\x1d\n\x15port_flap_timeout_sec\x18\x30 \x01(\x05\x12\x1c\n\tusi_setup\x18\x31 \x01(\x0b\x32\t.USISetup\x12 \n\x0brun_trigger\x18\x32 \x01(\x0b\x32\x0b.RunTrigger\x12\x12\n\ndebug_mode\x18\x33 \x01(\x08\x12\x13\n\x0buse_console\x18\x34 \x01(\x08\x1a=\n\x0fInterfacesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x19\n\x05value\x18\x02 \x01(\x0b\x32\n.Interface:\x02\x38\x01\x1a\x31\n\x0f\x46\x61ilModuleEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"0\n\x08USISetup\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x17\n\x0frpc_timeout_sec\x18\x02 \x01(\x05\"\xf4\x01\n\x0bSwitchSetup\x12\x11\n\tctrl_intf\x18\t \x01(\t\x12\x0f\n\x07ip_addr\x18\x0b \x01(\t\x12\x13\n\x0buplink_port\x18\r \x01(\x05\x12\x0f\n\x07lo_port\x18\x0e \x01(\x05\x12\x10\n\x08\x61lt_port\x18\x10 \x01(\x05\x12\x0f\n\x07lo_addr\x18\x12 \x01(\t\x12\x11\n\tmods_addr\x18\x14 \x01(\t\x12\x0f\n\x07of_dpid\x18) \x01(\t\x12\x11\n\tdata_intf\x18* \x01(\t\x12\x0e\n\x06\x65xt_br\x18+ \x01(\t\x12\r\n\x05model\x18, \x01(\t\x12\x10\n\x08username\x18- \x01(\t\x12\x10\n\x08password\x18. \x01(\t\"2\n\nRunTrigger\x12\x12\n\nvlan_start\x18\x01 \x01(\x05\x12\x10\n\x08vlan_end\x18\x02 \x01(\x05\"\'\n\tInterface\x12\x0c\n\x04opts\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05*U\n\x08\x44HCPMode\x12\n\n\x06NORMAL\x10\x00\x12\r\n\tSTATIC_IP\x10\x01\x12\x0c\n\x08\x45XTERNAL\x10\x02\x12\x11\n\rLONG_RESPONSE\x10\x03\x12\r\n\tIP_CHANGE\x10\x04\x62\x06proto3') ) -_RUNTRIGGERTYPE = _descriptor.EnumDescriptor( - name='RunTriggerType', - full_name='RunTriggerType', - filename=None, - file=DESCRIPTOR, - values=[ - _descriptor.EnumValueDescriptor( - name='PORT', index=0, number=0, - serialized_options=None, - type=None), - _descriptor.EnumValueDescriptor( - name='VLAN', index=1, number=1, - serialized_options=None, - type=None), - ], - containing_type=None, - serialized_options=None, - serialized_start=1511, - serialized_end=1547, -) -_sym_db.RegisterEnumDescriptor(_RUNTRIGGERTYPE) - -RunTriggerType = enum_type_wrapper.EnumTypeWrapper(_RUNTRIGGERTYPE) _DHCPMODE = _descriptor.EnumDescriptor( name='DHCPMode', full_name='DHCPMode', @@ -75,14 +52,12 @@ ], containing_type=None, serialized_options=None, - serialized_start=1549, - serialized_end=1634, + serialized_start=1554, + serialized_end=1639, ) _sym_db.RegisterEnumDescriptor(_DHCPMODE) DHCPMode = enum_type_wrapper.EnumTypeWrapper(_DHCPMODE) -PORT = 0 -VLAN = 1 NORMAL = 0 STATIC_IP = 1 EXTERNAL = 2 @@ -124,8 +99,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1059, - serialized_end=1120, + serialized_start=1050, + serialized_end=1111, ) _DAQCONFIG_FAILMODULEENTRY = _descriptor.Descriptor( @@ -161,8 +136,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1122, - serialized_end=1171, + serialized_start=1113, + serialized_end=1162, ) _DAQCONFIG = _descriptor.Descriptor( @@ -432,9 +407,9 @@ is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( - name='run_trigger_type', full_name='DaqConfig.run_trigger_type', index=37, - number=50, type=14, cpp_type=8, label=1, - has_default_value=False, default_value=0, + name='run_trigger', full_name='DaqConfig.run_trigger', index=37, + number=50, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -465,7 +440,7 @@ oneofs=[ ], serialized_start=34, - serialized_end=1171, + serialized_end=1162, ) @@ -502,8 +477,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1173, - serialized_end=1221, + serialized_start=1164, + serialized_end=1212, ) @@ -617,8 +592,46 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1224, - serialized_end=1468, + serialized_start=1215, + serialized_end=1459, +) + + +_RUNTRIGGER = _descriptor.Descriptor( + name='RunTrigger', + full_name='RunTrigger', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='vlan_start', full_name='RunTrigger.vlan_start', index=0, + number=1, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='vlan_end', full_name='RunTrigger.vlan_end', index=1, + number=2, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1461, + serialized_end=1511, ) @@ -655,8 +668,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1470, - serialized_end=1509, + serialized_start=1513, + serialized_end=1552, ) _DAQCONFIG_INTERFACESENTRY.fields_by_name['value'].message_type = _INTERFACE @@ -666,12 +679,12 @@ _DAQCONFIG.fields_by_name['interfaces'].message_type = _DAQCONFIG_INTERFACESENTRY _DAQCONFIG.fields_by_name['fail_module'].message_type = _DAQCONFIG_FAILMODULEENTRY _DAQCONFIG.fields_by_name['usi_setup'].message_type = _USISETUP -_DAQCONFIG.fields_by_name['run_trigger_type'].enum_type = _RUNTRIGGERTYPE +_DAQCONFIG.fields_by_name['run_trigger'].message_type = _RUNTRIGGER DESCRIPTOR.message_types_by_name['DaqConfig'] = _DAQCONFIG DESCRIPTOR.message_types_by_name['USISetup'] = _USISETUP DESCRIPTOR.message_types_by_name['SwitchSetup'] = _SWITCHSETUP +DESCRIPTOR.message_types_by_name['RunTrigger'] = _RUNTRIGGER DESCRIPTOR.message_types_by_name['Interface'] = _INTERFACE -DESCRIPTOR.enum_types_by_name['RunTriggerType'] = _RUNTRIGGERTYPE DESCRIPTOR.enum_types_by_name['DHCPMode'] = _DHCPMODE _sym_db.RegisterFileDescriptor(DESCRIPTOR) @@ -712,6 +725,13 @@ )) _sym_db.RegisterMessage(SwitchSetup) +RunTrigger = _reflection.GeneratedProtocolMessageType('RunTrigger', (_message.Message,), dict( + DESCRIPTOR = _RUNTRIGGER, + __module__ = 'daq.proto.system_config_pb2' + # @@protoc_insertion_point(class_scope:RunTrigger) + )) +_sym_db.RegisterMessage(RunTrigger) + Interface = _reflection.GeneratedProtocolMessageType('Interface', (_message.Message,), dict( DESCRIPTOR = _INTERFACE, __module__ = 'daq.proto.system_config_pb2' diff --git a/proto/system_config.proto b/proto/system_config.proto index 9a37076533..4fe67b5f65 100644 --- a/proto/system_config.proto +++ b/proto/system_config.proto @@ -119,7 +119,7 @@ message DaqConfig { USISetup usi_setup = 49; // Configures events that trigger a DAQ run - RunTriggerType run_trigger_type = 50; + RunTrigger run_trigger = 50; // verbose output bool debug_mode = 51; @@ -128,11 +128,6 @@ message DaqConfig { bool use_console = 52; } -enum RunTriggerType { - PORT = 0; - VLAN = 1; -} - enum DHCPMode { NORMAL = 0; STATIC_IP = 1; @@ -181,7 +176,7 @@ message SwitchSetup { // Interface name for external switch data plane string data_intf = 42; - // Name for external OVS bridge in liu of physical switch + // Name for external OVS bridge in lieu of physical switch string ext_br = 43; // Switch model @@ -194,6 +189,16 @@ message SwitchSetup { string password = 46; } +/* + * Information for test vlan ranges. + */ +message RunTrigger { + // start of vlan range + int32 vlan_start = 1; + + // end of vlan range + int32 vlan_end = 2; +} /* * Information for faux containers. diff --git a/testing/test_base.out b/testing/test_base.out index caa0a23896..2dc7e06c5e 100644 --- a/testing/test_base.out +++ b/testing/test_base.out @@ -158,10 +158,9 @@ Switch test with target 192.0.2.138:2 Monolog processing base.switch.ping... switch ping 2 %%%%%%%%%%%%%%%%%%%%%% Alt switch tests -XXX runner INFO 9a:02:57:1e:8f:01 learned on vid 1001 +XXX runner INFO 9a:02:57:1e:8f:01 learned on vid 2000 Correct IP: 1 9a02571e8f01: ['9a02571e8f01:ping:1'] -9a02571e8f02: ['9a02571e8f02:acquire:TimeoutError'] %%%%%%%%%%%%%%%%%%%%%% Mud profile tests result open 9a02571e8f01: [] 9a02571e8f02: [] 9a02571e8f03: [] device open 1 1 1 diff --git a/testing/test_base.sh b/testing/test_base.sh index 0d925d1393..a8147a9c55 100755 --- a/testing/test_base.sh +++ b/testing/test_base.sh @@ -65,9 +65,9 @@ function run_cmds { monitor_log "Added link faux-2 as port 3 on alt-switch" run_cmds monitor_log "Target device 9a02571e8f01 waiting for ip" 'docker exec daq-networking-2 bash -c "./autorestart_dnsmasq &"' timeout 1200s cmd/run -s -fgrep '9a:02:57:1e:8f:01 learned on vid 1001' inst/cmdrun.log | head -1 | redact | tee -a $TEST_RESULTS +fgrep '9a:02:57:1e:8f:01 learned on vid 2000' inst/cmdrun.log | head -1 | redact | tee -a $TEST_RESULTS echo Correct IP: $(fgrep '10.20.99' inst/run-9a02571e8f01/scans/ip_triggers.txt | wc -l) | tee -a $TEST_RESULTS -cat inst/result.log | tee -a $TEST_RESULTS # ping test should fail since there are no dhcp packets captured +cat inst/result.log | grep 9a02571e8f01 | tee -a $TEST_RESULTS # ping test should fail since there are no dhcp packets captured echo %%%%%%%%%%%%%%%%%%%%%% Mud profile tests | tee -a $TEST_RESULTS rm -f local/system.yaml cp config/system/muddy.conf local/system.conf From 55075a31d7100a311b7a7d545d5041ff25f90244 Mon Sep 17 00:00:00 2001 From: frgitdaq <62390501+frgitdaq@users.noreply.github.com> Date: Mon, 12 Oct 2020 08:03:11 +0100 Subject: [PATCH 162/212] Update NTP support test fix #622 (#595) * Use both startup.pcap and monitor.pcap in NTP support test --- subset/network/README.md | 7 +++---- subset/network/ntp_tests.py | 12 ++++++------ subset/network/test_network | 5 ++--- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/subset/network/README.md b/subset/network/README.md index 677a519931..16989e34b2 100644 --- a/subset/network/README.md +++ b/subset/network/README.md @@ -25,7 +25,7 @@ The NTP tests inspect the client NTP version and the device's ability to update ### Note for test developers The functional test code is included in the `ntp_tests.py` file. -The test reads packets from startup.pcap and monitor.pcap. +The test reads packets from monitor.pcap. If the python code needs debugging, the pip module `scapy` is required (`pip install scapy`). @@ -36,11 +36,10 @@ If the python code needs debugging, the pip module `scapy` is required (`pip ins | connection.network.ntp_update | Does the device demonstrate updating its clock using NTP? | Device clock is synchronized | Device clock is not synchronized | Not enough NTP packets are received | #### NTP Support #### -The version of NTP used by the client is extracted from the fist client (outbound) NTP packets discovered in startup.pcap. +The version of NTP used by the client is extracted from the first client (outbound) NTP packets discovered in monitor.pcap. #### NTP Update #### The following criteria are used to determine whether a DUT has synced its clock with the NTP server provided by DAQ: - - A minimum of 2 NTP packets are present in startup.pcap and monitor.pcap (one potential poll). - A minimum of 2 NTP packets have been exchanged between the DUT and the DAQ-provided NTP server. - A valid NTP poll is present. Consisting of a client-server exchange. - The calculated offset is less than 0.128 seconds and the final poll does not have a leap indicator of 3 (unsynchronized). @@ -73,4 +72,4 @@ Check Device uses the DNS server from DHCP and resolves hostnames ### Conditions for connection.dns.hostname_connect - pass -> if the device uses the DNS server from DHCP, and resolves a hostname - fail -> device uses a DNS serveer other than the server fron DHCP - - skip -> device did not send any DNS requests \ No newline at end of file + - skip -> device did not send any DNS requests diff --git a/subset/network/ntp_tests.py b/subset/network/ntp_tests.py index f001734ff0..c4ac22aeb4 100644 --- a/subset/network/ntp_tests.py +++ b/subset/network/ntp_tests.py @@ -6,8 +6,7 @@ arguments = sys.argv test_request = str(arguments[1]) -startup_pcap_file = str(arguments[2]) -monitor_pcap_file = str(arguments[3]) +pcap_file = str(arguments[2]) report_filename = 'ntp_tests.txt' ignore = '%%' @@ -63,9 +62,10 @@ def ntp_payload(packet): def test_ntp_support(): - capture = rdpcap(startup_pcap_file) - if len(capture) > 0: - version = ntp_client_version(capture) + capture = rdpcap(pcap_file) + packets = ntp_packets(capture) + if len(packets) > 0: + version = ntp_client_version(packets) if version is None: add_summary("No NTP packets received.") return 'skip' @@ -81,7 +81,7 @@ def test_ntp_support(): def test_ntp_update(): - capture = rdpcap(monitor_pcap_file) + capture = rdpcap(pcap_file) packets = ntp_packets(capture) if len(packets) < 2: add_summary("Not enough NTP packets received.") diff --git a/subset/network/test_network b/subset/network/test_network index 15b642f456..0bc5ee332b 100755 --- a/subset/network/test_network +++ b/subset/network/test_network @@ -2,7 +2,6 @@ REPORT=/tmp/report.txt -STARTUP=/scans/startup.pcap MONITOR=/scans/monitor.pcap # General Network Tests @@ -12,8 +11,8 @@ python network_tests.py communication.type.broadcast $MONITOR $TARGET_IP cat network_tests.txt >> $REPORT # NTP Tests -python ntp_tests.py connection.network.ntp_support $STARTUP $MONITOR -python ntp_tests.py connection.network.ntp_update $STARTUP $MONITOR +python ntp_tests.py connection.network.ntp_support $MONITOR +python ntp_tests.py connection.network.ntp_update $MONITOR cat ntp_tests.txt >> $REPORT From f1ea75178360ae5fb2106b10d67ce3a902786953 Mon Sep 17 00:00:00 2001 From: frgitdaq <62390501+frgitdaq@users.noreply.github.com> Date: Tue, 13 Oct 2020 16:03:13 +0100 Subject: [PATCH 163/212] IP Change (11) (#658) * DHCP disconnect test --- daq/test_modules/ipaddr_module.py | 3 ++- subset/ipaddr/README.md | 10 +++++++++ subset/ipaddr/dhcp_tests.py | 34 ++++++++++++++++++++++++++++++- subset/ipaddr/test_dhcp | 1 + testing/test_dhcp.out | 3 ++- testing/test_dhcp.sh | 17 ++++++++++------ 6 files changed, 59 insertions(+), 9 deletions(-) diff --git a/daq/test_modules/ipaddr_module.py b/daq/test_modules/ipaddr_module.py index 7889f3c8d5..3ad7774eb5 100644 --- a/daq/test_modules/ipaddr_module.py +++ b/daq/test_modules/ipaddr_module.py @@ -80,7 +80,7 @@ def _next_test(self): def _dhcp_port_toggle_test(self): self._set_timeout() if not self.host.connect_port(False): - self._logger('disconnect port not enabled') + self._logger.error('disconnect port not enabled') return time.sleep(self.host.config.get("port_debounce_sec", 0) + 1) self.host.connect_port(True) @@ -126,6 +126,7 @@ def terminate(self): def ip_listener(self, target_ip): """Respond to a ip notification event""" self._logger.info('ip notification %s' % target_ip) + self.host.runner.ping_test(self.host.gateway.host, self.host.target_ip) if self._ip_callback: self._ip_callback() diff --git a/subset/ipaddr/README.md b/subset/ipaddr/README.md index a3dee54b7f..030076b7ae 100644 --- a/subset/ipaddr/README.md +++ b/subset/ipaddr/README.md @@ -12,3 +12,13 @@ This is because the functional code included in ipaddr communicates with the ope #### Result Cases: - PASS: A DHCP request has been received by the device after the port has been disconnected and connected. - FAIL: No DHCP request was received (this will also be the case if the target is using a static IP). +### connection.dhcp.private_address +- Device supports all private address ranges. +#### Result Cases: +- PASS: The device accepts all private address ranges specified. +- FAIL: The device does not accept all private address ranges specified. +### connection.dhcp.ip_change +- Device communicates after IP change. +#### Result Cases: +- PASS: A ping reply is found after the IP address has been changed. +- FAIL: No ping reply is found after the IP address has been changed. diff --git a/subset/ipaddr/dhcp_tests.py b/subset/ipaddr/dhcp_tests.py index 4d357690f1..e3cfe4b450 100644 --- a/subset/ipaddr/dhcp_tests.py +++ b/subset/ipaddr/dhcp_tests.py @@ -1,7 +1,7 @@ from __future__ import absolute_import import sys import json -from scapy.all import rdpcap, DHCP +from scapy.all import rdpcap, DHCP, ICMP, IP TEST_REQUEST = str(sys.argv[1]) DHCP_REQUEST = 3 @@ -13,11 +13,14 @@ def main(): ipaddr_log = '/tmp/activate.log' module_config_file = '/config/device/module_config.json' dhcp_ranges = [] + scan_file = '/scans/test_ipaddr.pcap' report_filename = 'report.txt' dash_break_line = '--------------------\n' description_dhcp_short = 'Reconnect device and check for DHCP request.' + description_ip_change = 'Device communicates after IP change.' description_private_address = 'Device supports all private address ranges.' running_port_toggle = 'Running dhcp port_toggle test' + running_ip_change = 'Running ip change test' ip_notification = 'ip notification' result = None summary = None @@ -79,6 +82,32 @@ def _test_dhcp_short(): fd.close() return 'fail', 'No DHCP request received.' + def _test_ip_change(): + + fd = open(ipaddr_log, 'r') + run_ip_change = False + ip_change_ip = None + for line in fd: + if run_ip_change: + if ip_notification in line: + ip_change_ip = line.split(ip_notification + ' ')[1].rstrip() + break + if running_ip_change in line: + run_ip_change = True + fd.close() + + if ip_change_ip is None: + return 'skip', 'IP change test did not run.' + + capture = rdpcap(scan_file) + pingFound = False + for packet in capture: + if ICMP in packet and packet[IP].src == ip_change_ip: + pingFound = True + if pingFound: + return 'pass', 'Ping response received after IP change.' + return 'fail', 'No ping response received after IP change.' + def _test_private_address(): if len(dhcp_ranges) == 0: return 'skip', 'No private address ranges were specified.' @@ -96,6 +125,9 @@ def _test_private_address(): if TEST_REQUEST == 'connection.network.dhcp_short': result, summary = _test_dhcp_short() _write_report("{d}\n{b}".format(b=dash_break_line, d=description_dhcp_short)) + elif TEST_REQUEST == 'connection.dhcp.ip_change': + result, summary = _test_ip_change() + _write_report("{d}\n{b}".format(b=dash_break_line, d=description_ip_change)) elif TEST_REQUEST == 'connection.dhcp.private_address': result, summary = _test_private_address() _write_report("{d}\n{b}".format(b=dash_break_line, d=description_private_address)) diff --git a/subset/ipaddr/test_dhcp b/subset/ipaddr/test_dhcp index c8a975f879..b5728daf13 100755 --- a/subset/ipaddr/test_dhcp +++ b/subset/ipaddr/test_dhcp @@ -4,5 +4,6 @@ REPORT=/tmp/report.txt python dhcp_tests.py connection.network.dhcp_short python dhcp_tests.py connection.dhcp.private_address +python dhcp_tests.py connection.dhcp.ip_change cat report.txt >> $REPORT diff --git a/testing/test_dhcp.out b/testing/test_dhcp.out index c9ab0bfb43..9f1e138906 100644 --- a/testing/test_dhcp.out +++ b/testing/test_dhcp.out @@ -13,6 +13,7 @@ Device 4 ip triggers: 1 Device 4 subnet 1 ip: 1 subnet 2 ip: 1 subnet 3 ip: 2 ip_changed: 1 Device 5 ip triggers: 1 Device 5 num of ips: 2 -DHCP timeouts: 1 +Device 5 ip change: 1 Device 6 DHCP timeouts: 1 +Device 6 ip change: 0 Done with tests diff --git a/testing/test_dhcp.sh b/testing/test_dhcp.sh index b3796c53de..d6a28edd70 100755 --- a/testing/test_dhcp.sh +++ b/testing/test_dhcp.sh @@ -92,17 +92,25 @@ cmd/run -b -s settle_sec=0 dhcp_lease_time=120s cat inst/result.log | sort | tee -a $TEST_RESULTS -for iface in $(seq 1 5); do +for iface in $(seq 1 6); do intf_mac=9a:02:57:1e:8f:0$iface ip_file=inst/run-9a02571e8f0$iface/scans/ip_triggers.txt + report_file=inst/run-9a02571e8f0$iface/nodes/ipaddr0$iface/tmp/report.txt cat $ip_file ip_triggers=$(fgrep done $ip_file | wc -l) long_triggers=$(fgrep long $ip_file | wc -l) num_ips=$(cat $ip_file | cut -d ' ' -f 1 | sort | uniq | wc -l) + ip_change=$(cat $report_file | fgrep 'pass connection.dhcp.ip_change' | wc -l) echo Found $ip_triggers ip triggers and $long_triggers long ip responses. - if [ $iface == 5 ]; then + + if [ $iface == 6 ]; then + device_dhcp_timeouts=$(cat inst/cmdrun.log | fgrep 'DHCP times out after 120s lease time' | fgrep "ipaddr_ipaddr0$iface" | wc -l) + echo "Device $iface DHCP timeouts: $device_dhcp_timeouts" | tee -a $TEST_RESULTS + echo "Device $iface ip change: $((ip_change))" | tee -a $TEST_RESULTS + elif [ $iface == 5 ]; then echo "Device $iface ip triggers: $(((ip_triggers + long_triggers) >= 3))" | tee -a $TEST_RESULTS echo "Device $iface num of ips: $num_ips" | tee -a $TEST_RESULTS + echo "Device $iface ip change: $((ip_change))" | tee -a $TEST_RESULTS elif [ $iface == 4 ]; then echo "Device $iface ip triggers: $(((ip_triggers + long_triggers) >= 4))" | tee -a $TEST_RESULTS subnet_ip=$(fgrep "ip notification 192.168" inst/run-*/nodes/ipaddr*/tmp/activate.log | wc -l) @@ -115,10 +123,7 @@ for iface in $(seq 1 5); do else echo "Device $iface ip triggers: $((ip_triggers > 0)) $((long_triggers > 0))" | tee -a $TEST_RESULTS fi + done -dhcp_timeouts=$(cat inst/cmdrun.log | fgrep 'DHCP times out after 120s lease time' | wc -l) -device_6_dhcp_timeouts=$(cat inst/cmdrun.log | fgrep 'DHCP times out after 120s lease time' | fgrep 'ipaddr_ipaddr06' | wc -l) -echo "DHCP timeouts: $dhcp_timeouts" | tee -a $TEST_RESULTS -echo "Device 6 DHCP timeouts: $device_6_dhcp_timeouts" | tee -a $TEST_RESULTS echo Done with tests | tee -a $TEST_RESULTS From a6fb56907024b72220641b422d08eedb5e2c5a6c Mon Sep 17 00:00:00 2001 From: Noureddine Date: Tue, 13 Oct 2020 17:22:57 +0100 Subject: [PATCH 164/212] Add SSH Reporting, SSH Bug Fixes (#670) * add further log and reporting info to the ssh test --- subset/security/test_ssh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/subset/security/test_ssh b/subset/security/test_ssh index e1af63282c..28e99e8ccf 100755 --- a/subset/security/test_ssh +++ b/subset/security/test_ssh @@ -11,7 +11,7 @@ TEST_DESCRIPTION="Check that device only support SSHv2" REPORT=/tmp/report.txt LOG=/tmp/nmap_log.txt -nmap -sV -sC $TARGET_IP > $LOG +nmap -sV -sC --host-timeout=4m --open -p- $TARGET_IP 2>&1 | tee $LOG nmap_log=$(cat $LOG ) @@ -19,7 +19,7 @@ sshv1=$(grep 'sshv1: Server supports SSHv1' $LOG) if [[ -z "${sshv1}" ]]; then #No SSHv1, but is there an SSHv2 server running ? - sshv2=$(grep -P '^\d+\/tcp\s+open ssh.*protocol 2.0\)$' $LOG) + sshv2=$(grep -P '^\d+\/tcp\s+open\s+ssh.*protocol 2.0\)$' $LOG) if [[ -z "${sshv2}" ]]; then test_outcome="skip" @@ -39,6 +39,6 @@ result_and_summary="RESULT ${test_outcome} ${TEST_NAME} ${test_summary}" write_out_result $REPORT \ "$TEST_NAME" \ "$TEST_DESCRIPTION" \ - "$sshv2" \ + "$nmap_log" \ "$result_and_summary" - \ No newline at end of file + From 8b41fadd48fd39bae87295ba4d7810f2ced91e14 Mon Sep 17 00:00:00 2001 From: henry54809 Date: Tue, 13 Oct 2020 10:33:02 -0700 Subject: [PATCH 165/212] Fix Cisco switch power response (#679) Cisco switch power response may be merged into 1 line. --- usi/src/main/java/daq/usi/UsiImpl.java | 1 - .../main/java/daq/usi/cisco/Cisco9300.java | 23 +++++-- usi/src/test/java/daq/usi/Cisco9300Test.java | 66 +++++++++++++++++++ .../test/resources/cisco_power_response.txt | 35 ++++++++++ .../test/resources/cisco_power_response2.txt | 34 ++++++++++ .../test/resources/cisco_power_response3.txt | 32 +++++++++ 6 files changed, 186 insertions(+), 5 deletions(-) create mode 100644 usi/src/test/resources/cisco_power_response.txt create mode 100644 usi/src/test/resources/cisco_power_response2.txt create mode 100644 usi/src/test/resources/cisco_power_response3.txt diff --git a/usi/src/main/java/daq/usi/UsiImpl.java b/usi/src/main/java/daq/usi/UsiImpl.java index a8dd1e87db..ba3c1145a4 100644 --- a/usi/src/main/java/daq/usi/UsiImpl.java +++ b/usi/src/main/java/daq/usi/UsiImpl.java @@ -68,7 +68,6 @@ public void getPower(SwitchInfo request, StreamObserver responseO if (debug) { System.out.println(data); } - System.out.println("Received request in getPower"); responseObserver.onNext(data); responseObserver.onCompleted(); }); diff --git a/usi/src/main/java/daq/usi/cisco/Cisco9300.java b/usi/src/main/java/daq/usi/cisco/Cisco9300.java index f37e475bd9..1dae36be7f 100644 --- a/usi/src/main/java/daq/usi/cisco/Cisco9300.java +++ b/usi/src/main/java/daq/usi/cisco/Cisco9300.java @@ -14,6 +14,7 @@ import java.util.LinkedList; import java.util.Map; import java.util.Queue; +import java.util.Set; import java.util.stream.Collectors; @@ -29,6 +30,7 @@ public class Cisco9300 extends BaseSwitchController { "Measured at the port", "power", "Device Type", "device", "IEEE Class", "dev_class", + "Device Detected", "_", "Power available to the device", "max"); private static final Map poeStatusMap = Map.of("on", POEStatus.State.ON, "off", POEStatus.State.OFF, "fault", POEStatus.State.FAULT, @@ -301,13 +303,26 @@ private Map processInterfaceStatus(String response) { private Map processPowerStatusInline(String response) { Map powerMap = new HashMap<>(); Arrays.stream(response.split("\n")) + .filter(s -> s.length() > 0) .forEach( line -> { String[] lineParts = line.trim().split(":"); - if (lineParts.length > 1) { - String powerMapKey = powerInlineMap.getOrDefault(lineParts[0], null); - if (powerMapKey != null) { - powerMap.put(powerMapKey, lineParts[1].trim()); + Set keys = powerInlineMap.keySet(); + String pendingKey = null; + for (int i = 0; i < lineParts.length; i++) { + String part = lineParts[i]; + for (String key : keys) { + if (!part.contains(key)) { + continue; + } + if (i < lineParts.length - 1) { + powerMap.put(powerInlineMap.get(key), lineParts[i + 1].trim()); + } + if (pendingKey != null) { + powerMap.put(powerInlineMap.get(pendingKey), part.replace(key, "").trim()); + } + pendingKey = key; + break; } } }); diff --git a/usi/src/test/java/daq/usi/Cisco9300Test.java b/usi/src/test/java/daq/usi/Cisco9300Test.java index 333e9658c6..7c14ec84d9 100644 --- a/usi/src/test/java/daq/usi/Cisco9300Test.java +++ b/usi/src/test/java/daq/usi/Cisco9300Test.java @@ -9,6 +9,12 @@ import grpc.POEStatus; import grpc.POESupport; import grpc.PowerResponse; +import java.io.FileReader; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -49,6 +55,66 @@ public void receiveData(PowerResponse data) throws Exception { at.receiveData(""); } + @Test + void testSamplePowerResponse1() throws Exception { + URL outputFile = Cisco9300Test.class.getClassLoader() + .getResource("cisco_power_response.txt"); + String output = new String(Files.readAllBytes(Paths.get(outputFile.toURI())), + StandardCharsets.UTF_8); + fakeLogin(); + at.getPower(1, new ResponseHandler() { + @Override + public void receiveData(PowerResponse data) throws Exception { + assertEquals(data.getPoeSupport(), POESupport.State.ENABLED); + assertEquals(data.getPoeNegotiation(), POENegotiation.State.ENABLED); + assertEquals(data.getPoeStatus(), POEStatus.State.OFF); + assertEquals(data.getCurrentPowerConsumption(), 0); + assertEquals(data.getMaxPowerConsumption(), 0); + } + }); + at.receiveData(output); + } + + @Test + void testSamplePowerResponse2() throws Exception { + URL outputFile = Cisco9300Test.class.getClassLoader() + .getResource("cisco_power_response2.txt"); + String output = new String(Files.readAllBytes(Paths.get(outputFile.toURI())), + StandardCharsets.UTF_8); + fakeLogin(); + at.getPower(1, new ResponseHandler() { + @Override + public void receiveData(PowerResponse data) throws Exception { + assertEquals(data.getPoeSupport(), POESupport.State.ENABLED); + assertEquals(data.getPoeNegotiation(), POENegotiation.State.ENABLED); + assertEquals(data.getPoeStatus(), POEStatus.State.ON); + assertEquals("" + data.getCurrentPowerConsumption(), "5.4"); + assertEquals("" + data.getMaxPowerConsumption(), "30.0"); + } + }); + at.receiveData(output); + } + + @Test + void testSamplePowerResponse3() throws Exception { + URL outputFile = Cisco9300Test.class.getClassLoader() + .getResource("cisco_power_response3.txt"); + String output = new String(Files.readAllBytes(Paths.get(outputFile.toURI())), + StandardCharsets.UTF_8); + fakeLogin(); + at.getPower(1, new ResponseHandler() { + @Override + public void receiveData(PowerResponse data) throws Exception { + assertEquals(data.getPoeSupport(), POESupport.State.ENABLED); + assertEquals(data.getPoeNegotiation(), POENegotiation.State.ENABLED); + assertEquals(data.getPoeStatus(), POEStatus.State.ON); + assertEquals("" + data.getCurrentPowerConsumption(), "5.4"); + assertEquals("" + data.getMaxPowerConsumption(), "30.0"); + } + }); + at.receiveData(output); + } + @Test void testSampleInterfaceResponse() throws Exception { final String output = "show interface gigabitethernet1/0/2 status\n\n\n" diff --git a/usi/src/test/resources/cisco_power_response.txt b/usi/src/test/resources/cisco_power_response.txt new file mode 100644 index 0000000000..3a92e26d26 --- /dev/null +++ b/usi/src/test/resources/cisco_power_response.txt @@ -0,0 +1,35 @@ + Interface: Gi1/0/3 + Inline Power Mode: auto + Operational status: off + Device Detected: no + Device Type: n/a + IEEE Class: n/a + Discovery mechanism used/configured: Ieee and Cisco + Police: off + Power Allocated + Admin Value: 30.0 + Power drawn from the source: 0.0 + Power available to the device: 0.0 + + Actual consumption + Measured at the port: 0.0 + Maximum Power drawn by the device since powered on: 0.0 + + Absent Counter: 0 + Over Current Counter: 0 + Short Current Counter: 0 + Invalid Signature Counter: 0 + Power Denied Counter: 0 + Power Negotiation Used: None + LLDP Power Negotiation --Sent to PD-- --Rcvd from PD-- + + Power Type: - - Power Source: - - + Power Priority: - - + + Requested Power(W): - - + + Allocated Power(W): - - +Four-Pair PoE Supported: No +Spare Pair Power Enabled: No +Four-Pair PD Architecture: N/A +arup-daq-lab# diff --git a/usi/src/test/resources/cisco_power_response2.txt b/usi/src/test/resources/cisco_power_response2.txt new file mode 100644 index 0000000000..fe97c72f9a --- /dev/null +++ b/usi/src/test/resources/cisco_power_response2.txt @@ -0,0 +1,34 @@ + Interface: Gi1/0/1 + + Inline Power Mode: auto Operational status: on + Device Detected: yes + Device Type: Ieee PD + IEEE Class: 4 + Discovery mechanism used/configured: Ieee and Cisco + Police: off + Power Allocated + Admin Value: 30.0 + Power drawn from the source: 30.0 + Power available to the device: 30.0 + + Actual consumption + Measured at the port: 5.4 + Maximum Power drawn by the device since powered on: 8.5 + + Absent Counter: 0 + Over Current Counter: 0 + Short Current Counter: 0 + Invalid Signature Counter: 0 + Power Denied Counter: 0 + Power Negotiation Used: None + LLDP Power Negotiation --Sent to PD-- --Rcvd from PD-- + Power Type: - - + Power Source: - - + Power Priority: - - + Requested Power(W): - - + Allocated Power(W): - - +Four-Pair PoE Supported: No +Spare Pair Power Enabled: No +Four-Pair PD Architecture: N/A +arup-daq-lab# + diff --git a/usi/src/test/resources/cisco_power_response3.txt b/usi/src/test/resources/cisco_power_response3.txt new file mode 100644 index 0000000000..c2f765268d --- /dev/null +++ b/usi/src/test/resources/cisco_power_response3.txt @@ -0,0 +1,32 @@ + Interface: Gi1/0/1 + + Inline Power Mode: auto Operational status: on Device Detected: yes + Device Type: Ieee PD + IEEE Class: 4 + Discovery mechanism used/configured: Ieee and Cisco + Police: off + Power Allocated + Admin Value: 30.0 + Power drawn from the source: 30.0 + Power available to the device: 30.0 + + Actual consumption Measured at the port: 5.4 + Maximum Power drawn by the device since powered on: 8.5 + + Absent Counter: 0 + Over Current Counter: 0 + Short Current Counter: 0 + Invalid Signature Counter: 0 + Power Denied Counter: 0 + Power Negotiation Used: None + LLDP Power Negotiation --Sent to PD-- --Rcvd from PD-- + Power Type: - - + Power Source: - - + Power Priority: - - + Requested Power(W): - - + Allocated Power(W): - - +Four-Pair PoE Supported: No +Spare Pair Power Enabled: No +Four-Pair PD Architecture: N/A +arup-daq-lab# + From 86fa5803d19228ffa8728c9a33602cbb7e64489f Mon Sep 17 00:00:00 2001 From: Francesco Anselmo Date: Tue, 13 Oct 2020 19:05:50 +0100 Subject: [PATCH 166/212] Ip addr flush (#672) --- bin/physical_sec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/physical_sec b/bin/physical_sec index 939d6c4d5c..9028168de1 100755 --- a/bin/physical_sec +++ b/bin/physical_sec @@ -116,7 +116,7 @@ if [ -z "$ext_ctrl" ]; then else echo Bridging $ext_ctrl to $ctrl_bridge sudo ovs-vsctl add-port $ctrl_bridge $ext_ctrl - sudo ip addr flush dev $ext_ctrl + sudo ip -l 200 addr flush dev $ext_ctrl fi echo Warmup ping for $ext_addr From 284b1b13f52fdc242729bf54c58d6fc0ea8c6b03 Mon Sep 17 00:00:00 2001 From: Puneet Date: Tue, 13 Oct 2020 17:57:06 -0700 Subject: [PATCH 167/212] 1.9.9 release --- docs/changelog.md | 10 +++++++- etc/docker_images.txt | 56 +++++++++++++++++++++---------------------- etc/docker_images.ver | 2 +- 3 files changed, 38 insertions(+), 30 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index fcd6b8c867..d1c48e7b72 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,5 +1,13 @@ # Changelog -* 1.9.8 +* 1.9.9 + * IP addr flush (#672) + * Fix Cisco switch power response (#679) + * Add SSH Reporting, SSH Bug Fixes (#670) + * IP Change (11) (#658) + * Update NTP support test fix #622 (#595) + * set gateway set vlan (#671) + * Update dependency jsoneditor to v9.1.1 (#654) + * External Gateway (#664) * New "new ip" assignment, extend rpc_timeout_sec and ping counts for Cisco switches (#666) * Update dependency commons-net:commons-net to v3.7.1 (#663) * gateway refactoring (#662) diff --git a/etc/docker_images.txt b/etc/docker_images.txt index e886b3759d..abc5be8b87 100644 --- a/etc/docker_images.txt +++ b/etc/docker_images.txt @@ -1,28 +1,28 @@ -daqf/aardvark2 ba31f0cdb571 -daqf/aardvark 52c88e3e29e9 -daqf/default 1f85c8cfd8b8 -daqf/faucet fa7367da86db -daqf/faux1 ddeff0fb4754 -daqf/faux2 1b77f7e85617 -daqf/gauge d4d9bfe1dce4 -daqf/networking 959f29a0882e -daqf/switch 2b0aa3afdf68 -daqf/test_bacext 974ccaf9bf18 -daqf/test_bacnet 08947e647db6 -daqf/test_brute 87ecefddf2ac -daqf/test_discover a8b5185faefe -daqf/test_fail 950817b0746f -daqf/test_hold 9ae60191b01f -daqf/test_ipaddr 2062d59c6a00 -daqf/test_manual 5bf34aaa9022 -daqf/test_mudgee 6d69223fc470 -daqf/test_network 875fa4a8ee38 -daqf/test_nmap 8c5de302c83a -daqf/test_pass 94139c33b754 -daqf/test_password 681129401c9d -daqf/test_ping c5967970fe7c -daqf/test_ssh 95069cbe6986 -daqf/test_switch 3f9467a6b64e -daqf/test_tls 5579450357a9 -daqf/test_udmi f6b132ae1c61 -daqf/usi a62f71285240 +daqf/aardvark2 0ce393ffb37e +daqf/aardvark f995c298c258 +daqf/default f1ef1d3ad545 +daqf/faucet fbe8fcd74856 +daqf/faux1 0ec2c2cb1c31 +daqf/faux2 8d4cbcd56104 +daqf/gauge 7a28cc93a38c +daqf/networking 2ff4f90e1d1a +daqf/switch 768b5e452e5b +daqf/test_bacext d6700b638cb8 +daqf/test_bacnet 323dbb70aedf +daqf/test_brute abbc2ee87029 +daqf/test_discover a9aa590c379b +daqf/test_fail 8b41703da93b +daqf/test_hold 212b678f24b6 +daqf/test_ipaddr cf75e4d9c236 +daqf/test_manual afeddf913b15 +daqf/test_mudgee 8748bc8faf02 +daqf/test_network 7ab8a5b0f99e +daqf/test_nmap bfe22f561e0f +daqf/test_pass e9dbc0eb1142 +daqf/test_password aa34b67972f7 +daqf/test_ping d262285977d0 +daqf/test_ssh fb02c5bb8abd +daqf/test_switch 7c6f2981cf17 +daqf/test_tls d0dcf063a766 +daqf/test_udmi fd5b8333c32f +daqf/usi c102882781e6 diff --git a/etc/docker_images.ver b/etc/docker_images.ver index 66beabb579..6ae756c479 100644 --- a/etc/docker_images.ver +++ b/etc/docker_images.ver @@ -1 +1 @@ -1.9.8 +1.9.9 From c3c893810588c80d66bcac482263d2a568481808 Mon Sep 17 00:00:00 2001 From: Puneet Date: Tue, 13 Oct 2020 18:29:16 -0700 Subject: [PATCH 168/212] 1.9.10 release --- docs/changelog.md | 2 +- etc/docker_images.txt | 16 ++++++++-------- etc/docker_images.ver | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/changelog.md b/docs/changelog.md index d1c48e7b72..f136508412 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,5 +1,5 @@ # Changelog -* 1.9.9 +* 1.9.10 * IP addr flush (#672) * Fix Cisco switch power response (#679) * Add SSH Reporting, SSH Bug Fixes (#670) diff --git a/etc/docker_images.txt b/etc/docker_images.txt index abc5be8b87..07ee73e62f 100644 --- a/etc/docker_images.txt +++ b/etc/docker_images.txt @@ -1,11 +1,11 @@ daqf/aardvark2 0ce393ffb37e daqf/aardvark f995c298c258 daqf/default f1ef1d3ad545 -daqf/faucet fbe8fcd74856 +daqf/faucet 604890ada50c daqf/faux1 0ec2c2cb1c31 daqf/faux2 8d4cbcd56104 -daqf/gauge 7a28cc93a38c -daqf/networking 2ff4f90e1d1a +daqf/gauge fd968818716f +daqf/networking d3696fe76191 daqf/switch 768b5e452e5b daqf/test_bacext d6700b638cb8 daqf/test_bacnet 323dbb70aedf @@ -13,16 +13,16 @@ daqf/test_brute abbc2ee87029 daqf/test_discover a9aa590c379b daqf/test_fail 8b41703da93b daqf/test_hold 212b678f24b6 -daqf/test_ipaddr cf75e4d9c236 +daqf/test_ipaddr 1acbf1a0315e daqf/test_manual afeddf913b15 daqf/test_mudgee 8748bc8faf02 -daqf/test_network 7ab8a5b0f99e +daqf/test_network 55d727fd3f51 daqf/test_nmap bfe22f561e0f daqf/test_pass e9dbc0eb1142 daqf/test_password aa34b67972f7 daqf/test_ping d262285977d0 -daqf/test_ssh fb02c5bb8abd +daqf/test_ssh 92337d261b25 daqf/test_switch 7c6f2981cf17 -daqf/test_tls d0dcf063a766 +daqf/test_tls 4e256e492642 daqf/test_udmi fd5b8333c32f -daqf/usi c102882781e6 +daqf/usi f80caf353903 diff --git a/etc/docker_images.ver b/etc/docker_images.ver index 6ae756c479..f0a2883d66 100644 --- a/etc/docker_images.ver +++ b/etc/docker_images.ver @@ -1 +1 @@ -1.9.9 +1.9.10 From 67574a2274c8a236abea106ba8d76efb2c139f62 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Oct 2020 19:57:27 -0700 Subject: [PATCH 169/212] Bump junit from 4.13 to 4.13.1 in /subset/switches (#678) --- subset/switches/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subset/switches/pom.xml b/subset/switches/pom.xml index 44e1dc0bf8..6081c1dd78 100644 --- a/subset/switches/pom.xml +++ b/subset/switches/pom.xml @@ -27,7 +27,7 @@ junit junit - 4.13 + 4.13.1 test From a299adf0af46b7051f4f8acae32f950527813f3f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 13 Oct 2020 19:57:50 -0700 Subject: [PATCH 170/212] Update dependency io.grpc:grpc-stub to v1.32.2 (#677) --- subset/switches/pom.xml | 2 +- usi/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subset/switches/pom.xml b/subset/switches/pom.xml index 6081c1dd78..3a788a0ec7 100644 --- a/subset/switches/pom.xml +++ b/subset/switches/pom.xml @@ -48,7 +48,7 @@ io.grpc grpc-stub - 1.32.1 + 1.32.2 org.apache.tomcat diff --git a/usi/pom.xml b/usi/pom.xml index 7b5377a11a..6724cb3fd1 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -48,7 +48,7 @@ io.grpc grpc-stub - 1.32.1 + 1.32.2 org.apache.tomcat From 226bec87d8179b93bc678f23a5964c89b923c073 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 13 Oct 2020 19:58:08 -0700 Subject: [PATCH 171/212] Update dependency io.grpc:grpc-protobuf to v1.32.2 (#675) --- subset/switches/pom.xml | 2 +- usi/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subset/switches/pom.xml b/subset/switches/pom.xml index 3a788a0ec7..26298efa22 100644 --- a/subset/switches/pom.xml +++ b/subset/switches/pom.xml @@ -43,7 +43,7 @@ io.grpc grpc-protobuf - 1.32.1 + 1.32.2 io.grpc diff --git a/usi/pom.xml b/usi/pom.xml index 6724cb3fd1..8cdf2bd04c 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -43,7 +43,7 @@ io.grpc grpc-protobuf - 1.32.1 + 1.32.2 io.grpc From 99e19ce62d06e3d36c28595c1bca30153fd8e3a1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 13 Oct 2020 19:58:25 -0700 Subject: [PATCH 172/212] Update dependency io.grpc:grpc-netty-shaded to v1.32.2 (#674) --- subset/switches/pom.xml | 2 +- usi/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subset/switches/pom.xml b/subset/switches/pom.xml index 26298efa22..92399d81f0 100644 --- a/subset/switches/pom.xml +++ b/subset/switches/pom.xml @@ -38,7 +38,7 @@ io.grpc grpc-netty-shaded - 1.32.1 + 1.32.2 io.grpc diff --git a/usi/pom.xml b/usi/pom.xml index 8cdf2bd04c..56093ff6c6 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -38,7 +38,7 @@ io.grpc grpc-netty-shaded - 1.32.1 + 1.32.2 io.grpc From 2f3cff33af3d4f5468f72678945f5fd1d85bf2a1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 13 Oct 2020 19:58:54 -0700 Subject: [PATCH 173/212] Update dependency io.grpc:grpc-bom to v1.32.2 (#676) --- subset/switches/pom.xml | 2 +- usi/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subset/switches/pom.xml b/subset/switches/pom.xml index 92399d81f0..c3460de97a 100644 --- a/subset/switches/pom.xml +++ b/subset/switches/pom.xml @@ -16,7 +16,7 @@ io.grpc grpc-bom - 1.32.1 + 1.32.2 pom import diff --git a/usi/pom.xml b/usi/pom.xml index 56093ff6c6..88d56f0480 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -16,7 +16,7 @@ io.grpc grpc-bom - 1.32.1 + 1.32.2 pom import From 9b8a549d55e62eb7f55f560c83d04ddab1bb5322 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 13 Oct 2020 19:59:17 -0700 Subject: [PATCH 174/212] Update dependency junit:junit to v4.13.1 (#673) --- docker/include/bacnet/bacnetFaux/build.gradle | 2 +- docker/include/network/NTPClient/build.gradle | 2 +- mudacl/build.gradle | 2 +- subset/bacnet/bacnetTests/build.gradle | 2 +- subset/network/mac_oui/build.gradle | 2 +- subset/security/tlstest/build.gradle | 2 +- usi/pom.xml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docker/include/bacnet/bacnetFaux/build.gradle b/docker/include/bacnet/bacnetFaux/build.gradle index 85657774fd..bb6f54eba3 100644 --- a/docker/include/bacnet/bacnetFaux/build.gradle +++ b/docker/include/bacnet/bacnetFaux/build.gradle @@ -12,7 +12,7 @@ repositories { } dependencies { - testCompile group: 'junit', name: 'junit', version: '4.13' + testCompile group: 'junit', name: 'junit', version: '4.13.1' implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.googlecode.json-simple:json-simple:1.1.1' } diff --git a/docker/include/network/NTPClient/build.gradle b/docker/include/network/NTPClient/build.gradle index 8a3dd211ff..1e2b327729 100644 --- a/docker/include/network/NTPClient/build.gradle +++ b/docker/include/network/NTPClient/build.gradle @@ -12,7 +12,7 @@ repositories { } dependencies { - testCompile group: 'junit', name: 'junit', version: '4.13' + testCompile group: 'junit', name: 'junit', version: '4.13.1' } jar { diff --git a/mudacl/build.gradle b/mudacl/build.gradle index f3667604bb..0ced07390c 100644 --- a/mudacl/build.gradle +++ b/mudacl/build.gradle @@ -34,5 +34,5 @@ repositories { dependencies { compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.11.1' compile group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: '2.11.1' - testCompile group: 'junit', name: 'junit', version: '4.13' + testCompile group: 'junit', name: 'junit', version: '4.13.1' } diff --git a/subset/bacnet/bacnetTests/build.gradle b/subset/bacnet/bacnetTests/build.gradle index 0fa797854a..56705183a7 100644 --- a/subset/bacnet/bacnetTests/build.gradle +++ b/subset/bacnet/bacnetTests/build.gradle @@ -12,7 +12,7 @@ repositories { } dependencies { - testCompile group: 'junit', name: 'junit', version: '4.13' + testCompile group: 'junit', name: 'junit', version: '4.13.1' implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.googlecode.json-simple:json-simple:1.1.1' } diff --git a/subset/network/mac_oui/build.gradle b/subset/network/mac_oui/build.gradle index 0f0dc95fe6..151c22b2e1 100644 --- a/subset/network/mac_oui/build.gradle +++ b/subset/network/mac_oui/build.gradle @@ -24,7 +24,7 @@ repositories { dependencies { api 'org.apache.commons:commons-math3:3.6.1' implementation 'com.google.guava:guava:23.0' - testImplementation 'junit:junit:4.13' + testImplementation 'junit:junit:4.13.1' } jar { diff --git a/subset/security/tlstest/build.gradle b/subset/security/tlstest/build.gradle index a7957055f2..9166cd5a87 100644 --- a/subset/security/tlstest/build.gradle +++ b/subset/security/tlstest/build.gradle @@ -20,7 +20,7 @@ dependencies { implementation 'com.google.guava:guava:23.0' compile 'com.google.code.gson:gson:2.8.6' compile group: 'org.bouncycastle', name: 'bcprov-jdk16', version: '1.45' - testImplementation 'junit:junit:4.13' + testImplementation 'junit:junit:4.13.1' } diff --git a/usi/pom.xml b/usi/pom.xml index 88d56f0480..c4d31cfb2f 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -27,7 +27,7 @@ junit junit - 4.13 + 4.13.1 test From 2df3632da961b8db3105a03d604310e0c7b31480 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Oct 2020 19:59:39 -0700 Subject: [PATCH 175/212] Bump junit from 4.13 to 4.13.1 in /usi (#680) From d1c9bcf65d2e114a4543dd15e2ef833015d7e6ef Mon Sep 17 00:00:00 2001 From: frgitdaq <62390501+frgitdaq@users.noreply.github.com> Date: Thu, 15 Oct 2020 14:05:12 +0100 Subject: [PATCH 176/212] DHCP Change (20) (#665) * Test to check change of DHCP range for new IP --- daq/test_modules/ipaddr_module.py | 10 ++++++++++ subset/ipaddr/README.md | 9 +++++++-- subset/ipaddr/dhcp_tests.py | 27 +++++++++++++++++++++++++++ subset/ipaddr/test_dhcp | 1 + testing/test_dhcp.out | 6 ++++-- testing/test_dhcp.sh | 8 +++++--- 6 files changed, 54 insertions(+), 7 deletions(-) diff --git a/daq/test_modules/ipaddr_module.py b/daq/test_modules/ipaddr_module.py index 3ad7774eb5..8723f7e7d6 100644 --- a/daq/test_modules/ipaddr_module.py +++ b/daq/test_modules/ipaddr_module.py @@ -35,6 +35,7 @@ def __init__(self, host, tmpdir, test_name, module_config): ('dhcp port_toggle test', self._dhcp_port_toggle_test), ('dhcp multi subnet test', self._multi_subnet_test), ('ip change test', self._ip_change_test), + ('dhcp change test', self._dhcp_change_test), ('analyze results', self._analyze) ] self._logger = logger.get_logger('ipaddr_%s' % self.host_name) @@ -102,6 +103,15 @@ def _ip_change_test(self): self.host.gateway.request_new_ip(self.host.target_mac) self._ip_callback = self._next_test + def _dhcp_change_test(self): + self._set_timeout() + if not self.host.connect_port(False): + self._logger.error('disconnect port not enabled') + return + self.host.gateway.request_new_ip(self.host.target_mac) + self.host.connect_port(True) + self._ip_callback = self._next_test + def _analyze(self): self._set_timeout() self._ip_callback = None diff --git a/subset/ipaddr/README.md b/subset/ipaddr/README.md index 030076b7ae..aaa95a7c89 100644 --- a/subset/ipaddr/README.md +++ b/subset/ipaddr/README.md @@ -15,8 +15,13 @@ This is because the functional code included in ipaddr communicates with the ope ### connection.dhcp.private_address - Device supports all private address ranges. #### Result Cases: -- PASS: The device accepts all private address ranges specified. -- FAIL: The device does not accept all private address ranges specified. +- PASS: A DHCP request was received for each private address range. +- FAIL: A DHCP request was not received for each private address range. +### connection.network.dhcp_change +- Device receives new IP address after IP change and port toggle. +#### Result Cases: +- PASS: Device received the new IP address. +- FAIL: Device did not receive the new IP address. ### connection.dhcp.ip_change - Device communicates after IP change. #### Result Cases: diff --git a/subset/ipaddr/dhcp_tests.py b/subset/ipaddr/dhcp_tests.py index e3cfe4b450..18b8259b66 100644 --- a/subset/ipaddr/dhcp_tests.py +++ b/subset/ipaddr/dhcp_tests.py @@ -19,7 +19,9 @@ def main(): description_dhcp_short = 'Reconnect device and check for DHCP request.' description_ip_change = 'Device communicates after IP change.' description_private_address = 'Device supports all private address ranges.' + description_dhcp_change = 'Device receives new IP address after IP change and port toggle.' running_port_toggle = 'Running dhcp port_toggle test' + running_dhcp_change = 'Running dhcp change test' running_ip_change = 'Running ip change test' ip_notification = 'ip notification' result = None @@ -120,6 +122,28 @@ def _test_private_address(): return 'pass', 'All private address ranges are supported.' return 'fail', 'Not all private address ranges are supported.' + def _test_dhcp_change(): + fd = open(ipaddr_log, 'r') + run_dhcp_change = False + dhcp_change_ip = None + for line in fd: + if run_dhcp_change: + if ip_notification in line: + dhcp_change_ip = line.split(ip_notification + ' ')[1].rstrip() + break + if running_dhcp_change in line: + run_dhcp_change = True + fd.close() + + capture = rdpcap(scan_file) + pingFound = False + for packet in capture: + if ICMP in packet and packet[IP].src == dhcp_change_ip: + pingFound = True + if pingFound: + return 'pass', 'Device has received new IP address.' + return 'fail', 'Device has not received new IP address.' + _write_report("{b}{t}\n{b}".format(b=dash_break_line, t=TEST_REQUEST)) if TEST_REQUEST == 'connection.network.dhcp_short': @@ -131,6 +155,9 @@ def _test_private_address(): elif TEST_REQUEST == 'connection.dhcp.private_address': result, summary = _test_private_address() _write_report("{d}\n{b}".format(b=dash_break_line, d=description_private_address)) + elif TEST_REQUEST == 'connection.network.dhcp_change': + result, summary = _test_dhcp_change() + _write_report("{d}\n{b}".format(b=dash_break_line, d=description_dhcp_change)) _write_report("RESULT {r} {t} {s}\n".format(r=result, t=TEST_REQUEST, s=summary)) diff --git a/subset/ipaddr/test_dhcp b/subset/ipaddr/test_dhcp index b5728daf13..4ff40a8ce1 100755 --- a/subset/ipaddr/test_dhcp +++ b/subset/ipaddr/test_dhcp @@ -4,6 +4,7 @@ REPORT=/tmp/report.txt python dhcp_tests.py connection.network.dhcp_short python dhcp_tests.py connection.dhcp.private_address +python dhcp_tests.py connection.network.dhcp_change python dhcp_tests.py connection.dhcp.ip_change cat report.txt >> $REPORT diff --git a/testing/test_dhcp.out b/testing/test_dhcp.out index 9f1e138906..3ec1d368d8 100644 --- a/testing/test_dhcp.out +++ b/testing/test_dhcp.out @@ -10,10 +10,12 @@ Device 1 ip triggers: 1 0 Device 2 ip triggers: 0 0 Device 3 long ip triggers: 1 Device 4 ip triggers: 1 -Device 4 subnet 1 ip: 1 subnet 2 ip: 1 subnet 3 ip: 2 ip_changed: 1 +Device 4 subnet 1 ip: 1 subnet 2 ip: 1 subnet 3 ip: 3 ip_changed: 1 Device 5 ip triggers: 1 -Device 5 num of ips: 2 +Device 5 num of ips: 3 Device 5 ip change: 1 +Device 5 dhcp change: 1 Device 6 DHCP timeouts: 1 Device 6 ip change: 0 +Device 6 dhcp change: 0 Done with tests diff --git a/testing/test_dhcp.sh b/testing/test_dhcp.sh index d6a28edd70..0370eb5c6b 100755 --- a/testing/test_dhcp.sh +++ b/testing/test_dhcp.sh @@ -31,7 +31,7 @@ cat < local/site/mac_addrs/$intf_mac/module_config.json } EOF -# Multi subnet multi subnet tests +# Multi subnet tests intf_mac="9a02571e8f04" mkdir -p local/site/mac_addrs/$intf_mac cat < local/site/mac_addrs/$intf_mac/module_config.json @@ -48,7 +48,7 @@ cat < local/site/mac_addrs/$intf_mac/module_config.json } EOF -# ip change test +# ip and dhcp change tests intf_mac="9a02571e8f05" mkdir -p local/site/mac_addrs/$intf_mac cat < local/site/mac_addrs/$intf_mac/module_config.json @@ -100,17 +100,19 @@ for iface in $(seq 1 6); do ip_triggers=$(fgrep done $ip_file | wc -l) long_triggers=$(fgrep long $ip_file | wc -l) num_ips=$(cat $ip_file | cut -d ' ' -f 1 | sort | uniq | wc -l) + dhcp_change=$(cat $report_file | fgrep 'pass connection.network.dhcp_change' | wc -l) ip_change=$(cat $report_file | fgrep 'pass connection.dhcp.ip_change' | wc -l) echo Found $ip_triggers ip triggers and $long_triggers long ip responses. - if [ $iface == 6 ]; then device_dhcp_timeouts=$(cat inst/cmdrun.log | fgrep 'DHCP times out after 120s lease time' | fgrep "ipaddr_ipaddr0$iface" | wc -l) echo "Device $iface DHCP timeouts: $device_dhcp_timeouts" | tee -a $TEST_RESULTS echo "Device $iface ip change: $((ip_change))" | tee -a $TEST_RESULTS + echo "Device $iface dhcp change: $((dhcp_change))" | tee -a $TEST_RESULTS elif [ $iface == 5 ]; then echo "Device $iface ip triggers: $(((ip_triggers + long_triggers) >= 3))" | tee -a $TEST_RESULTS echo "Device $iface num of ips: $num_ips" | tee -a $TEST_RESULTS echo "Device $iface ip change: $((ip_change))" | tee -a $TEST_RESULTS + echo "Device $iface dhcp change: $((dhcp_change))" | tee -a $TEST_RESULTS elif [ $iface == 4 ]; then echo "Device $iface ip triggers: $(((ip_triggers + long_triggers) >= 4))" | tee -a $TEST_RESULTS subnet_ip=$(fgrep "ip notification 192.168" inst/run-*/nodes/ipaddr*/tmp/activate.log | wc -l) From 77a8b50c2ab5f14c050c0766b1fba6cb7a7ff11a Mon Sep 17 00:00:00 2001 From: Francesco Anselmo Date: Mon, 19 Oct 2020 19:12:34 +0100 Subject: [PATCH 177/212] Test renaming (#682) * alignment of test names to the test plan --- docs/device_report.md | 136 +++++++++--------- docs/soak_report.md | 2 +- docs/troubleshooting.md | 2 +- .../setups/qualification/report_template.md | 2 +- .../qualification/system_module_config.json | 20 +-- .../setups/remediation/report_template.md | 2 +- .../remediation/system_module_config.json | 20 +-- resources/test_site/module_config.json | 2 +- resources/test_site/report_template.md | 2 +- .../bacnetTests/src/main/java/PicsTest.java | 2 +- .../src/main/java/VersionTest.java | 2 +- subset/bacnet/readme.md | 8 +- subset/bacnet/test_bacext | 4 +- subset/ipaddr/README.md | 11 +- subset/ipaddr/dhcp_tests.py | 8 +- subset/ipaddr/test_dhcp | 8 +- subset/network/README.md | 10 +- subset/network/dns_tests.py | 4 +- .../mac_oui/src/main/java/MacLookup.java | 6 +- subset/network/network_tests.py | 14 +- subset/network/ntp_tests.py | 4 +- subset/network/run_macoui_test | 2 +- subset/network/test_network | 10 +- subset/pentests/readme.md | 4 +- subset/pentests/test_discover | 2 +- subset/ping/module_manifest.json | 2 +- subset/ping/test_ping | 2 +- .../password/run_password_test_for_protocol | 14 +- subset/security/tls.module_manifest.json | 14 +- .../tlstest/src/main/java/Client.java | 12 +- .../src/main/java/ResultGenerator.java | 12 +- subset/switches/module_manifest.json | 6 +- subset/switches/readme.md | 8 +- .../src/main/java/switchtest/SwitchTest.java | 6 +- subset/switches/test_switch | 19 ++- testing/test_aux.out | 112 +++++++-------- testing/test_base.out | 6 +- testing/test_dhcp.sh | 4 +- testing/test_modules.out | 30 ++-- .../mock/test_combine_reports/report_1.json | 4 +- .../mock/test_combine_reports/report_2.json | 4 +- testing/unit/test_combine_reports.py | 2 +- 42 files changed, 273 insertions(+), 271 deletions(-) diff --git a/docs/device_report.md b/docs/device_report.md index d69eec5ecd..369af071b3 100644 --- a/docs/device_report.md +++ b/docs/device_report.md @@ -9,7 +9,7 @@ ## Test Iteration -| Test | | +| Test parameter | Value | |------------------|------------------------| | Test report start date | XXX | | Test report end date | XXX | @@ -62,37 +62,37 @@ Overall device result FAIL |---|---|---|---|---| |pass|base.startup.dhcp|Other|Other|| |skip|base.switch.ping|Other|Other|No local IP has been set, check system config| -|pass|base.target.ping|Connectivity|Required|target reached| |skip|cloud.udmi.pointset|Other|Other|No device id| |skip|cloud.udmi.provision|Other|Other|No device id| |skip|cloud.udmi.state|Other|Other|No device id| |skip|cloud.udmi.system|Other|Other|No device id| -|info|communication.type.broadcast|Other|Other|Broadcast packets received. Unicast packets received.| -|skip|connection.dns.hostname_connect|Other|Other|Device did not send any DNS requests| -|fail|connection.mac_oui|Other|Other|Manufacturer prefix not found!| -|pass|connection.min_send|Other|Other|ARP packets received. Data packets were sent at a frequency of less than 5 minutes| -|pass|connection.network.ntp_support|Other|Other|Using NTPv4.| -|pass|connection.network.ntp_update|Other|Other|Device clock synchronized.| -|skip|connection.port_duplex|Other|Other|No local IP has been set, check system config| -|skip|connection.port_link|Other|Other|No local IP has been set, check system config| -|skip|connection.port_speed|Other|Other|No local IP has been set, check system config| +|pass|communication.network.min_send|Other|Other|ARP packets received. Data packets were sent at a frequency of less than 5 minutes| +|info|communication.network.type|Other|Other|Broadcast packets received. Unicast packets received.| +|pass|connection.base.target_ping|Connectivity|Required|target reached| +|fail|connection.network.mac_oui|Other|Other|Manufacturer prefix not found!| +|skip|connection.switch.port_duplex|Other|Other|No local IP has been set, check system config| +|skip|connection.switch.port_link|Other|Other|No local IP has been set, check system config| +|skip|connection.switch.port_speed|Other|Other|No local IP has been set, check system config| +|skip|dns.network.hostname_resolution|Other|Other|Device did not send any DNS requests| |pass|manual.test.name|Security|Recommended|Manual test - for testing| +|pass|ntp.network.ntp_support|Other|Other|Using NTPv4.| +|pass|ntp.network.ntp_update|Other|Other|Device clock synchronized.| |skip|poe.switch.power|Other|Other|No local IP has been set, check system config| -|fail|protocol.bacnet.pic|Other|Other|PICS file defined however a BACnet device was not found.| -|skip|protocol.bacnet.version|Other|Other|Bacnet device not found.| -|skip|security.firmware|Other|Other|Could not retrieve a firmware version with nmap. Check bacnet port.| +|fail|protocol.bacext.pic|Other|Other|PICS file defined however a BACnet device was not found.| +|skip|protocol.bacext.version|Other|Other|Bacnet device not found.| +|skip|security.discover.firmware|Other|Other|Could not retrieve a firmware version with nmap. Check bacnet port.| |pass|security.nmap.http|Other|Other|No running http servers have been found.| |pass|security.nmap.ports|Other|Other|Only allowed ports found open.| -|skip|security.passwords.http|Other|Other|Port 80 not open on target device.| -|skip|security.passwords.https|Other|Other|Port 443 not open on target device.| -|skip|security.passwords.ssh|Other|Other|Port 22 not open on target device.| -|skip|security.passwords.telnet|Other|Other|Port 23 not open on target device.| +|skip|security.password.http|Other|Other|Port 80 not open on target device.| +|skip|security.password.https|Other|Other|Port 443 not open on target device.| +|skip|security.password.ssh|Other|Other|Port 22 not open on target device.| +|skip|security.password.telnet|Other|Other|Port 23 not open on target device.| |gone|security.ports.nmap|Security|Recommended|| -|skip|security.tlsv1.server|Other|Other|IOException unable to connect to server.| -|skip|security.tlsv1_2.client|Other|Other|No client initiated TLS communication detected| -|skip|security.tlsv1_2.server|Other|Other|IOException unable to connect to server.| -|skip|security.tlsv1_3.client|Other|Other|No client initiated TLS communication detected| -|skip|security.tlsv1_3.server|Other|Other|IOException unable to connect to server.| +|skip|security.tls.v1_2_client|Other|Other|No client initiated TLS communication detected| +|skip|security.tls.v1_2_server|Other|Other|IOException unable to connect to server.| +|skip|security.tls.v1_3_client|Other|Other|No client initiated TLS communication detected| +|skip|security.tls.v1_3_server|Other|Other|IOException unable to connect to server.| +|skip|security.tls.v1_server|Other|Other|IOException unable to connect to server.| |gone|unknown.fake.llama|Other|Other|| |gone|unknown.fake.monkey|Other|Other|| @@ -138,13 +138,13 @@ See log above RESULT skip base.switch.ping No local IP has been set, check system config -------------------- -base.target.ping +connection.base.target_ping -------------------- Attempt to ping the Device Under Test -------------------- See log above -------------------- -RESULT pass base.target.ping target reached +RESULT pass connection.base.target_ping target reached ``` @@ -198,7 +198,7 @@ RESULT pass security.nmap.http No running http servers have been found. ``` -------------------- -security.firmware +security.discover.firmware -------------------- Automatic bacnet firmware scan using nmap -------------------- @@ -206,7 +206,7 @@ PORT STATE SERVICE 47808/udp closed bacnet MAC Address: 9A:02:57:1E:8F:01 (Unknown) -------------------- -RESULT skip security.firmware Could not retrieve a firmware version with nmap. Check bacnet port. +RESULT skip security.discover.firmware Could not retrieve a firmware version with nmap. Check bacnet port. ``` @@ -223,31 +223,31 @@ RESULT skip security.firmware Could not retrieve a firmware version with nmap. C ``` -------------------- -connection.port_link +connection.switch.port_link -------------------- Connect the device to the network switch. Check the device and the switch for the green connection light & no errors -------------------- LOCAL_IP not configured, assuming no network switch. -------------------- -RESULT skip connection.port_link No local IP has been set, check system config +RESULT skip connection.switch.port_link No local IP has been set, check system config -------------------- -connection.port_speed +connection.switch.port_speed -------------------- Verify the device auto-negotiates connection speed -------------------- LOCAL_IP not configured, assuming no network switch. -------------------- -RESULT skip connection.port_speed No local IP has been set, check system config +RESULT skip connection.switch.port_speed No local IP has been set, check system config -------------------- -connection.port_duplex +connection.switch.port_duplex -------------------- Verify the device supports full duplex -------------------- LOCAL_IP not configured, assuming no network switch. -------------------- -RESULT skip connection.port_duplex No local IP has been set, check system config +RESULT skip connection.switch.port_duplex No local IP has been set, check system config -------------------- poe.switch.power @@ -274,22 +274,22 @@ RESULT skip poe.switch.power No local IP has been set, check system config ``` -------------------- -protocol.bacnet.version +protocol.bacext.version -------------------- Verify and record version of Bacnet used by the device -------------------- Bacnet device not found. -------------------- -RESULT skip protocol.bacnet.version Bacnet device not found. +RESULT skip protocol.bacext.version Bacnet device not found. -------------------- -protocol.bacnet.pic +protocol.bacext.pic -------------------- Verify BACnet traffic is compliant to the PIC statement -------------------- PICS file defined however a BACnet device was not found. -------------------- -RESULT fail protocol.bacnet.pic PICS file defined however a BACnet device was not found. +RESULT fail protocol.bacext.pic PICS file defined however a BACnet device was not found. ``` @@ -329,49 +329,49 @@ Gathering TLS Client X.X.X.X Information.... TLS Client Information Complete. -------------------- -security.tlsv1.server +security.tls.v1_2_client -------------------- -Verify the device supports at least TLS 1.0 (as a server) +Verify the device supports at least TLS 1.2 (as a client) -------------------- See log above -------------------- -RESULT skip security.tlsv1.server IOException unable to connect to server. +RESULT skip security.tls.v1_2_client No client initiated TLS communication detected -------------------- -security.tlsv1_2.client +security.tls.v1_2_server -------------------- -null +Verify the device supports TLS 1.2 (as a server) -------------------- See log above -------------------- -RESULT skip security.tlsv1_2.client No client initiated TLS communication detected +RESULT skip security.tls.v1_2_server IOException unable to connect to server. -------------------- -security.tlsv1_2.server +security.tls.v1_3_client -------------------- -Verify the device supports TLS 1.2 (as a server) +Verify the device supports at least TLS 1.3 (as a client) -------------------- See log above -------------------- -RESULT skip security.tlsv1_2.server IOException unable to connect to server. +RESULT skip security.tls.v1_3_client No client initiated TLS communication detected -------------------- -security.tlsv1_3.client +security.tls.v1_3_server -------------------- -null +Verify the device supports TLS 1.3 (as a server) -------------------- See log above -------------------- -RESULT skip security.tlsv1_3.client No client initiated TLS communication detected +RESULT skip security.tls.v1_3_server IOException unable to connect to server. -------------------- -security.tlsv1_3.server +security.tls.v1_server -------------------- -Verify the device supports TLS 1.3 (as a server) +Verify the device supports at least TLS 1.0 (as a server) -------------------- See log above -------------------- -RESULT skip security.tlsv1_3.server IOException unable to connect to server. +RESULT skip security.tls.v1_server IOException unable to connect to server. ``` @@ -405,7 +405,7 @@ MAC Address: 9A:02:57:1E:8F:01 (Unknown) Nmap done: 1 IP address (1 host up) scanned in XXX Could not connect to specified port on host. -------------------- -RESULT skip security.passwords.http Port 80 not open on target device. +RESULT skip security.password.http Port 80 not open on target device. -------------------- security.admin.password.https @@ -424,7 +424,7 @@ MAC Address: 9A:02:57:1E:8F:01 (Unknown) Nmap done: 1 IP address (1 host up) scanned in XXX Could not connect to specified port on host. -------------------- -RESULT skip security.passwords.https Port 443 not open on target device. +RESULT skip security.password.https Port 443 not open on target device. -------------------- security.admin.password.ssh @@ -443,7 +443,7 @@ MAC Address: 9A:02:57:1E:8F:01 (Unknown) Nmap done: 1 IP address (1 host up) scanned in XXX Could not connect to specified port on host. -------------------- -RESULT skip security.passwords.ssh Port 22 not open on target device. +RESULT skip security.password.ssh Port 22 not open on target device. -------------------- security.admin.password.telnet @@ -462,7 +462,7 @@ MAC Address: 9A:02:57:1E:8F:01 (Unknown) Nmap done: 1 IP address (1 host up) scanned in XXX Could not connect to specified port on host. -------------------- -RESULT skip security.passwords.telnet Port 23 not open on target device. +RESULT skip security.password.telnet Port 23 not open on target device. ``` @@ -553,7 +553,7 @@ RESULT pass manual.test.name Manual test - for testing ``` -------------------- -connection.min_send +communication.network.min_send -------------------- Device sends data at a frequency of less than 5 minutes. -------------------- @@ -568,43 +568,43 @@ Device sends data at a frequency of less than 5 minutes. -RESULT pass connection.min_send ARP packets received. Data packets were sent at a frequency of less than 5 minutes +RESULT pass communication.network.min_send ARP packets received. Data packets were sent at a frequency of less than 5 minutes -------------------- -communication.type.broadcast +communication.network.type -------------------- Device sends unicast or broadcast packets. -------------------- -RESULT info communication.type.broadcast Broadcast packets received. Unicast packets received. +RESULT info communication.network.type Broadcast packets received. Unicast packets received. -------------------- -connection.network.ntp_support +ntp.network.ntp_support -------------------- Device supports NTP version 4. -------------------- -RESULT pass connection.network.ntp_support Using NTPv4. +RESULT pass ntp.network.ntp_support Using NTPv4. -------------------- -connection.network.ntp_update +ntp.network.ntp_update -------------------- Device synchronizes its time to the NTP server. -------------------- -RESULT pass connection.network.ntp_update Device clock synchronized. +RESULT pass ntp.network.ntp_update Device clock synchronized. -------------------- -connection.mac_oui +connection.network.mac_oui -------------------- Check Physical device address OUI against IEEE registration and verify it is registered with the correct manufacturer -------------------- Using the host hardware address 9a:02:57:1e:8f:01 Mac OUI Test -------------------- -RESULT fail connection.mac_oui Manufacturer prefix not found! +RESULT fail connection.network.mac_oui Manufacturer prefix not found! -------------------- -connection.dns.hostname_connect +dns.network.hostname_resolution -------------------- Check device uses the DNS server from DHCP and resolves hostnames -------------------- -RESULT skip connection.dns.hostname_connect Device did not send any DNS requests +RESULT skip dns.network.hostname_resolution Device did not send any DNS requests ``` #### Module Config diff --git a/docs/soak_report.md b/docs/soak_report.md index 748bfeb93c..fec96777cd 100644 --- a/docs/soak_report.md +++ b/docs/soak_report.md @@ -8,7 +8,7 @@ Source: local |---|---|---| |base.startup.dhcp|2|0| |base.switch.ping|0|2| -|base.target.ping|2|0| +|connection.base.target_ping|2|0| |security.nmap.ports|2|0| |security.nmap.http|2|0| diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 05aca2c9d6..9ac51c176a 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -51,7 +51,7 @@ the common `cmdrun.log` file, the test-specific `activate.log`, `module_config.json`, and `report.txt` are the most helpul for diagnostics and troubleshooting. -* Each test result (e.g. _protocol.bacnet.version_) is supplied by a _module_. +* Each test result (e.g. _protocol.bacext.version_) is supplied by a _module_. * There is no obvious mapping from _test_ to _module_, so there might be some sleuthing involved. * Make sure the test's _module_ is properly configured/run in the `cmdrun.log` diff --git a/resources/setups/qualification/report_template.md b/resources/setups/qualification/report_template.md index 7a8cd03619..6ffb6a491a 100644 --- a/resources/setups/qualification/report_template.md +++ b/resources/setups/qualification/report_template.md @@ -13,7 +13,7 @@ Approver | {{ process.approver }} | ## Test Iteration -Test | +Test parameter | Value ---------------------- | ---------------------------- Test report start date | {{ start_time }} Test report end date | {{ end_time}} diff --git a/resources/setups/qualification/system_module_config.json b/resources/setups/qualification/system_module_config.json index c06d3ab4f3..8698ded88c 100644 --- a/resources/setups/qualification/system_module_config.json +++ b/resources/setups/qualification/system_module_config.json @@ -75,12 +75,12 @@ "required": "pass", "expected": "Required Pass" }, - "connection.dhcp.private_address": { + "connection.ipaddr.private_address": { "category": "Connection", "required": "pass", "expected": "Required Pass" }, - "connection.network.dhcp_short": { + "connection.ipaddr.dhcp_disconnect": { "category": "Connection", "required": "pass", "expected": "Required Pass" @@ -95,12 +95,12 @@ "required": "pass", "expected": "Required Pass" }, - "connection.network.ntp_support": { + "ntp.network.ntp_support": { "category": "Network Time", "required": "pass", "expected": "Required Pass" }, - "connection.network.ntp_update": { + "ntp.network.ntp_update": { "category": "Network Time", "required": "pass", "expected": "Required Pass" @@ -130,32 +130,32 @@ "required": "pass", "expected": "Required Pass" }, - "security.passwords.http": { + "security.password.http": { "category": "Security", "required": "pass", "expected": "Required Pass" }, - "security.passwords.https": { + "security.password.https": { "category": "Security", "required": "pass", "expected": "Required Pass" }, - "security.passwords.ssh": { + "security.password.ssh": { "category": "Security", "required": "pass", "expected": "Required Pass" }, - "security.passwords.telnet": { + "security.password.telnet": { "category": "Security", "required": "pass", "expected": "Required Pass" }, - "protocol.bacnet.pic": { + "protocol.bacext.pic": { "category": "Protocol", "required": "pass", "expected": "Required Pass for BACnet Devices" }, - "protocol.bacnet.version": { + "protocol.bacext.version": { "category": "Protocol", "required": "info", "expected": "Information" diff --git a/resources/setups/remediation/report_template.md b/resources/setups/remediation/report_template.md index d15f7070fd..fc3ff7217f 100644 --- a/resources/setups/remediation/report_template.md +++ b/resources/setups/remediation/report_template.md @@ -6,7 +6,7 @@ ## Test Iteration -Test | +Test parameter | Value ---------------------- | ---------------------------- Test report start date | {{ start_time }} Test report end date | {{ end_time}} diff --git a/resources/setups/remediation/system_module_config.json b/resources/setups/remediation/system_module_config.json index 3e215677ac..e821c16ee2 100644 --- a/resources/setups/remediation/system_module_config.json +++ b/resources/setups/remediation/system_module_config.json @@ -71,12 +71,12 @@ "required": "pass", "expected": "Required Pass" }, - "connection.dhcp.private_address": { + "connection.ipaddr.private_address": { "category": "Connection", "required": "pass", "expected": "Required Pass" }, - "connection.network.dhcp_short": { + "connection.ipaddr.dhcp_disconnect": { "category": "Connection", "required": "pass", "expected": "Required Pass" @@ -91,12 +91,12 @@ "required": "pass", "expected": "Required Pass" }, - "connection.network.ntp_support": { + "ntp.network.ntp_support": { "category": "Network Time", "required": "pass", "expected": "Recommended Pass" }, - "connection.network.ntp_update": { + "ntp.network.ntp_update": { "category": "Network Time", "required": "pass", "expected": "Recommended Pass" @@ -126,32 +126,32 @@ "required": "pass", "expected": "Required Pass" }, - "security.passwords.http": { + "security.password.http": { "category": "Security", "required": "pass", "expected": "Required Pass" }, - "security.passwords.https": { + "security.password.https": { "category": "Security", "required": "pass", "expected": "Required Pass" }, - "security.passwords.ssh": { + "security.password.ssh": { "category": "Security", "required": "pass", "expected": "Required Pass" }, - "security.passwords.telnet": { + "security.password.telnet": { "category": "Security", "required": "pass", "expected": "Required Pass" }, - "protocol.bacnet.pic": { + "protocol.bacext.pic": { "category": "Protocol", "required": "pass", "expected": "Required Pass for BACnet devices" }, - "protocol.bacnet.version": { + "protocol.bacext.version": { "category": "Protocol", "required": "info", "expected": "Information" diff --git a/resources/test_site/module_config.json b/resources/test_site/module_config.json index 03f7d504d0..05f4e85e48 100644 --- a/resources/test_site/module_config.json +++ b/resources/test_site/module_config.json @@ -38,7 +38,7 @@ "unknown.fake.monkey": { "required": "pass" }, - "base.target.ping": { + "connection.base.target_ping": { "category": "Connectivity", "expected": "Required" }, diff --git a/resources/test_site/report_template.md b/resources/test_site/report_template.md index 15325a9251..3fc93fc8a0 100644 --- a/resources/test_site/report_template.md +++ b/resources/test_site/report_template.md @@ -9,7 +9,7 @@ ## Test Iteration -| Test | | +| Test parameter | Value | |------------------|------------------------| | Test report start date | {{ start_time }} | | Test report end date | {{ end_time}} | diff --git a/subset/bacnet/bacnetTests/src/main/java/PicsTest.java b/subset/bacnet/bacnetTests/src/main/java/PicsTest.java index 0c140096f0..7c1db2210a 100644 --- a/subset/bacnet/bacnetTests/src/main/java/PicsTest.java +++ b/subset/bacnet/bacnetTests/src/main/java/PicsTest.java @@ -12,7 +12,7 @@ public class PicsTest { private Connection connection; private BacnetValidation validator; private BacnetPoints bacnetPoints = new BacnetPoints(); - private String testName = "protocol.bacnet.pic"; + private String testName = "protocol.bacext.pic"; private String passedTestReport = String.format("RESULT pass %s The devices matches the PICS\n", testName); private String failedTestReport = String.format("RESULT fail %s ", testName); private String skippedTestReport = String.format("RESULT skip %s ", testName); diff --git a/subset/bacnet/bacnetTests/src/main/java/VersionTest.java b/subset/bacnet/bacnetTests/src/main/java/VersionTest.java index f3edd3b97c..0bcb16d274 100644 --- a/subset/bacnet/bacnetTests/src/main/java/VersionTest.java +++ b/subset/bacnet/bacnetTests/src/main/java/VersionTest.java @@ -21,7 +21,7 @@ public class VersionTest { private String appendixText = ""; private boolean testPassed = false; boolean bacnetSupported = false; - private String testName = "protocol.bacnet.version"; + private String testName = "protocol.bacext.version"; private String infoReportText = String.format("RESULT info %s", testName); private String skippedReportText = String.format("RESULT skip %s Bacnet device not found.", testName); private String errorPropertyMessage = "errorClass=Property, errorCode=Unknown property"; diff --git a/subset/bacnet/readme.md b/subset/bacnet/readme.md index 4e7d6a0a08..f988ae39f1 100644 --- a/subset/bacnet/readme.md +++ b/subset/bacnet/readme.md @@ -6,17 +6,17 @@ The bacext test module includes tests that assess the BACnet stack implementatio The tests included in this module are: -- `protocol.bacnet.version` -- `protocol.bacnet.pic` +- `protocol.bacext.version` +- `protocol.bacext.pic` -### Conditions for `protocol.bacnet.version`: +### Conditions for `protocol.bacext.version`: This test retrieves the BACnet protocol version from a BACnet device - `info` -> BACnet protocol version found from device - `skip` -> the device under testing is not a BACnet device, test skipped -### Conditions for `protocol.bacnet.pic`: +### Conditions for `protocol.bacext.pic`: This test verifies that the device BACnet protocol implementation is compliant to the device PIC statement. diff --git a/subset/bacnet/test_bacext b/subset/bacnet/test_bacext index f6451e24b4..b12270ba5c 100755 --- a/subset/bacnet/test_bacext +++ b/subset/bacnet/test_bacext @@ -47,13 +47,13 @@ PICS_LOG=$(cat tmp/BacnetPICSTest_APPENDIX.txt) PICS_RESULT_AND_SUMMARY=$(cat tmp/BacnetPICSTestReport.txt) write_out_result $REPORT \ - "protocol.bacnet.version" \ + "protocol.bacext.version" \ "Verify and record version of Bacnet used by the device" \ "$VERSION_LOG" \ "$VERSION_RESULT_AND_SUMMARY" write_out_result $REPORT \ - "protocol.bacnet.pic" \ + "protocol.bacext.pic" \ "Verify BACnet traffic is compliant to the PIC statement" \ "$PICS_LOG" \ "$PICS_RESULT_AND_SUMMARY" diff --git a/subset/ipaddr/README.md b/subset/ipaddr/README.md index aaa95a7c89..f097de8187 100644 --- a/subset/ipaddr/README.md +++ b/subset/ipaddr/README.md @@ -7,22 +7,25 @@ This is because the functional code included in ipaddr communicates with the ope ## Tests -### connection.network.dhcp_short +### connection.ipaddr.dhcp_disconnect - Reconnect device and check for DHCP request. #### Result Cases: - PASS: A DHCP request has been received by the device after the port has been disconnected and connected. - FAIL: No DHCP request was received (this will also be the case if the target is using a static IP). -### connection.dhcp.private_address + +### connection.ipaddr.private_address - Device supports all private address ranges. #### Result Cases: - PASS: A DHCP request was received for each private address range. - FAIL: A DHCP request was not received for each private address range. -### connection.network.dhcp_change + +### connection.ipaddr.disconnect_ip_change - Device receives new IP address after IP change and port toggle. #### Result Cases: - PASS: Device received the new IP address. - FAIL: Device did not receive the new IP address. -### connection.dhcp.ip_change + +### connection.ipaddr.ip_change - Device communicates after IP change. #### Result Cases: - PASS: A ping reply is found after the IP address has been changed. diff --git a/subset/ipaddr/dhcp_tests.py b/subset/ipaddr/dhcp_tests.py index 18b8259b66..33e6d59626 100644 --- a/subset/ipaddr/dhcp_tests.py +++ b/subset/ipaddr/dhcp_tests.py @@ -146,16 +146,16 @@ def _test_dhcp_change(): _write_report("{b}{t}\n{b}".format(b=dash_break_line, t=TEST_REQUEST)) - if TEST_REQUEST == 'connection.network.dhcp_short': + if TEST_REQUEST == 'connection.ipaddr.dhcp_disconnect': result, summary = _test_dhcp_short() _write_report("{d}\n{b}".format(b=dash_break_line, d=description_dhcp_short)) - elif TEST_REQUEST == 'connection.dhcp.ip_change': + elif TEST_REQUEST == 'connection.ipaddr.ip_change': result, summary = _test_ip_change() _write_report("{d}\n{b}".format(b=dash_break_line, d=description_ip_change)) - elif TEST_REQUEST == 'connection.dhcp.private_address': + elif TEST_REQUEST == 'connection.ipaddr.private_address': result, summary = _test_private_address() _write_report("{d}\n{b}".format(b=dash_break_line, d=description_private_address)) - elif TEST_REQUEST == 'connection.network.dhcp_change': + elif TEST_REQUEST == 'connection.ipaddr.disconnect_ip_change': result, summary = _test_dhcp_change() _write_report("{d}\n{b}".format(b=dash_break_line, d=description_dhcp_change)) diff --git a/subset/ipaddr/test_dhcp b/subset/ipaddr/test_dhcp index 4ff40a8ce1..5567c52ba6 100755 --- a/subset/ipaddr/test_dhcp +++ b/subset/ipaddr/test_dhcp @@ -2,9 +2,9 @@ source reporting.sh REPORT=/tmp/report.txt -python dhcp_tests.py connection.network.dhcp_short -python dhcp_tests.py connection.dhcp.private_address -python dhcp_tests.py connection.network.dhcp_change -python dhcp_tests.py connection.dhcp.ip_change +python dhcp_tests.py connection.ipaddr.dhcp_disconnect +python dhcp_tests.py connection.ipaddr.private_address +python dhcp_tests.py connection.ipaddr.ip_change +python dhcp_tests.py connection.ipaddr.disconnect_ip_change cat report.txt >> $REPORT diff --git a/subset/network/README.md b/subset/network/README.md index 16989e34b2..2695fd8b4b 100644 --- a/subset/network/README.md +++ b/subset/network/README.md @@ -2,7 +2,7 @@ ## General Network Tests -### connection.min_send +### communication.network.min_send - Located in network_tests.py, started up in test_network. - Check if a device sends any data packet at a frequency of less than five minutes. @@ -11,7 +11,7 @@ - FAIL: If data packets are sent, and there are packets with time interval of less than five minutes found, then fail. - SKIP: If no data packets are sent and the monitor scan period is short, the test will skip instead of failing. -### communication.type.broadcast +### communication.network.type - Located in network_tests.py, started up in test_network. - This test counts the number of unicast, broadcast and multicast packets sent out by reading from the .pcap file that DAQ has created during runtime. @@ -32,8 +32,8 @@ If the python code needs debugging, the pip module `scapy` is required (`pip ins ### NTP Test conditions | Test ID | Info | Pass | Fail | Skip | |---|---|---|---|---| -| connection.network.ntp_support | Are the received NTP packets using NTP v4? | NTP version is 4 | NTP version is not 4 | No NTP packets are received | -| connection.network.ntp_update | Does the device demonstrate updating its clock using NTP? | Device clock is synchronized | Device clock is not synchronized | Not enough NTP packets are received | +| ntp.network.ntp_support | Are the received NTP packets using NTP v4? | NTP version is 4 | NTP version is not 4 | No NTP packets are received | +| ntp.network.ntp_update | Does the device demonstrate updating its clock using NTP? | Device clock is synchronized | Device clock is not synchronized | Not enough NTP packets are received | #### NTP Support #### The version of NTP used by the client is extracted from the first client (outbound) NTP packets discovered in monitor.pcap. @@ -69,7 +69,7 @@ static resource on the source code repo. ## DNS Tests Check Device uses the DNS server from DHCP and resolves hostnames -### Conditions for connection.dns.hostname_connect +### Conditions for dns.network.hostname_resolution - pass -> if the device uses the DNS server from DHCP, and resolves a hostname - fail -> device uses a DNS serveer other than the server fron DHCP - skip -> device did not send any DNS requests diff --git a/subset/network/dns_tests.py b/subset/network/dns_tests.py index f8ebfde258..bc5c782cc3 100644 --- a/subset/network/dns_tests.py +++ b/subset/network/dns_tests.py @@ -118,7 +118,7 @@ def check_communication_for_response(response_line): def test_dns(target_ip): - """ Runs the connection.dns.hostname_connect test + """ Runs the dns.network.hostname_resolution test Checks that: i) the device sends DNS requests @@ -176,7 +176,7 @@ def test_dns(target_ip): write_report("{b}{t}\n{b}".format(b=dash_break_line, t=test_request)) -if test_request == 'connection.dns.hostname_connect': +if test_request == 'dns.network.hostname_resolution': write_report("{d}\n{b}".format(b=dash_break_line, d=DESCRIPTION_HOSTNAME_CONNECT)) result = test_dns(device_address) diff --git a/subset/network/mac_oui/src/main/java/MacLookup.java b/subset/network/mac_oui/src/main/java/MacLookup.java index eff4c68963..f284459496 100644 --- a/subset/network/mac_oui/src/main/java/MacLookup.java +++ b/subset/network/mac_oui/src/main/java/MacLookup.java @@ -11,19 +11,19 @@ public class MacLookup { } public void startTest() { - System.out.println("Starting connection.mac_oui test..."); + System.out.println("Starting connection.network.mac_oui test..."); String splicedMac = macAddress.replace(":", ""); String formattedMac = splicedMac.substring(0, 6).toUpperCase(); System.out.println(formattedMac); try { String manufacturer = macDevices.get(formattedMac).toString(); - reportHandler.addText("RESULT pass connection.mac_oui Manufacturer: " + reportHandler.addText("RESULT pass connection.network.mac_oui Manufacturer: " + manufacturer + " found for address " + macAddress); reportHandler.writeReport(); System.out.println(formattedMac + " " + manufacturer); } catch (NullPointerException e) { System.out.println(e + " could not find the manufacturer"); - reportHandler.addText("RESULT fail connection.mac_oui Manufacturer prefix not found!"); + reportHandler.addText("RESULT fail connection.network.mac_oui Manufacturer prefix not found!"); reportHandler.writeReport(); System.out.println(formattedMac + " unknown"); } diff --git a/subset/network/network_tests.py b/subset/network/network_tests.py index 8fafee8856..5ef25bc182 100644 --- a/subset/network/network_tests.py +++ b/subset/network/network_tests.py @@ -1,13 +1,13 @@ """ This script can be called to run a specific network module test. Currently supports: - - connection.min_send + - communication.network.min_send - connection.dhcp_long - protocol.app_min_send - - communication.type.broadcast + - communication.network.type - network.ntp.support Usage: python network_tests.py - E.g. python network_tests.py connection.min_send $MONITOR $TARGET_IP + E.g. python network_tests.py communication.network.min_send $MONITOR $TARGET_IP """ import subprocess, time, sys, json @@ -123,7 +123,7 @@ def add_summary(text): def test_connection_min_send(): - """ Runs the connection.min_send test + """ Runs the communication.network.min_send test Tests if the device sends data packets of any type (inc data, NTP, etc) within a period of 5 minutes by looking through the monitor.pcap file @@ -184,7 +184,7 @@ def test_connection_min_send(): def test_communication_type_broadcast(): - """ Runs the communication.type.broadcast DAQ test. + """ Runs the communication.network.type DAQ test. Counts the number of unicast, broadcast and multicast packets sent. """ @@ -211,10 +211,10 @@ def test_communication_type_broadcast(): write_report("{b}{t}\n{b}".format(b=dash_break_line, t=test_request)) -if test_request == 'connection.min_send': +if test_request == 'communication.network.min_send': write_report("{d}\n{b}".format(b=dash_break_line, d=description_min_send)) result = test_connection_min_send() -elif test_request == 'communication.type.broadcast': +elif test_request == 'communication.network.type': write_report("{d}\n{b}".format(b=dash_break_line, d=description_communication_type)) result = test_communication_type_broadcast() diff --git a/subset/network/ntp_tests.py b/subset/network/ntp_tests.py index c4ac22aeb4..094b45e75f 100644 --- a/subset/network/ntp_tests.py +++ b/subset/network/ntp_tests.py @@ -157,10 +157,10 @@ def add_summary(text): write_report("{b}{t}\n{b}".format(b=dash_break_line, t=test_request)) -if test_request == 'connection.network.ntp_support': +if test_request == 'ntp.network.ntp_support': write_report("{d}\n{b}".format(b=dash_break_line, d=description_ntp_support)) result = test_ntp_support() -elif test_request == 'connection.network.ntp_update': +elif test_request == 'ntp.network.ntp_update': write_report("{d}\n{b}".format(b=dash_break_line, d=description_ntp_update)) result = test_ntp_update() diff --git a/subset/network/run_macoui_test b/subset/network/run_macoui_test index fba57c38c6..2507147b30 100755 --- a/subset/network/run_macoui_test +++ b/subset/network/run_macoui_test @@ -9,7 +9,7 @@ CONFIG=/config/device/module_config.json LOG=/tmp/nmap.log RESULT_LINES=/tmp/result_lines.txt -TEST_NAME="connection.mac_oui" +TEST_NAME="connection.network.mac_oui" TEST_DESCRIPTION="Check Physical device address OUI against IEEE registration and verify it is registered with the correct manufacturer" REDACTED_LOG=/tmp/macoui.report.log diff --git a/subset/network/test_network b/subset/network/test_network index 0bc5ee332b..022c91bedb 100755 --- a/subset/network/test_network +++ b/subset/network/test_network @@ -5,14 +5,14 @@ REPORT=/tmp/report.txt MONITOR=/scans/monitor.pcap # General Network Tests -python network_tests.py connection.min_send $MONITOR $TARGET_IP -python network_tests.py communication.type.broadcast $MONITOR $TARGET_IP +python network_tests.py communication.network.min_send $MONITOR $TARGET_IP +python network_tests.py communication.network.type $MONITOR $TARGET_IP cat network_tests.txt >> $REPORT # NTP Tests -python ntp_tests.py connection.network.ntp_support $MONITOR -python ntp_tests.py connection.network.ntp_update $MONITOR +python ntp_tests.py ntp.network.ntp_support $MONITOR +python ntp_tests.py ntp.network.ntp_update $MONITOR cat ntp_tests.txt >> $REPORT @@ -20,6 +20,6 @@ cat ntp_tests.txt >> $REPORT ./run_macoui_test $TARGET_MAC $REPORT # DNS Tests -python dns_tests.py connection.dns.hostname_connect $MONITOR $TARGET_IP +python dns_tests.py dns.network.hostname_resolution $MONITOR $TARGET_IP cat dns_tests.txt >> $REPORT diff --git a/subset/pentests/readme.md b/subset/pentests/readme.md index 845555fe11..4a2da2d7ab 100644 --- a/subset/pentests/readme.md +++ b/subset/pentests/readme.md @@ -21,9 +21,9 @@ The discover test module attempts to find information from devices automatically Tests included in this module: -- security.firmware +- security.discover.firmware -### Conditions for security.firmware: +### Conditions for security.discover.firmware: - pass -> version matches device_info.firmware_version - fail -> version DOES NOT match device_info.firmware_version diff --git a/subset/pentests/test_discover b/subset/pentests/test_discover index 42d0d98580..af62e9d31d 100755 --- a/subset/pentests/test_discover +++ b/subset/pentests/test_discover @@ -4,7 +4,7 @@ source reporting.sh REPORT=/tmp/report.txt CONFIG=/config/device/module_config.json -TEST_NAME='security.firmware' +TEST_NAME='security.discover.firmware' TEST_DESCRIPTION='Automatic bacnet firmware scan using nmap' TEST_SUMMARY=' Nothing more to report...' LOG=/tmp/discover.log diff --git a/subset/ping/module_manifest.json b/subset/ping/module_manifest.json index 1f6b3585e4..bbd2e491d6 100644 --- a/subset/ping/module_manifest.json +++ b/subset/ping/module_manifest.json @@ -5,7 +5,7 @@ "base.switch.ping": { "description": "Attempt to ping access switch (if configured)" }, - "base.target.ping": { + "connection.base.target_ping": { "description": "Attempt to ping the Device Under Test" } } diff --git a/subset/ping/test_ping b/subset/ping/test_ping index d0d8bb2805..9a6631dbd8 100755 --- a/subset/ping/test_ping +++ b/subset/ping/test_ping @@ -76,7 +76,7 @@ else summary="could not reach target" fi -echo RESULT $local_status base.target.ping $summary %% $TARGET_IP | tee -a $RESULT_LINES +echo RESULT $local_status connection.base.target_ping $summary %% $TARGET_IP | tee -a $RESULT_LINES echo | tee -a $MONO_LOG echo Done with basic connectivity tests | tee -a $MONO_LOG diff --git a/subset/security/password/run_password_test_for_protocol b/subset/security/password/run_password_test_for_protocol index 5b4d0c4099..0e08892db4 100755 --- a/subset/security/password/run_password_test_for_protocol +++ b/subset/security/password/run_password_test_for_protocol @@ -108,19 +108,19 @@ function write_to_result_file() { touch $RESULT_FILE if [ "$3" == "pass" ]; then - echo "RESULT pass security.passwords.$1 Was not able to brute force using dictionary." > $RESULT_FILE + echo "RESULT pass security.password.$1 Was not able to brute force using dictionary." > $RESULT_FILE elif [ "$3" == "fail" ]; then - echo "RESULT fail security.passwords.$1 Was able to brute force using dictionary." > $RESULT_FILE + echo "RESULT fail security.password.$1 Was able to brute force using dictionary." > $RESULT_FILE elif [ "$3" == "skip_no_host" ]; then - echo "RESULT skip security.passwords.$1 Unable to connect to host." > $RESULT_FILE + echo "RESULT skip security.password.$1 Unable to connect to host." > $RESULT_FILE elif [ "$3" == "skip_no_port" ]; then - echo "RESULT skip security.passwords.$1 Port $2 not open on target device." > $RESULT_FILE + echo "RESULT skip security.password.$1 Port $2 not open on target device." > $RESULT_FILE elif [ "$3" == "skip_ncrack_error" ]; then - echo "RESULT skip security.passwords.$1 Skipping due to brute force issue with ncrack. Please see log." > $RESULT_FILE + echo "RESULT skip security.password.$1 Skipping due to brute force issue with ncrack. Please see log." > $RESULT_FILE elif [ "$3" == "skip_medusa_error" ]; then - echo "RESULT skip security.passwords.$1 Skipping due to brute force issue with medusa. Please see log." > $RESULT_FILE + echo "RESULT skip security.password.$1 Skipping due to brute force issue with medusa. Please see log." > $RESULT_FILE elif [ "$3" == "skip_http_error" ]; then - echo "RESULT skip security.passwords.$1 Skipping due to http(s) server not having authentication method." > $RESULT_FILE + echo "RESULT skip security.password.$1 Skipping due to http(s) server not having authentication method." > $RESULT_FILE fi } diff --git a/subset/security/tls.module_manifest.json b/subset/security/tls.module_manifest.json index 881e4c54ef..3228fb49bf 100644 --- a/subset/security/tls.module_manifest.json +++ b/subset/security/tls.module_manifest.json @@ -1,17 +1,17 @@ { - "security.tlsv1.server": { + "security.tls.v1_server": { "description": "Verify the device supports at least TLS 1.0 (as a server)" }, - "security.tlsv1_2.server": { + "security.tls.v1_2_server": { "description": "Verify the device supports TLS 1.2 (as a server)" }, - "security.tlsv1_3.server": { + "security.tls.v1_3_server": { "description": "Verify the device supports TLS 1.3 (as a server)" }, - "security.tlsv1_2.client": { - "desc": "Verify the device supports at least TLS 1.2 (as a client)" + "security.tls.v1_2_client": { + "description": "Verify the device supports at least TLS 1.2 (as a client)" }, - "security.tlsv1_3.client": { - "desc": "Verify the device supports at least TLS 1.3 (as a client)" + "security.tls.v1_3_client": { + "description": "Verify the device supports at least TLS 1.3 (as a client)" } } \ No newline at end of file diff --git a/subset/security/tlstest/src/main/java/Client.java b/subset/security/tlstest/src/main/java/Client.java index 756a8b3db6..2382891a69 100644 --- a/subset/security/tlstest/src/main/java/Client.java +++ b/subset/security/tlstest/src/main/java/Client.java @@ -281,15 +281,15 @@ private boolean isCipherSupported(List cipherList, String cipher ){ private void passClient(boolean handshake,boolean cipherValid,String tlsVersion) { if (handshake && cipherValid) { clientReport += - "\nRESULT pass security.tlsv" + "\nRESULT pass security.tls.v" + tlsVersion.replace(".","_") - + ".client" + + "_client" + " Client/Server completed handshake and ECDH/ECDSA supported ciphers."; } else { clientReport += - "\nRESULT fail security.tlsv" + "\nRESULT fail security.tls.v" + tlsVersion.replace(".","_") - + ".client"; + + "_client"; clientReport+=handshake?"":" No completed SSL/TLS handshake detected."; clientReport+=cipherValid?"":" Cipher could not be validated."; } @@ -297,9 +297,9 @@ private void passClient(boolean handshake,boolean cipherValid,String tlsVersion) private void skipClient(String skipMessage,String tlsVersion) { clientReport += - "\nRESULT skip security.tlsv" + "\nRESULT skip security.tls.v" + tlsVersion.replace(".","_") - + ".client " + + "_client " + skipMessage; } diff --git a/subset/security/tlstest/src/main/java/ResultGenerator.java b/subset/security/tlstest/src/main/java/ResultGenerator.java index 33b8ff706b..79c7c6bb65 100644 --- a/subset/security/tlstest/src/main/java/ResultGenerator.java +++ b/subset/security/tlstest/src/main/java/ResultGenerator.java @@ -22,9 +22,9 @@ else if(tlsServer.getServerResult() == TestResult.SKIP private static String generatePassResults(Server server){ String report = ""; report += - "\nRESULT pass security.tlsv" + "\nRESULT pass security.tls.v" + server.getTlsVersion().replace(".","_") - + ".server " + + "_server " + getKeyLengthStatusMessage(server.getServerKeyLengthStatus()) + " " + getCertStatusMessage(server.getServerCertStatus()) + " " + getSignatureMessage(server.getSigStatus()) + " " @@ -35,9 +35,9 @@ private static String generatePassResults(Server server){ private static String generateFailResults(Server server){ String report = ""; report += - "\nRESULT fail security.tlsv" + "\nRESULT fail security.tls.v" + server.getTlsVersion().replace(".","_") - + ".server"; + + "_server"; if(server.getServerKeyLengthStatus() == KeyLengthStatus.PUBLIC_KEY_INVALID_LENGTH){ report+=" " + getKeyLengthStatusMessage(server.getServerKeyLengthStatus()); } @@ -55,9 +55,9 @@ private static String generateFailResults(Server server){ private static String generateServerSkipResult(Server server) { String report = - "\nRESULT skip security.tlsv" + "\nRESULT skip security.tls.v" + server.getTlsVersion().replace(".","_") - + ".server" + + "_server" + " IOException unable to connect to server."; return report; } diff --git a/subset/switches/module_manifest.json b/subset/switches/module_manifest.json index 2794ab49e1..47812cd36e 100644 --- a/subset/switches/module_manifest.json +++ b/subset/switches/module_manifest.json @@ -1,11 +1,11 @@ { - "connection.port_link" : { + "connection.switch.port_link" : { "description" : "Connect the device to the network switch. Check the device and the switch for the green connection light & no errors" }, - "connection.port_speed" : { + "connection.switch.port_speed" : { "description" : "Verify the device auto-negotiates connection speed" }, - "connection.port_duplex" : { + "connection.switch.port_duplex" : { "description" : "Verify the device supports full duplex" }, "poe.switch.power" : { diff --git a/subset/switches/readme.md b/subset/switches/readme.md index af54891a89..23c8a63d39 100644 --- a/subset/switches/readme.md +++ b/subset/switches/readme.md @@ -73,19 +73,19 @@ Example of all necessary parameters in the system.conf related to physical switc # Make sure docker's ip range doesn't conflict with that of the switch. Default docker ip range is 172.17.0.0/16. Default switch ip range is 192.168.0.0/16 usi_setup.url=172.17.0.1:5000 -## Conditions for connection.port_duplex +## Conditions for connection.switch.port_duplex - pass -> If the duplex mode is detected as full - fail -> If the duplex mode is detected but not full or if the duplex mode cannot be detected -## Conditions for connection.port_link +## Conditions for connection.switch.port_link - pass -> If the status of the port the device is plugged into is determined to be in a connected or "UP" state. - fail -> If the status of the port the device is plugged into is determined to be in a disconnected or "DOWN" state. -## Conditions for connection.port_speed +## Conditions for connection.switch.port_speed - pass -> If the speed of the port is auto-negotiated and determiend to be higher than 10 MBPS - fail ->If the speed of the port is determined to be <= 10MBPS -## Conditions for poe.power +## Conditions for poe.switch.power - pass -> If the a PoE device is connected and power has been detected and supplied to the device. - fail -> If the a PoE device is connected and *NO* power has been detected and supplied to the device. Failure also occurs if the switch reports either a faulty PoE state or is denying power to the device. This can also fail if associated power data fails to resolve correctly during switch interrogation. - skip -> If the PoE option is disabled in the device module_config.json or if the switch reports no PoE support. diff --git a/subset/switches/src/main/java/switchtest/SwitchTest.java b/subset/switches/src/main/java/switchtest/SwitchTest.java index 79597081c3..8f8cf237ff 100644 --- a/subset/switches/src/main/java/switchtest/SwitchTest.java +++ b/subset/switches/src/main/java/switchtest/SwitchTest.java @@ -52,7 +52,7 @@ protected void captureResult(String test, Result result, String additional) { } protected void testLink(InterfaceResponse interfaceResponse) { - final String testName = "connection.port_link"; + final String testName = "connection.switch.port_link"; if (interfaceResponse.getLinkStatus() == LinkStatus.State.UP) { captureResult(testName, Result.PASS, "Link is up"); } else { @@ -61,7 +61,7 @@ protected void testLink(InterfaceResponse interfaceResponse) { } protected void testSpeed(InterfaceResponse interfaceResponse) { - final String testName = "connection.port_speed"; + final String testName = "connection.switch.port_speed"; int linkSpeed = interfaceResponse.getLinkSpeed(); if (linkSpeed > 0) { if (linkSpeed >= 10) { @@ -77,7 +77,7 @@ protected void testSpeed(InterfaceResponse interfaceResponse) { } protected void testDuplex(InterfaceResponse interfaceResponse) { - final String testName = "connection.port_duplex"; + final String testName = "connection.switch.port_duplex"; String duplex = interfaceResponse.getDuplex(); if (duplex != null) { if (duplex.equals("full")) { diff --git a/subset/switches/test_switch b/subset/switches/test_switch index 1d58ab9ca2..1e02e63509 100755 --- a/subset/switches/test_switch +++ b/subset/switches/test_switch @@ -26,7 +26,6 @@ if [ -n "$LOCAL_IP" ]; then echo Switch test with model $SWITCH_MODEL echo Switch test with ip:port $SWITCH_IP:$TARGET_PORT echo Switch test with username:password $SWITCH_USERNAME:$SWITCH_PASSWORD - # It may take up to 40 pings for it to go through for Cisco switch. Root cause is still unknown atm. ping -n -c 100 $SWITCH_IP POE_ENABLED=`jq -r .modules.switch.poe.enabled $MODULE_CONFIG` @@ -47,22 +46,22 @@ else SUMMARY="No local IP has been set, check system config" write_out_result $REPORT \ - "connection.port_link" \ - "$(jq -r '.["connection.port_link"].description' $MANIFEST)" \ + "connection.switch.port_link" \ + "$(jq -r '.["connection.switch.port_link"].description' $MANIFEST)" \ "$SKIP_REASON" \ - "RESULT $RESULT connection.port_link $SUMMARY" + "RESULT $RESULT connection.switch.port_link $SUMMARY" write_out_result $REPORT \ - "connection.port_speed" \ - "$(jq -r '.["connection.port_speed"].description' $MANIFEST)" \ + "connection.switch.port_speed" \ + "$(jq -r '.["connection.switch.port_speed"].description' $MANIFEST)" \ "$SKIP_REASON" \ - "RESULT $RESULT connection.port_speed $SUMMARY" + "RESULT $RESULT connection.switch.port_speed $SUMMARY" write_out_result $REPORT \ - "connection.port_duplex" \ - "$(jq -r '.["connection.port_duplex"].description' $MANIFEST)" \ + "connection.switch.port_duplex" \ + "$(jq -r '.["connection.switch.port_duplex"].description' $MANIFEST)" \ "$SKIP_REASON" \ - "RESULT $RESULT connection.port_duplex $SUMMARY" + "RESULT $RESULT connection.switch.port_duplex $SUMMARY" write_out_result $REPORT \ "poe.switch.power" \ diff --git a/testing/test_aux.out b/testing/test_aux.out index c3a19e54d2..ef7b025daf 100644 --- a/testing/test_aux.out +++ b/testing/test_aux.out @@ -2,72 +2,72 @@ Running testing/test_aux.sh Aux Tests RESULT pass base.startup.dhcp RESULT skip base.switch.ping No local IP has been set, check system config -RESULT pass base.target.ping target reached +RESULT pass connection.base.target_ping target reached RESULT pass base.startup.ntp Correct NTP server address RESULT skip base.startup.dns No dns traffic detected RESULT pass base.startup.dhcp RESULT skip base.switch.ping No local IP has been set, check system config -RESULT pass base.target.ping target reached +RESULT pass connection.base.target_ping target reached RESULT fail base.startup.ntp Invalid NTP server address RESULT fail base.startup.dns Invalid DNS server address RESULT pass base.startup.dhcp RESULT skip base.switch.ping No local IP has been set, check system config -RESULT pass base.target.ping target reached +RESULT pass connection.base.target_ping target reached RESULT skip base.startup.ntp No NTP traffic detected RESULT pass base.startup.dns Correct DNS server address -RESULT skip protocol.bacnet.version Bacnet device not found. -RESULT fail protocol.bacnet.pic PICS file defined however a BACnet device was not found. -RESULT info protocol.bacnet.version Protocol version: 1 -RESULT skip protocol.bacnet.pic BACnet device found, but pics.csv not found in device type directory. -RESULT info protocol.bacnet.version Protocol version: 1 -RESULT pass protocol.bacnet.pic The devices matches the PICS -RESULT skip security.tlsv1.server IOException unable to connect to server. -RESULT skip security.tlsv1_2.client No client initiated TLS communication detected -RESULT skip security.tlsv1_2.server IOException unable to connect to server. -RESULT skip security.tlsv1_3.client No client initiated TLS communication detected -RESULT skip security.tlsv1_3.server IOException unable to connect to server. -RESULT fail security.tlsv1.server Certificate is expired. Certificate has not been signed by a CA. -RESULT pass security.tlsv1_2.client Client/Server completed handshake and ECDH/ECDSA supported ciphers. -RESULT fail security.tlsv1_2.server Certificate is expired. Certificate has not been signed by a CA. -RESULT pass security.tlsv1_3.client Client/Server completed handshake and ECDH/ECDSA supported ciphers. -RESULT fail security.tlsv1_3.server Certificate is expired. Certificate has not been signed by a CA. -RESULT fail security.tlsv1.server Certificate has not been signed by a CA. Cipher Valid. -RESULT pass security.tlsv1_2.client Client/Server completed handshake and ECDH/ECDSA supported ciphers. -RESULT fail security.tlsv1_2.server Certificate has not been signed by a CA. Cipher Valid. -RESULT pass security.tlsv1_3.client Client/Server completed handshake and ECDH/ECDSA supported ciphers. -RESULT fail security.tlsv1_3.server Certificate has not been signed by a CA. -RESULT skip security.passwords.http Port 80 not open on target device. -RESULT skip security.passwords.https Port 443 not open on target device. -RESULT skip security.passwords.ssh Port 22 not open on target device. -RESULT skip security.passwords.telnet Port 23 not open on target device. -RESULT fail security.passwords.http Was able to brute force using dictionary. -RESULT fail security.passwords.https Was able to brute force using dictionary. -RESULT fail security.passwords.ssh Was able to brute force using dictionary. -RESULT fail security.passwords.telnet Was able to brute force using dictionary. -RESULT pass security.passwords.http Was not able to brute force using dictionary. -RESULT pass security.passwords.https Was not able to brute force using dictionary. -RESULT pass security.passwords.ssh Was not able to brute force using dictionary. -RESULT pass security.passwords.telnet Was not able to brute force using dictionary. -RESULT skip security.firmware Could not retrieve a firmware version with nmap. Check bacnet port. -RESULT pass security.firmware version found: ?\xFF\xFF\x19,>u\x08\x00no -RESULT pass connection.min_send ARP packets received. Data packets were sent at a frequency of less than 5 minutes -RESULT info communication.type.broadcast Broadcast packets received. Unicast packets received. -RESULT pass connection.network.ntp_support Using NTPv4. -RESULT pass connection.network.ntp_update Device clock synchronized. -RESULT fail connection.mac_oui Manufacturer prefix not found! -RESULT skip connection.dns.hostname_connect Device did not send any DNS requests -RESULT pass connection.min_send ARP packets received. Data packets were sent at a frequency of less than 5 minutes -RESULT info communication.type.broadcast Broadcast packets received. Unicast packets received. -RESULT fail connection.network.ntp_support Not using NTPv4. -RESULT fail connection.network.ntp_update Device clock not synchronized with local NTP server. -RESULT pass connection.mac_oui Manufacturer: Google found for address 3c:5a:b4:1e:8f:0b -RESULT fail connection.dns.hostname_connect Device sent DNS requests to servers other than the DHCP provided server -RESULT pass connection.min_send ARP packets received. Data packets were sent at a frequency of less than 5 minutes -RESULT info communication.type.broadcast Broadcast packets received. Unicast packets received. -RESULT skip connection.network.ntp_support No NTP packets received. -RESULT skip connection.network.ntp_update Not enough NTP packets received. -RESULT pass connection.mac_oui Manufacturer: Google found for address 3c:5a:b4:1e:8f:0a -RESULT pass connection.dns.hostname_connect Device sends DNS requests and resolves host names +RESULT skip protocol.bacext.version Bacnet device not found. +RESULT fail protocol.bacext.pic PICS file defined however a BACnet device was not found. +RESULT info protocol.bacext.version Protocol version: 1 +RESULT skip protocol.bacext.pic BACnet device found, but pics.csv not found in device type directory. +RESULT info protocol.bacext.version Protocol version: 1 +RESULT pass protocol.bacext.pic The devices matches the PICS +RESULT skip security.tls.v1_2_client No client initiated TLS communication detected +RESULT skip security.tls.v1_2_server IOException unable to connect to server. +RESULT skip security.tls.v1_3_client No client initiated TLS communication detected +RESULT skip security.tls.v1_3_server IOException unable to connect to server. +RESULT skip security.tls.v1_server IOException unable to connect to server. +RESULT pass security.tls.v1_2_client Client/Server completed handshake and ECDH/ECDSA supported ciphers. +RESULT fail security.tls.v1_2_server Certificate is expired. Certificate has not been signed by a CA. +RESULT pass security.tls.v1_3_client Client/Server completed handshake and ECDH/ECDSA supported ciphers. +RESULT fail security.tls.v1_3_server Certificate is expired. Certificate has not been signed by a CA. +RESULT fail security.tls.v1_server Certificate is expired. Certificate has not been signed by a CA. +RESULT pass security.tls.v1_2_client Client/Server completed handshake and ECDH/ECDSA supported ciphers. +RESULT fail security.tls.v1_2_server Certificate has not been signed by a CA. Cipher Valid. +RESULT pass security.tls.v1_3_client Client/Server completed handshake and ECDH/ECDSA supported ciphers. +RESULT fail security.tls.v1_3_server Certificate has not been signed by a CA. +RESULT fail security.tls.v1_server Certificate has not been signed by a CA. Cipher Valid. +RESULT skip security.password.http Port 80 not open on target device. +RESULT skip security.password.https Port 443 not open on target device. +RESULT skip security.password.ssh Port 22 not open on target device. +RESULT skip security.password.telnet Port 23 not open on target device. +RESULT fail security.password.http Was able to brute force using dictionary. +RESULT fail security.password.https Was able to brute force using dictionary. +RESULT fail security.password.ssh Was able to brute force using dictionary. +RESULT fail security.password.telnet Was able to brute force using dictionary. +RESULT pass security.password.http Was not able to brute force using dictionary. +RESULT pass security.password.https Was not able to brute force using dictionary. +RESULT pass security.password.ssh Was not able to brute force using dictionary. +RESULT pass security.password.telnet Was not able to brute force using dictionary. +RESULT skip security.discover.firmware Could not retrieve a firmware version with nmap. Check bacnet port. +RESULT pass security.discover.firmware version found: ?\xFF\xFF\x19,>u\x08\x00no +RESULT pass communication.network.min_send ARP packets received. Data packets were sent at a frequency of less than 5 minutes +RESULT info communication.network.type Broadcast packets received. Unicast packets received. +RESULT pass ntp.network.ntp_support Using NTPv4. +RESULT pass ntp.network.ntp_update Device clock synchronized. +RESULT fail connection.network.mac_oui Manufacturer prefix not found! +RESULT skip dns.network.hostname_resolution Device did not send any DNS requests +RESULT pass communication.network.min_send ARP packets received. Data packets were sent at a frequency of less than 5 minutes +RESULT info communication.network.type Broadcast packets received. Unicast packets received. +RESULT fail ntp.network.ntp_support Not using NTPv4. +RESULT fail ntp.network.ntp_update Device clock not synchronized with local NTP server. +RESULT pass connection.network.mac_oui Manufacturer: Google found for address 3c:5a:b4:1e:8f:0b +RESULT fail dns.network.hostname_resolution Device sent DNS requests to servers other than the DHCP provided server +RESULT pass communication.network.min_send ARP packets received. Data packets were sent at a frequency of less than 5 minutes +RESULT info communication.network.type Broadcast packets received. Unicast packets received. +RESULT skip ntp.network.ntp_support No NTP packets received. +RESULT skip ntp.network.ntp_update Not enough NTP packets received. +RESULT pass connection.network.mac_oui Manufacturer: Google found for address 3c:5a:b4:1e:8f:0a +RESULT pass dns.network.hostname_resolution Device sends DNS requests and resolves host names dhcp requests 1 1 1 1 3c5ab41e8f0a: [] 3c5ab41e8f0b: ['3c5ab41e8f0b:ping:TimeoutError'] diff --git a/testing/test_base.out b/testing/test_base.out index 2dc7e06c5e..1e6a149ff4 100644 --- a/testing/test_base.out +++ b/testing/test_base.out @@ -32,7 +32,7 @@ Overall device result PASS |---|---|---|---|---| |pass|base.startup.dhcp|Other|Other|| |skip|base.switch.ping|Other|Other|No local IP has been set, check system config| -|pass|base.target.ping|Other|Other|target reached| +|pass|connection.base.target_ping|Other|Other|target reached| |pass|security.nmap.http|Other|Other|No running http servers have been found.| |pass|security.nmap.ports|Other|Other|Only allowed ports found open.| @@ -78,13 +78,13 @@ See log above RESULT skip base.switch.ping No local IP has been set, check system config -------------------- -base.target.ping +connection.base.target_ping -------------------- Attempt to ping the Device Under Test -------------------- See log above -------------------- -RESULT pass base.target.ping target reached +RESULT pass connection.base.target_ping target reached ``` diff --git a/testing/test_dhcp.sh b/testing/test_dhcp.sh index 0370eb5c6b..542d4b64f2 100755 --- a/testing/test_dhcp.sh +++ b/testing/test_dhcp.sh @@ -100,8 +100,8 @@ for iface in $(seq 1 6); do ip_triggers=$(fgrep done $ip_file | wc -l) long_triggers=$(fgrep long $ip_file | wc -l) num_ips=$(cat $ip_file | cut -d ' ' -f 1 | sort | uniq | wc -l) - dhcp_change=$(cat $report_file | fgrep 'pass connection.network.dhcp_change' | wc -l) - ip_change=$(cat $report_file | fgrep 'pass connection.dhcp.ip_change' | wc -l) + dhcp_change=$(cat $report_file | fgrep 'pass connection.ipaddr.disconnect_ip_change' | wc -l) + ip_change=$(cat $report_file | fgrep 'pass connection.ipaddr.ip_change' | wc -l) echo Found $ip_triggers ip triggers and $long_triggers long ip responses. if [ $iface == 6 ]; then device_dhcp_timeouts=$(cat inst/cmdrun.log | fgrep 'DHCP times out after 120s lease time' | fgrep "ipaddr_ipaddr0$iface" | wc -l) diff --git a/testing/test_modules.out b/testing/test_modules.out index 2d73387cf4..57492070f2 100644 --- a/testing/test_modules.out +++ b/testing/test_modules.out @@ -1,23 +1,23 @@ Running testing/test_modules.sh Base Tests Testing tls alt -RESULT skip security.tlsv1.server IOException unable to connect to server. -RESULT skip security.tlsv1_2.client No client initiated TLS communication detected -RESULT skip security.tlsv1_2.server IOException unable to connect to server. -RESULT skip security.tlsv1_3.client No client initiated TLS communication detected -RESULT skip security.tlsv1_3.server IOException unable to connect to server. +RESULT skip security.tls.v1_2_client No client initiated TLS communication detected +RESULT skip security.tls.v1_2_server IOException unable to connect to server. +RESULT skip security.tls.v1_3_client No client initiated TLS communication detected +RESULT skip security.tls.v1_3_server IOException unable to connect to server. +RESULT skip security.tls.v1_server IOException unable to connect to server. Testing tls alt tls -RESULT pass security.tlsv1.server Certificate public key length is >= 224. Certificate active for current date. Certificate has been signed by a CA. Cipher Valid. -RESULT skip security.tlsv1_2.client No client initiated TLS communication detected -RESULT pass security.tlsv1_2.server Certificate public key length is >= 224. Certificate active for current date. Certificate has been signed by a CA. Cipher Valid. -RESULT skip security.tlsv1_3.client No client initiated TLS communication detected -RESULT pass security.tlsv1_3.server Certificate public key length is >= 224. Certificate active for current date. Certificate has been signed by a CA. Cipher check not required. +RESULT skip security.tls.v1_2_client No client initiated TLS communication detected +RESULT pass security.tls.v1_2_server Certificate public key length is >= 224. Certificate active for current date. Certificate has been signed by a CA. Cipher Valid. +RESULT skip security.tls.v1_3_client No client initiated TLS communication detected +RESULT pass security.tls.v1_3_server Certificate public key length is >= 224. Certificate active for current date. Certificate has been signed by a CA. Cipher check not required. +RESULT pass security.tls.v1_server Certificate public key length is >= 224. Certificate active for current date. Certificate has been signed by a CA. Cipher Valid. Testing tls alt expiredtls -RESULT fail security.tlsv1.server Certificate is expired. Certificate has not been signed by a CA. -RESULT skip security.tlsv1_2.client No client initiated TLS communication detected -RESULT fail security.tlsv1_2.server Certificate is expired. Certificate has not been signed by a CA. -RESULT skip security.tlsv1_3.client No client initiated TLS communication detected -RESULT fail security.tlsv1_3.server Certificate is expired. Certificate has not been signed by a CA. +RESULT skip security.tls.v1_2_client No client initiated TLS communication detected +RESULT fail security.tls.v1_2_server Certificate is expired. Certificate has not been signed by a CA. +RESULT skip security.tls.v1_3_client No client initiated TLS communication detected +RESULT fail security.tls.v1_3_server Certificate is expired. Certificate has not been signed by a CA. +RESULT fail security.tls.v1_server Certificate is expired. Certificate has not been signed by a CA. Testing ssh RESULT skip security.ssh.version Device is not running an SSH server Testing ssh ssh diff --git a/testing/unit/mock/test_combine_reports/report_1.json b/testing/unit/mock/test_combine_reports/report_1.json index e7e5da50de..f7b9b95ea7 100644 --- a/testing/unit/mock/test_combine_reports/report_1.json +++ b/testing/unit/mock/test_combine_reports/report_1.json @@ -18,9 +18,9 @@ "expected": "Other", "result_description": "target " }, - "base.target.ping": { + "connection.base.target_ping": { "result": "fail", - "test_name": "base.target.ping", + "test_name": "connection.base.target_ping", "module_name": "ping", "category": "Other", "expected": "Other", diff --git a/testing/unit/mock/test_combine_reports/report_2.json b/testing/unit/mock/test_combine_reports/report_2.json index 60351416fc..dac4186e6d 100644 --- a/testing/unit/mock/test_combine_reports/report_2.json +++ b/testing/unit/mock/test_combine_reports/report_2.json @@ -18,9 +18,9 @@ "expected": "Other", "result_description": "target " }, - "base.target.ping": { + "connection.base.target_ping": { "result": "fail", - "test_name": "base.target.ping", + "test_name": "connection.base.target_ping", "module_name": "ping", "category": "Other", "expected": "Other", diff --git a/testing/unit/test_combine_reports.py b/testing/unit/test_combine_reports.py index d7b944de40..5e9069fc41 100644 --- a/testing/unit/test_combine_reports.py +++ b/testing/unit/test_combine_reports.py @@ -100,7 +100,7 @@ def custom_open(report, mode=None): 'tests': { 'base.startup.dhcp': {'pass': 2}, 'base.switch.ping': {'pass': 1, 'fail': 1}, - 'base.target.ping': {'fail': 2} + 'connection.base.target_ping': {'fail': 2} }, 'categories': { 'Other1': {'pass': 1}, 'Other': {'pass': 2, 'fail': 3} From 24d85e9a80082774d9bacf654d2d5940a2357cd4 Mon Sep 17 00:00:00 2001 From: Yufeng Duan <55268016+didovesei@users.noreply.github.com> Date: Tue, 20 Oct 2020 14:49:38 -0700 Subject: [PATCH 178/212] Add packaging files (#684) --- debian/changelog | 5 ++ debian/compat | 1 + debian/control | 25 ++++++ debian/copyright | 197 +++++++++++++++++++++++++++++++++++++++++++++++ debian/rules | 12 +++ setup.cfg | 28 +++++++ setup.py | 10 +++ 7 files changed, 278 insertions(+) create mode 100644 debian/changelog create mode 100644 debian/compat create mode 100644 debian/control create mode 100644 debian/copyright create mode 100755 debian/rules create mode 100644 setup.cfg create mode 100644 setup.py diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000000..136d496dbb --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +daq (1.9.11-1) UNRELEASED; urgency=low + + * Initial release. + + -- Yufeng Duan <> Tue, 20 Oct 2020 05:33:11 +0000 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000000..b4de394767 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +11 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000000..3eaa841186 --- /dev/null +++ b/debian/control @@ -0,0 +1,25 @@ +Source: daq +Section: python +Priority: optional +Maintainer: Faucet Maintainers +Build-Depends: debhelper (>=11~), + dh-python, + python3-all, + python3-setuptools, + python3-pbr (>= 1.9), +Standards-Version: 4.1.4 +Homepage: https://github.com/faucetsdn/forch +X-Python3-Version: >= 3.6 + +Package: python3-daq +Architecture: all +# TODO Need to audit the imported modules to complete dependancies +Depends: python3-grpcio, + python3-protobuf, + python3-yaml +Description: DAQ is a framework designed to test and operate IoT devices in an enterprise IoT environment. + +Package: daq +Architecture: all +Depends: python3-forch +Description: DAQ is a framework designed to test and operate IoT devices in an enterprise IoT environment. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000000..51f865305e --- /dev/null +++ b/debian/copyright @@ -0,0 +1,197 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: daq +Source: https://github.com/faucetsdn/daq + +License: Apache-2.0 + . + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + . + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + . + 1. Definitions. + . + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + . + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + . + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + . + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + . + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + . + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + . + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + . + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + . + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + . + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + . + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + . + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + . + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + . + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + . + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + . + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + . + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + . + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + . + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + . + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + . + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + . + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + . + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + . + END OF TERMS AND CONDITIONS + . + . + Copyright 2017 The Contributors + . + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + . + http://www.apache.org/licenses/LICENSE-2.0 + . + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000000..139425684c --- /dev/null +++ b/debian/rules @@ -0,0 +1,12 @@ +#!/usr/bin/make -f + +export PYBUILD_NAME=daq + +%: + dh $@ --with python3 --buildsystem=pybuild + +override_dh_strip: + dh_strip --no-automatic-dbgsym + +# TODO skip test until test_modules directory is renamed in the source +override_dh_auto_test: diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000000..1202cd3302 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,28 @@ +[metadata] +name = daq +summary = DAQ is a framework designed to test and operate IoT devices in an enterprise IoT environment. +license = Apache-2 +platform = any +classifier = + Development Status :: 5 - Production/Stable + License :: OSI Approved :: Apache Software License + Topic :: System :: Networking + Natural Language :: English + Programming Language :: Python + Programming Language :: Python :: 3.6 + Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 + Operating System :: Unix +keywords = + openflow + openvswitch + ryu + +[files] +packages = + daq + +[pytype] +python_version = 3.6 +pythonpath = + .: diff --git a/setup.py b/setup.py new file mode 100644 index 0000000000..8a548bb048 --- /dev/null +++ b/setup.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python3 + +from __future__ import absolute_import +import setuptools + +setuptools.setup( + name='daq', + setup_requires=['pbr>=1.9', 'setuptools>=17.1'], + pbr=True +) From 79d8d51700b7dafbc0b8bfceb6067ef785cb22b4 Mon Sep 17 00:00:00 2001 From: Trevor Pering Date: Wed, 21 Oct 2020 22:58:48 -0700 Subject: [PATCH 179/212] Add minimal setup_docker --- bin/setup_docker | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100755 bin/setup_docker diff --git a/bin/setup_docker b/bin/setup_docker new file mode 100755 index 0000000000..132d4b0109 --- /dev/null +++ b/bin/setup_docker @@ -0,0 +1,7 @@ +#!/bin/bash -e +# +# Setup daq for running inside of a docker container. +# + +echo Hello. + From 788592b7e0982e422d6075b6918107582c24a338 Mon Sep 17 00:00:00 2001 From: Yufeng Duan <55268016+didovesei@users.noreply.github.com> Date: Thu, 22 Oct 2020 11:37:56 -0700 Subject: [PATCH 180/212] Add gRPC client to send device result to server (#656) --- .pylintrc | 2 + daq/device_report_client.py | 30 ++++ daq/network.py | 32 +++- daq/runner.py | 14 ++ etc/FORCH_VERSION | 2 +- firebase/public/protos.hash | 2 +- firebase/public/protos.html | 35 ++++ libs/proto/system_config_pb2.py | 208 +++++++++++++--------- proto/system_config.proto | 11 ++ testing/test_aux.out | 3 + testing/unit/test_device_report_client.py | 65 +++++++ 11 files changed, 314 insertions(+), 90 deletions(-) create mode 100644 daq/device_report_client.py create mode 100644 testing/unit/test_device_report_client.py diff --git a/.pylintrc b/.pylintrc index 918f56efe9..599129aca3 100644 --- a/.pylintrc +++ b/.pylintrc @@ -3,3 +3,5 @@ good-names=fd,e output-format=parseable disable=F0401,R0201,R0902,W0703,I0011,W0403,E1102,R0903,E0611,W0511,W0613,E1601 max-line-length=100 +ignored-classes= + OrchestrationConfig, DevicesState, PortBehavior diff --git a/daq/device_report_client.py b/daq/device_report_client.py new file mode 100644 index 0000000000..81fd1e72d8 --- /dev/null +++ b/daq/device_report_client.py @@ -0,0 +1,30 @@ +"""gRPC client to send device result""" + +import grpc + +from forch.proto.grpc.device_report_pb2_grpc import DeviceReportStub +from forch.proto.devices_state_pb2 import DevicesState + +from utils import dict_proto + +_SERVER_ADDRESS_DEFAULT = '127.0.0.1' +_SERVER_PORT_DEFAULT = 50051 + + +class DeviceReportClient: + """gRPC client to send device result""" + def __init__(self, server_address=_SERVER_ADDRESS_DEFAULT, server_port=_SERVER_PORT_DEFAULT): + self._initialize_stub(server_address, server_port) + + def _initialize_stub(self, sever_address, server_port): + channel = grpc.insecure_channel(f'{sever_address}:{server_port}') + self._stub = DeviceReportStub(channel) + + def send_device_result(self, mac, device_result): + """Send device result of a device to server""" + devices_state = { + 'device_mac_behaviors': { + mac: {'port_behavior': device_result} + } + } + self._stub.ReportDevicesState(dict_proto(devices_state, DevicesState)) diff --git a/daq/network.py b/daq/network.py index 06a668f44c..adc95addca 100644 --- a/daq/network.py +++ b/daq/network.py @@ -1,6 +1,8 @@ """Networking module""" import os +from shutil import copyfile +import yaml import logger from topology import FaucetTopology @@ -11,6 +13,7 @@ from mininet import cli as mininet_cli from mininet import util as mininet_util from forch import faucetizer +from forch.proto.forch_configuration_pb2 import OrchestrationConfig LOGGER = logger.get_logger('network') @@ -37,6 +40,7 @@ class TestNetwork: MAX_INTERNAL_DPID = 100 DEFAULT_OF_PORT = 6653 _CTRL_PRI_IFACE = 'ctrl-pri' + INTERMEDIATE_FAUCET_FILE = "inst/faucet_intermediate.yaml" OUTPUT_FAUCET_FILE = "inst/faucet.yaml" def __init__(self, config): @@ -52,7 +56,9 @@ def __init__(self, config): self.ext_ofpt = int(switch_setup.get('lo_port', self.DEFAULT_OF_PORT)) self.ext_loip = switch_setup.get('mods_addr') self.switch_links = {} - self.faucitizer = faucetizer.Faucetizer(None, None) + orch_config = OrchestrationConfig() + self.faucitizer = faucetizer.Faucetizer( + orch_config, self.INTERMEDIATE_FAUCET_FILE, self.OUTPUT_FAUCET_FILE) # pylint: disable=too-many-arguments def add_host(self, name, cls=DAQHost, ip_addr=None, env_vars=None, vol_maps=None, @@ -166,8 +172,7 @@ def initialize(self): self.topology.start() LOGGER.info("Initializing faucitizer...") - self.faucitizer.process_faucet_config(self.topology.get_network_topology()) - faucetizer.write_behavioral_config(self.faucitizer, self.OUTPUT_FAUCET_FILE) + self._generate_behavioral_config() target_ip = "127.0.0.1" LOGGER.debug("Adding controller at %s", target_ip) @@ -190,16 +195,29 @@ def direct_port_traffic(self, target_mac, port, target): LOGGER.info('Directing traffic for %s on port %s to %s', target_mac, port, dest) # TODO: Convert this to use faucitizer to change vlan self.topology.direct_port_traffic(target_mac, port, target) - self.faucitizer.process_faucet_config(self.topology.get_network_topology()) - faucetizer.write_behavioral_config(self.faucitizer, self.OUTPUT_FAUCET_FILE) + self._generate_behavioral_config() + + def _generate_behavioral_config(self): + with open(self.INTERMEDIATE_FAUCET_FILE, 'w') as file: + network_topology = self.topology.get_network_topology() + yaml.safe_dump(network_topology, file) + + # TODO: temporary fix. Remove after Forch behavior is changed + dir_name = os.path.dirname(self.OUTPUT_FAUCET_FILE) + for included_file_name in network_topology.get('include', []): + base_name, ext = os.path.splitext(included_file_name) + src_name = os.path.join(dir_name, included_file_name) + dst_name = os.path.join(dir_name, base_name + '_augmented' + ext) + copyfile(src_name, dst_name) + + self.faucitizer.reload_structural_config(self.INTERMEDIATE_FAUCET_FILE) def direct_vlan_traffic(self, port_set, vlan): """Modify gateway set's vlan to match triggering vlan""" LOGGER.info('Directing traffic for port set %s to vlan %s', port_set, vlan) # TODO: Convert this to use faucitizer to change vlan self.topology.direct_vlan_traffic(port_set, vlan) - self.faucitizer.process_faucet_config(self.topology.get_network_topology()) - faucetizer.write_behavioral_config(self.faucitizer, self.OUTPUT_FAUCET_FILE) + self._generate_behavioral_config() def _attach_switch_interface(self, switch_intf_name): switch_port = self.topology.switch_port() diff --git a/daq/runner.py b/daq/runner.py index d8ced2f1f1..ec79fc4ee5 100644 --- a/daq/runner.py +++ b/daq/runner.py @@ -11,7 +11,10 @@ import pathlib from datetime import datetime, timedelta, timezone +from forch.proto.shared_constants_pb2 import PortBehavior + import configurator +from device_report_client import DeviceReportClient import faucet_event_client import container_gateway @@ -166,6 +169,7 @@ def __init__(self, config): self._system_active = False logging_client = self.gcp.get_logging_client() self.daq_run_id = self._init_daq_run_id() + self._device_result_client = self._init_device_result_client() if logging_client: logger.set_stackdriver_client(logging_client, labels={"daq_run_id": self.daq_run_id}) @@ -195,6 +199,12 @@ def _init_daq_run_id(self): output_stream.write(daq_run_id + '\n') return daq_run_id + def _init_device_result_client(self): + server_port = self.config.get('device_reporting', {}).get('server_port') + if server_port: + return DeviceReportClient(server_port=server_port) + return None + def _send_heartbeat(self): message = { 'name': 'status', @@ -755,6 +765,10 @@ def _target_set_finalize(self, device, result_set, reason): self._linger_exit = 1 self._result_sets[device] = result_set + if self._device_result_client: + self._device_result_client.send_device_result( + device.mac, PortBehavior.passed) + def _target_set_cancel(self, device): target_host = device.host if target_host: diff --git a/etc/FORCH_VERSION b/etc/FORCH_VERSION index 94b357edfe..2c5f97ecff 100644 --- a/etc/FORCH_VERSION +++ b/etc/FORCH_VERSION @@ -1 +1 @@ -0.33 +0.46 diff --git a/firebase/public/protos.hash b/firebase/public/protos.hash index 69b691d3f2..0e00dc5b0c 100644 --- a/firebase/public/protos.hash +++ b/firebase/public/protos.hash @@ -1 +1 @@ -66212fcc5d2f6ebb82cc0b25696a293e387b94cf proto/system_config.proto +57a09959d00dcb455cff637de1ac9aba897a6517 proto/system_config.proto diff --git a/firebase/public/protos.html b/firebase/public/protos.html index 5dba0d178e..03c67b466e 100644 --- a/firebase/public/protos.html +++ b/firebase/public/protos.html @@ -190,6 +190,10 @@

      Table of Contents

      MDaqConfig.InterfacesEntry +
    • + MDeviceReporting +
    • +
    • MInterface
    • @@ -518,6 +522,13 @@

      DaqConfig

      Drop into console mode after test

      + + device_reporting + DeviceReporting + +

      Reporting device result

      + + @@ -587,6 +598,30 @@

      DaqConfig.InterfacesEntry

      +

      DeviceReporting

      +

      Configuration for device result reporting

      + + + + + + + + + + + + + + + + +
      FieldTypeLabelDescription
      server_portint32

      Server port

      + + + + +

      Interface

      Information for faux containers.

      diff --git a/libs/proto/system_config_pb2.py b/libs/proto/system_config_pb2.py index b34b291eb0..14d3092b62 100644 --- a/libs/proto/system_config_pb2.py +++ b/libs/proto/system_config_pb2.py @@ -1,8 +1,7 @@ +# -*- coding: utf-8 -*- # Generated by the protocol buffer compiler. DO NOT EDIT! # source: daq/proto/system_config.proto -import sys -_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) from google.protobuf.internal import enum_type_wrapper from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message @@ -20,7 +19,7 @@ package='', syntax='proto3', serialized_options=None, - serialized_pb=_b('\n\x1d\x64\x61q/proto/system_config.proto\"\xe8\x08\n\tDaqConfig\x12\x18\n\x10site_description\x18\x01 \x01(\t\x12\x18\n\x10monitor_scan_sec\x18\x02 \x01(\x05\x12\x1b\n\x13\x64\x65\x66\x61ult_timeout_sec\x18\x03 \x01(\x05\x12\x12\n\nsettle_sec\x18& \x01(\x05\x12\x11\n\tbase_conf\x18\x04 \x01(\t\x12\x11\n\tsite_path\x18\x05 \x01(\t\x12\x1f\n\x17initial_dhcp_lease_time\x18\x06 \x01(\t\x12\x17\n\x0f\x64hcp_lease_time\x18\x07 \x01(\t\x12\x19\n\x11\x64hcp_response_sec\x18\' \x01(\x05\x12\x1e\n\x16long_dhcp_response_sec\x18\x08 \x01(\x05\x12\"\n\x0cswitch_setup\x18\t \x01(\x0b\x32\x0c.SwitchSetup\x12\x12\n\nhost_tests\x18\x10 \x01(\t\x12\x13\n\x0b\x62uild_tests\x18$ \x01(\x08\x12\x11\n\trun_limit\x18\x11 \x01(\x05\x12\x11\n\tfail_mode\x18\x12 \x01(\x08\x12\x13\n\x0bsingle_shot\x18\" \x01(\x08\x12\x15\n\rresult_linger\x18\x13 \x01(\x08\x12\x0f\n\x07no_test\x18\x14 \x01(\x08\x12\x11\n\tkeep_hold\x18( \x01(\x08\x12\x14\n\x0c\x64\x61q_loglevel\x18\x15 \x01(\t\x12\x18\n\x10mininet_loglevel\x18\x16 \x01(\t\x12\x13\n\x0b\x66inish_hook\x18# \x01(\t\x12\x10\n\x08gcp_cred\x18\x17 \x01(\t\x12\x11\n\tgcp_topic\x18\x18 \x01(\t\x12\x13\n\x0bschema_path\x18\x19 \x01(\t\x12\x11\n\tmud_files\x18\x1a \x01(\t\x12\x14\n\x0c\x64\x65vice_specs\x18\x1b \x01(\t\x12\x13\n\x0btest_config\x18\x1c \x01(\t\x12\x19\n\x11port_debounce_sec\x18\x1d \x01(\x05\x12\x15\n\rtopology_hook\x18\x1e \x01(\t\x12\x17\n\x0f\x64\x65vice_template\x18\x1f \x01(\t\x12\x14\n\x0csite_reports\x18 \x01(\t\x12\x1f\n\x17run_data_retention_days\x18! \x01(\x02\x12.\n\ninterfaces\x18% \x03(\x0b\x32\x1a.DaqConfig.InterfacesEntry\x12/\n\x0b\x66\x61il_module\x18/ \x03(\x0b\x32\x1a.DaqConfig.FailModuleEntry\x12\x1d\n\x15port_flap_timeout_sec\x18\x30 \x01(\x05\x12\x1c\n\tusi_setup\x18\x31 \x01(\x0b\x32\t.USISetup\x12 \n\x0brun_trigger\x18\x32 \x01(\x0b\x32\x0b.RunTrigger\x12\x12\n\ndebug_mode\x18\x33 \x01(\x08\x12\x13\n\x0buse_console\x18\x34 \x01(\x08\x1a=\n\x0fInterfacesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x19\n\x05value\x18\x02 \x01(\x0b\x32\n.Interface:\x02\x38\x01\x1a\x31\n\x0f\x46\x61ilModuleEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"0\n\x08USISetup\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x17\n\x0frpc_timeout_sec\x18\x02 \x01(\x05\"\xf4\x01\n\x0bSwitchSetup\x12\x11\n\tctrl_intf\x18\t \x01(\t\x12\x0f\n\x07ip_addr\x18\x0b \x01(\t\x12\x13\n\x0buplink_port\x18\r \x01(\x05\x12\x0f\n\x07lo_port\x18\x0e \x01(\x05\x12\x10\n\x08\x61lt_port\x18\x10 \x01(\x05\x12\x0f\n\x07lo_addr\x18\x12 \x01(\t\x12\x11\n\tmods_addr\x18\x14 \x01(\t\x12\x0f\n\x07of_dpid\x18) \x01(\t\x12\x11\n\tdata_intf\x18* \x01(\t\x12\x0e\n\x06\x65xt_br\x18+ \x01(\t\x12\r\n\x05model\x18, \x01(\t\x12\x10\n\x08username\x18- \x01(\t\x12\x10\n\x08password\x18. \x01(\t\"2\n\nRunTrigger\x12\x12\n\nvlan_start\x18\x01 \x01(\x05\x12\x10\n\x08vlan_end\x18\x02 \x01(\x05\"\'\n\tInterface\x12\x0c\n\x04opts\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05*U\n\x08\x44HCPMode\x12\n\n\x06NORMAL\x10\x00\x12\r\n\tSTATIC_IP\x10\x01\x12\x0c\n\x08\x45XTERNAL\x10\x02\x12\x11\n\rLONG_RESPONSE\x10\x03\x12\r\n\tIP_CHANGE\x10\x04\x62\x06proto3') + serialized_pb=b'\n\x1d\x64\x61q/proto/system_config.proto\"\x94\t\n\tDaqConfig\x12\x18\n\x10site_description\x18\x01 \x01(\t\x12\x18\n\x10monitor_scan_sec\x18\x02 \x01(\x05\x12\x1b\n\x13\x64\x65\x66\x61ult_timeout_sec\x18\x03 \x01(\x05\x12\x12\n\nsettle_sec\x18& \x01(\x05\x12\x11\n\tbase_conf\x18\x04 \x01(\t\x12\x11\n\tsite_path\x18\x05 \x01(\t\x12\x1f\n\x17initial_dhcp_lease_time\x18\x06 \x01(\t\x12\x17\n\x0f\x64hcp_lease_time\x18\x07 \x01(\t\x12\x19\n\x11\x64hcp_response_sec\x18\' \x01(\x05\x12\x1e\n\x16long_dhcp_response_sec\x18\x08 \x01(\x05\x12\"\n\x0cswitch_setup\x18\t \x01(\x0b\x32\x0c.SwitchSetup\x12\x12\n\nhost_tests\x18\x10 \x01(\t\x12\x13\n\x0b\x62uild_tests\x18$ \x01(\x08\x12\x11\n\trun_limit\x18\x11 \x01(\x05\x12\x11\n\tfail_mode\x18\x12 \x01(\x08\x12\x13\n\x0bsingle_shot\x18\" \x01(\x08\x12\x15\n\rresult_linger\x18\x13 \x01(\x08\x12\x0f\n\x07no_test\x18\x14 \x01(\x08\x12\x11\n\tkeep_hold\x18( \x01(\x08\x12\x14\n\x0c\x64\x61q_loglevel\x18\x15 \x01(\t\x12\x18\n\x10mininet_loglevel\x18\x16 \x01(\t\x12\x13\n\x0b\x66inish_hook\x18# \x01(\t\x12\x10\n\x08gcp_cred\x18\x17 \x01(\t\x12\x11\n\tgcp_topic\x18\x18 \x01(\t\x12\x13\n\x0bschema_path\x18\x19 \x01(\t\x12\x11\n\tmud_files\x18\x1a \x01(\t\x12\x14\n\x0c\x64\x65vice_specs\x18\x1b \x01(\t\x12\x13\n\x0btest_config\x18\x1c \x01(\t\x12\x19\n\x11port_debounce_sec\x18\x1d \x01(\x05\x12\x15\n\rtopology_hook\x18\x1e \x01(\t\x12\x17\n\x0f\x64\x65vice_template\x18\x1f \x01(\t\x12\x14\n\x0csite_reports\x18 \x01(\t\x12\x1f\n\x17run_data_retention_days\x18! \x01(\x02\x12.\n\ninterfaces\x18% \x03(\x0b\x32\x1a.DaqConfig.InterfacesEntry\x12/\n\x0b\x66\x61il_module\x18/ \x03(\x0b\x32\x1a.DaqConfig.FailModuleEntry\x12\x1d\n\x15port_flap_timeout_sec\x18\x30 \x01(\x05\x12\x1c\n\tusi_setup\x18\x31 \x01(\x0b\x32\t.USISetup\x12 \n\x0brun_trigger\x18\x32 \x01(\x0b\x32\x0b.RunTrigger\x12\x12\n\ndebug_mode\x18\x33 \x01(\x08\x12\x13\n\x0buse_console\x18\x34 \x01(\x08\x12*\n\x10\x64\x65vice_reporting\x18\x35 \x01(\x0b\x32\x10.DeviceReporting\x1a=\n\x0fInterfacesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x19\n\x05value\x18\x02 \x01(\x0b\x32\n.Interface:\x02\x38\x01\x1a\x31\n\x0f\x46\x61ilModuleEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"0\n\x08USISetup\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x17\n\x0frpc_timeout_sec\x18\x02 \x01(\x05\"\xf4\x01\n\x0bSwitchSetup\x12\x11\n\tctrl_intf\x18\t \x01(\t\x12\x0f\n\x07ip_addr\x18\x0b \x01(\t\x12\x13\n\x0buplink_port\x18\r \x01(\x05\x12\x0f\n\x07lo_port\x18\x0e \x01(\x05\x12\x10\n\x08\x61lt_port\x18\x10 \x01(\x05\x12\x0f\n\x07lo_addr\x18\x12 \x01(\t\x12\x11\n\tmods_addr\x18\x14 \x01(\t\x12\x0f\n\x07of_dpid\x18) \x01(\t\x12\x11\n\tdata_intf\x18* \x01(\t\x12\x0e\n\x06\x65xt_br\x18+ \x01(\t\x12\r\n\x05model\x18, \x01(\t\x12\x10\n\x08username\x18- \x01(\t\x12\x10\n\x08password\x18. \x01(\t\"2\n\nRunTrigger\x12\x12\n\nvlan_start\x18\x01 \x01(\x05\x12\x10\n\x08vlan_end\x18\x02 \x01(\x05\"\'\n\tInterface\x12\x0c\n\x04opts\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05\"&\n\x0f\x44\x65viceReporting\x12\x13\n\x0bserver_port\x18\x01 \x01(\x05*U\n\x08\x44HCPMode\x12\n\n\x06NORMAL\x10\x00\x12\r\n\tSTATIC_IP\x10\x01\x12\x0c\n\x08\x45XTERNAL\x10\x02\x12\x11\n\rLONG_RESPONSE\x10\x03\x12\r\n\tIP_CHANGE\x10\x04\x62\x06proto3' ) _DHCPMODE = _descriptor.EnumDescriptor( @@ -52,8 +51,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=1554, - serialized_end=1639, + serialized_start=1638, + serialized_end=1723, ) _sym_db.RegisterEnumDescriptor(_DHCPMODE) @@ -76,7 +75,7 @@ _descriptor.FieldDescriptor( name='key', full_name='DaqConfig.InterfacesEntry.key', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -93,14 +92,14 @@ nested_types=[], enum_types=[ ], - serialized_options=_b('8\001'), + serialized_options=b'8\001', is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=1050, - serialized_end=1111, + serialized_start=1094, + serialized_end=1155, ) _DAQCONFIG_FAILMODULEENTRY = _descriptor.Descriptor( @@ -113,14 +112,14 @@ _descriptor.FieldDescriptor( name='key', full_name='DaqConfig.FailModuleEntry.key', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='value', full_name='DaqConfig.FailModuleEntry.value', index=1, number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -130,14 +129,14 @@ nested_types=[], enum_types=[ ], - serialized_options=_b('8\001'), + serialized_options=b'8\001', is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=1113, - serialized_end=1162, + serialized_start=1157, + serialized_end=1206, ) _DAQCONFIG = _descriptor.Descriptor( @@ -150,7 +149,7 @@ _descriptor.FieldDescriptor( name='site_description', full_name='DaqConfig.site_description', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -178,28 +177,28 @@ _descriptor.FieldDescriptor( name='base_conf', full_name='DaqConfig.base_conf', index=4, number=4, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='site_path', full_name='DaqConfig.site_path', index=5, number=5, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='initial_dhcp_lease_time', full_name='DaqConfig.initial_dhcp_lease_time', index=6, number=6, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='dhcp_lease_time', full_name='DaqConfig.dhcp_lease_time', index=7, number=7, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -227,7 +226,7 @@ _descriptor.FieldDescriptor( name='host_tests', full_name='DaqConfig.host_tests', index=11, number=16, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -283,63 +282,63 @@ _descriptor.FieldDescriptor( name='daq_loglevel', full_name='DaqConfig.daq_loglevel', index=19, number=21, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='mininet_loglevel', full_name='DaqConfig.mininet_loglevel', index=20, number=22, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='finish_hook', full_name='DaqConfig.finish_hook', index=21, number=35, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='gcp_cred', full_name='DaqConfig.gcp_cred', index=22, number=23, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='gcp_topic', full_name='DaqConfig.gcp_topic', index=23, number=24, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='schema_path', full_name='DaqConfig.schema_path', index=24, number=25, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='mud_files', full_name='DaqConfig.mud_files', index=25, number=26, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='device_specs', full_name='DaqConfig.device_specs', index=26, number=27, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='test_config', full_name='DaqConfig.test_config', index=27, number=28, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -353,21 +352,21 @@ _descriptor.FieldDescriptor( name='topology_hook', full_name='DaqConfig.topology_hook', index=29, number=30, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='device_template', full_name='DaqConfig.device_template', index=30, number=31, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='site_reports', full_name='DaqConfig.site_reports', index=31, number=32, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -427,6 +426,13 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='device_reporting', full_name='DaqConfig.device_reporting', index=40, + number=53, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], @@ -440,7 +446,7 @@ oneofs=[ ], serialized_start=34, - serialized_end=1162, + serialized_end=1206, ) @@ -454,7 +460,7 @@ _descriptor.FieldDescriptor( name='url', full_name='USISetup.url', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -477,8 +483,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1164, - serialized_end=1212, + serialized_start=1208, + serialized_end=1256, ) @@ -492,14 +498,14 @@ _descriptor.FieldDescriptor( name='ctrl_intf', full_name='SwitchSetup.ctrl_intf', index=0, number=9, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='ip_addr', full_name='SwitchSetup.ip_addr', index=1, number=11, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -527,56 +533,56 @@ _descriptor.FieldDescriptor( name='lo_addr', full_name='SwitchSetup.lo_addr', index=5, number=18, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='mods_addr', full_name='SwitchSetup.mods_addr', index=6, number=20, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='of_dpid', full_name='SwitchSetup.of_dpid', index=7, number=41, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='data_intf', full_name='SwitchSetup.data_intf', index=8, number=42, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='ext_br', full_name='SwitchSetup.ext_br', index=9, number=43, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='model', full_name='SwitchSetup.model', index=10, number=44, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='username', full_name='SwitchSetup.username', index=11, number=45, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='password', full_name='SwitchSetup.password', index=12, number=46, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -592,8 +598,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1215, - serialized_end=1459, + serialized_start=1259, + serialized_end=1503, ) @@ -630,8 +636,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1461, - serialized_end=1511, + serialized_start=1505, + serialized_end=1555, ) @@ -645,7 +651,7 @@ _descriptor.FieldDescriptor( name='opts', full_name='Interface.opts', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), + has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), @@ -668,8 +674,39 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1513, - serialized_end=1552, + serialized_start=1557, + serialized_end=1596, +) + + +_DEVICEREPORTING = _descriptor.Descriptor( + name='DeviceReporting', + full_name='DeviceReporting', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='server_port', full_name='DeviceReporting.server_port', index=0, + number=1, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1598, + serialized_end=1636, ) _DAQCONFIG_INTERFACESENTRY.fields_by_name['value'].message_type = _INTERFACE @@ -680,65 +717,74 @@ _DAQCONFIG.fields_by_name['fail_module'].message_type = _DAQCONFIG_FAILMODULEENTRY _DAQCONFIG.fields_by_name['usi_setup'].message_type = _USISETUP _DAQCONFIG.fields_by_name['run_trigger'].message_type = _RUNTRIGGER +_DAQCONFIG.fields_by_name['device_reporting'].message_type = _DEVICEREPORTING DESCRIPTOR.message_types_by_name['DaqConfig'] = _DAQCONFIG DESCRIPTOR.message_types_by_name['USISetup'] = _USISETUP DESCRIPTOR.message_types_by_name['SwitchSetup'] = _SWITCHSETUP DESCRIPTOR.message_types_by_name['RunTrigger'] = _RUNTRIGGER DESCRIPTOR.message_types_by_name['Interface'] = _INTERFACE +DESCRIPTOR.message_types_by_name['DeviceReporting'] = _DEVICEREPORTING DESCRIPTOR.enum_types_by_name['DHCPMode'] = _DHCPMODE _sym_db.RegisterFileDescriptor(DESCRIPTOR) -DaqConfig = _reflection.GeneratedProtocolMessageType('DaqConfig', (_message.Message,), dict( +DaqConfig = _reflection.GeneratedProtocolMessageType('DaqConfig', (_message.Message,), { - InterfacesEntry = _reflection.GeneratedProtocolMessageType('InterfacesEntry', (_message.Message,), dict( - DESCRIPTOR = _DAQCONFIG_INTERFACESENTRY, - __module__ = 'daq.proto.system_config_pb2' + 'InterfacesEntry' : _reflection.GeneratedProtocolMessageType('InterfacesEntry', (_message.Message,), { + 'DESCRIPTOR' : _DAQCONFIG_INTERFACESENTRY, + '__module__' : 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:DaqConfig.InterfacesEntry) - )) + }) , - FailModuleEntry = _reflection.GeneratedProtocolMessageType('FailModuleEntry', (_message.Message,), dict( - DESCRIPTOR = _DAQCONFIG_FAILMODULEENTRY, - __module__ = 'daq.proto.system_config_pb2' + 'FailModuleEntry' : _reflection.GeneratedProtocolMessageType('FailModuleEntry', (_message.Message,), { + 'DESCRIPTOR' : _DAQCONFIG_FAILMODULEENTRY, + '__module__' : 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:DaqConfig.FailModuleEntry) - )) + }) , - DESCRIPTOR = _DAQCONFIG, - __module__ = 'daq.proto.system_config_pb2' + 'DESCRIPTOR' : _DAQCONFIG, + '__module__' : 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:DaqConfig) - )) + }) _sym_db.RegisterMessage(DaqConfig) _sym_db.RegisterMessage(DaqConfig.InterfacesEntry) _sym_db.RegisterMessage(DaqConfig.FailModuleEntry) -USISetup = _reflection.GeneratedProtocolMessageType('USISetup', (_message.Message,), dict( - DESCRIPTOR = _USISETUP, - __module__ = 'daq.proto.system_config_pb2' +USISetup = _reflection.GeneratedProtocolMessageType('USISetup', (_message.Message,), { + 'DESCRIPTOR' : _USISETUP, + '__module__' : 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:USISetup) - )) + }) _sym_db.RegisterMessage(USISetup) -SwitchSetup = _reflection.GeneratedProtocolMessageType('SwitchSetup', (_message.Message,), dict( - DESCRIPTOR = _SWITCHSETUP, - __module__ = 'daq.proto.system_config_pb2' +SwitchSetup = _reflection.GeneratedProtocolMessageType('SwitchSetup', (_message.Message,), { + 'DESCRIPTOR' : _SWITCHSETUP, + '__module__' : 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:SwitchSetup) - )) + }) _sym_db.RegisterMessage(SwitchSetup) -RunTrigger = _reflection.GeneratedProtocolMessageType('RunTrigger', (_message.Message,), dict( - DESCRIPTOR = _RUNTRIGGER, - __module__ = 'daq.proto.system_config_pb2' +RunTrigger = _reflection.GeneratedProtocolMessageType('RunTrigger', (_message.Message,), { + 'DESCRIPTOR' : _RUNTRIGGER, + '__module__' : 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:RunTrigger) - )) + }) _sym_db.RegisterMessage(RunTrigger) -Interface = _reflection.GeneratedProtocolMessageType('Interface', (_message.Message,), dict( - DESCRIPTOR = _INTERFACE, - __module__ = 'daq.proto.system_config_pb2' +Interface = _reflection.GeneratedProtocolMessageType('Interface', (_message.Message,), { + 'DESCRIPTOR' : _INTERFACE, + '__module__' : 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:Interface) - )) + }) _sym_db.RegisterMessage(Interface) +DeviceReporting = _reflection.GeneratedProtocolMessageType('DeviceReporting', (_message.Message,), { + 'DESCRIPTOR' : _DEVICEREPORTING, + '__module__' : 'daq.proto.system_config_pb2' + # @@protoc_insertion_point(class_scope:DeviceReporting) + }) +_sym_db.RegisterMessage(DeviceReporting) + _DAQCONFIG_INTERFACESENTRY._options = None _DAQCONFIG_FAILMODULEENTRY._options = None diff --git a/proto/system_config.proto b/proto/system_config.proto index 4fe67b5f65..812d55eafa 100644 --- a/proto/system_config.proto +++ b/proto/system_config.proto @@ -126,6 +126,9 @@ message DaqConfig { // Drop into console mode after test bool use_console = 52; + + // Reporting device result + DeviceReporting device_reporting = 53; } enum DHCPMode { @@ -210,3 +213,11 @@ message Interface { // Switch port for attching interface. int32 port = 2; } + +/* + * Configuration for device result reporting + */ +message DeviceReporting { + // Server port + int32 server_port = 1; +} diff --git a/testing/test_aux.out b/testing/test_aux.out index ef7b025daf..b873ced907 100644 --- a/testing/test_aux.out +++ b/testing/test_aux.out @@ -75,8 +75,11 @@ dhcp requests 1 1 1 1 arp.txt dp_port_acls.yaml dp_sec_port_1_acl.yaml +dp_sec_port_1_acl_augmented.yaml dp_sec_port_2_acl.yaml +dp_sec_port_2_acl_augmented.yaml dp_sec_port_3_acl.yaml +dp_sec_port_3_acl_augmented.yaml faucet.log faucet.yaml finish.out diff --git a/testing/unit/test_device_report_client.py b/testing/unit/test_device_report_client.py new file mode 100644 index 0000000000..f4e231afa2 --- /dev/null +++ b/testing/unit/test_device_report_client.py @@ -0,0 +1,65 @@ +"""Unit tests for device report client""" + +import time +import unittest + +from forch.device_report_server import DeviceReportServer + +from device_report_client import DeviceReportClient +from utils import proto_dict + + +class DeviceReportClientTestBase(unittest.TestCase): + """Base class for device report client unit test""" + _SERVER_ADDRESS = '0.0.0.0' + _SERVER_PORT = 50071 + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._server = None + self._client = None + + def _process_result(self, result): + pass + + def setUp(self): + """Setup fixture for each test method""" + self._client = DeviceReportClient(server_port=self._SERVER_PORT) + + self._server = DeviceReportServer( + self._process_result, self._SERVER_ADDRESS, self._SERVER_PORT) + self._server.start() + + def tearDown(self): + """Cleanup after each test method finishes""" + self._server.stop() + + +class DeviceDeviceReportServerlientBasicTestCase(DeviceReportClientTestBase): + """Basic test case for device report client""" + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._received_results = [] + + def _process_result(self, result): + devices_state_map = proto_dict(result, including_default_value_fields=True) + mac, device_behavior = devices_state_map['device_mac_behaviors'].popitem() + received_result = {'mac': mac, 'port_behavior': device_behavior['port_behavior']} + self._received_results.append(received_result) + + def test_sending_device_result(self): + """Test behavior of the client and server when client sends devices states""" + expected_results = [ + {'mac': '00:0X:00:00:00:01', 'port_behavior': 'unknown'}, + {'mac': '00:0Y:00:00:00:02', 'port_behavior': 'passed'}, + {'mac': '00:0Z:00:00:00:03', 'port_behavior': 'cleared'}, + {'mac': '00:0A:00:00:00:04', 'port_behavior': 'passed'}, + {'mac': '00:0B:00:00:00:05', 'port_behavior': 'unknown'} + ] + + for result in expected_results: + print(f'Sending result:\n{result}') + self._client.send_device_result(result['mac'], result['port_behavior']) + + time.sleep(2) + self.assertEqual(self._received_results, expected_results) From 8e4d715779f6f08dbd18917e295cd90f3bbbc53a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 Oct 2020 13:52:39 -0700 Subject: [PATCH 181/212] Update dependency io.grpc:grpc-protobuf to v1.33.0 (#688) --- subset/switches/pom.xml | 2 +- usi/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subset/switches/pom.xml b/subset/switches/pom.xml index c3460de97a..8799b0ccf6 100644 --- a/subset/switches/pom.xml +++ b/subset/switches/pom.xml @@ -43,7 +43,7 @@ io.grpc grpc-protobuf - 1.32.2 + 1.33.0 io.grpc diff --git a/usi/pom.xml b/usi/pom.xml index c4d31cfb2f..39230b1396 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -43,7 +43,7 @@ io.grpc grpc-protobuf - 1.32.2 + 1.33.0 io.grpc From 6a821cb169c79bac4090238cab8249d97a0e1cb8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 Oct 2020 13:52:58 -0700 Subject: [PATCH 182/212] Update dependency io.grpc:grpc-bom to v1.33.0 (#686) --- subset/switches/pom.xml | 2 +- usi/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subset/switches/pom.xml b/subset/switches/pom.xml index 8799b0ccf6..f619c07227 100644 --- a/subset/switches/pom.xml +++ b/subset/switches/pom.xml @@ -16,7 +16,7 @@ io.grpc grpc-bom - 1.32.2 + 1.33.0 pom import diff --git a/usi/pom.xml b/usi/pom.xml index 39230b1396..cfdcbbcaff 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -16,7 +16,7 @@ io.grpc grpc-bom - 1.32.2 + 1.33.0 pom import From 6dd7993c748c824a6161c7821e928478ffd5d05a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 Oct 2020 13:55:03 -0700 Subject: [PATCH 183/212] Update dependency gradle to v6.7 (#681) --- .../bacnet/bacnetFaux/gradle/wrapper/gradle-wrapper.properties | 2 +- .../network/NTPClient/gradle/wrapper/gradle-wrapper.properties | 2 +- mudacl/gradle/wrapper/gradle-wrapper.properties | 2 +- .../bacnet/bacnetTests/gradle/wrapper/gradle-wrapper.properties | 2 +- subset/network/mac_oui/gradle/wrapper/gradle-wrapper.properties | 2 +- .../security/tlstest/gradle/wrapper/gradle-wrapper.properties | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docker/include/bacnet/bacnetFaux/gradle/wrapper/gradle-wrapper.properties b/docker/include/bacnet/bacnetFaux/gradle/wrapper/gradle-wrapper.properties index 12d38de6a4..be52383ef4 100644 --- a/docker/include/bacnet/bacnetFaux/gradle/wrapper/gradle-wrapper.properties +++ b/docker/include/bacnet/bacnetFaux/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/docker/include/network/NTPClient/gradle/wrapper/gradle-wrapper.properties b/docker/include/network/NTPClient/gradle/wrapper/gradle-wrapper.properties index 12d38de6a4..be52383ef4 100644 --- a/docker/include/network/NTPClient/gradle/wrapper/gradle-wrapper.properties +++ b/docker/include/network/NTPClient/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/mudacl/gradle/wrapper/gradle-wrapper.properties b/mudacl/gradle/wrapper/gradle-wrapper.properties index 567aa53d89..3e157c80e7 100644 --- a/mudacl/gradle/wrapper/gradle-wrapper.properties +++ b/mudacl/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip diff --git a/subset/bacnet/bacnetTests/gradle/wrapper/gradle-wrapper.properties b/subset/bacnet/bacnetTests/gradle/wrapper/gradle-wrapper.properties index 12d38de6a4..be52383ef4 100644 --- a/subset/bacnet/bacnetTests/gradle/wrapper/gradle-wrapper.properties +++ b/subset/bacnet/bacnetTests/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/subset/network/mac_oui/gradle/wrapper/gradle-wrapper.properties b/subset/network/mac_oui/gradle/wrapper/gradle-wrapper.properties index 8d8e8abe86..e8894b0281 100644 --- a/subset/network/mac_oui/gradle/wrapper/gradle-wrapper.properties +++ b/subset/network/mac_oui/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip diff --git a/subset/security/tlstest/gradle/wrapper/gradle-wrapper.properties b/subset/security/tlstest/gradle/wrapper/gradle-wrapper.properties index 12d38de6a4..be52383ef4 100644 --- a/subset/security/tlstest/gradle/wrapper/gradle-wrapper.properties +++ b/subset/security/tlstest/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 237ff32fc42afe90b012c63960273fea9cc5dafd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 Oct 2020 13:55:31 -0700 Subject: [PATCH 184/212] Update dependency io.grpc:grpc-netty-shaded to v1.33.0 (#687) --- subset/switches/pom.xml | 2 +- usi/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subset/switches/pom.xml b/subset/switches/pom.xml index f619c07227..7385c45bb6 100644 --- a/subset/switches/pom.xml +++ b/subset/switches/pom.xml @@ -38,7 +38,7 @@ io.grpc grpc-netty-shaded - 1.32.2 + 1.33.0 io.grpc diff --git a/usi/pom.xml b/usi/pom.xml index cfdcbbcaff..29de9f5df7 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -38,7 +38,7 @@ io.grpc grpc-netty-shaded - 1.32.2 + 1.33.0 io.grpc From 6a6231657272e86e0feb8f0e16bb3b17aba41fc6 Mon Sep 17 00:00:00 2001 From: Trevor Pering Date: Thu, 22 Oct 2020 18:26:05 -0700 Subject: [PATCH 185/212] Add simple setup option (#693) --- bin/setup_dev | 11 +++++++++++ bin/setup_docker | 7 ------- 2 files changed, 11 insertions(+), 7 deletions(-) delete mode 100755 bin/setup_docker diff --git a/bin/setup_dev b/bin/setup_dev index a7212ed1c3..11b7dc997b 100755 --- a/bin/setup_dev +++ b/bin/setup_dev @@ -9,6 +9,12 @@ ROOT=$(dirname $0)/.. cd $ROOT +SIMPLE= +if [ "$1" == simple ]; then + SIMPLE=y + shift +fi + PVERSION=3.7 FAUCETR=${DAQ_FAUCET_REPO:-https://github.com/faucetsdn/faucet} @@ -144,6 +150,11 @@ $PIP freeze echo Resetting .cache directory permissions... test -n "$USER" && sudo chown $USER -R $HOME/.cache +if [ -n "$SIMPLE" ]; then + echo Finished with simple setup. + exit 0 +fi + if [ -z "$FAUCETV" ]; then echo No faucet version found, skipping. else diff --git a/bin/setup_docker b/bin/setup_docker deleted file mode 100755 index 132d4b0109..0000000000 --- a/bin/setup_docker +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -e -# -# Setup daq for running inside of a docker container. -# - -echo Hello. - From 47814f60106819751adfe7b6fd1a0ff629b97a2f Mon Sep 17 00:00:00 2001 From: Trevor Date: Fri, 23 Oct 2020 14:23:55 -0700 Subject: [PATCH 186/212] Attempt python3.8 update (#696) --- .github/workflows/tests.yml | 8 ++++---- bin/setup_dev | 2 +- docker/modules/Dockerfile.faux2 | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index fe101d0ee7..91126daaf1 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -20,10 +20,10 @@ jobs: - uses: actions/checkout@v2 with: fetch-depth: 0 - - name: Set up Python 3.7 + - name: Set up Python 3.8 uses: actions/setup-python@v2 with: - python-version: 3.7 + python-version: 3.8 - name: Set up JDK 1.11 uses: actions/setup-java@v1 with: @@ -49,10 +49,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Set up Python 3.7 + - name: Set up Python 3.8 uses: actions/setup-python@v2 with: - python-version: 3.7 + python-version: 3.8 - name: Install dependencies run: | bin/setup_dev diff --git a/bin/setup_dev b/bin/setup_dev index 11b7dc997b..c7f68ad604 100755 --- a/bin/setup_dev +++ b/bin/setup_dev @@ -15,7 +15,7 @@ if [ "$1" == simple ]; then shift fi -PVERSION=3.7 +PVERSION=3.8 FAUCETR=${DAQ_FAUCET_REPO:-https://github.com/faucetsdn/faucet} FAUCETX=$(cat etc/FAUCET_VERSION) diff --git a/docker/modules/Dockerfile.faux2 b/docker/modules/Dockerfile.faux2 index e179f0b9a7..7a9b0857d3 100644 --- a/docker/modules/Dockerfile.faux2 +++ b/docker/modules/Dockerfile.faux2 @@ -9,7 +9,7 @@ FROM daqf/aardvark:latest RUN $AG update && $AG install openjdk-11-jre RUN $AG update && $AG install openjdk-11-jdk git RUN $AG update && $AG install isc-dhcp-client ethtool network-manager netcat curl \ - python3.7 ifupdown openssl ssh nano apache2-utils ntpdate + python3.8 ifupdown openssl ssh nano apache2-utils ntpdate # Additional OS dependencies RUN $AG update && $AG install -y telnetd && $AG install xinetd nginx @@ -18,7 +18,7 @@ RUN $AG update && $AG install -y telnetd && $AG install xinetd nginx RUN $AG update && cd /tmp && ln -s ~/bin bin && $AG download resolvconf && mv resolvconf_*.deb ~ # Default to python3 -RUN update-alternatives --install /usr/bin/python python /usr/bin/python3.7 2 +RUN update-alternatives --install /usr/bin/python python /usr/bin/python3.8 2 # Basic faux stuff COPY docker/include/bin/start_faux docker/include/bin/failing bin/ From a692cee67be8809dfec470a467cede00513fc887 Mon Sep 17 00:00:00 2001 From: Trevor Date: Fri, 23 Oct 2020 16:58:31 -0700 Subject: [PATCH 187/212] Separate out cmd/start (#695) --- cmd/exrun | 40 +--------------------------------------- cmd/start | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 39 deletions(-) create mode 100755 cmd/start diff --git a/cmd/exrun b/cmd/exrun index 7bfeaf39ce..a391027623 100755 --- a/cmd/exrun +++ b/cmd/exrun @@ -9,11 +9,7 @@ LOCALDIR=$ROOT/local FAUCET_LOG=$INSTDIR/faucet.log FAUCET_SOCK=faucet_event.sock export FAUCET_EVENT_SOCK=$INSTDIR/$FAUCET_SOCK -export DAQ_VERSION=$(git describe --dirty) TAGGED_VERSION=`cat etc/docker_images.ver` -LSB_RAW=$(lsb_release -a) -export DAQ_LSB_RELEASE=$(echo $LSB_RAW) -export DAQ_SYS_UNAME=$(uname -a) skip_autostart= cleanup_file=inst/exrun_cleanup.sh uri_url_override="" @@ -141,42 +137,8 @@ if [ -z "$skip_autostart" ]; then fi fi -if [ -f .pdbrc ]; then - echo Found .pdbrc file, using pdb... - runcmd="python3 -m pdb" -elif [ -n "$DAQ_CODECOV" ]; then - echo Running with codecov analysis... - runcmd="coverage run --source=daq -a" -else - runcmd="python3" -fi - -if [ -d venv ]; then - echo Entering virtual python environment... - source venv/bin/activate -fi - -if [ -z `which ifconfig` ]; then - export PATH=/sbin:$PATH -fi - -if [ -z `which tcpdump` ]; then - export PATH=/usr/sbin:$PATH -fi - -echo Using python3 at `which python3` -echo Executing: $runcmd daq/daq.py $conf_file $@ - -export PYTHONDONTWRITEBYTECODE=True -export PYTHONUNBUFFERED=True -export TERM=dumb - -echo Prepending $ROOT/binhack to PATH -export OVSVSCTL_ORIG=`which ovs-vsctl` -export PATH=$ROOT/binhack:$PATH - exit_code=0 -$runcmd daq/daq.py $conf_file $uri_url_override $@ 2>&1 || exit_code=$? +cmd/start $conf_file $@ $uri_url_override || exit_code=$? if [ -f "$cleanup_file" ]; then source $cleanup_file diff --git a/cmd/start b/cmd/start new file mode 100755 index 0000000000..07d4f5ed0f --- /dev/null +++ b/cmd/start @@ -0,0 +1,45 @@ +#!/bin/bash -e + +ROOT=$(realpath $(dirname $0)/..) +cd $ROOT + +export DAQ_VERSION=$(git describe --dirty) +LSB_RAW=$(lsb_release -a) +export DAQ_LSB_RELEASE=$(echo $LSB_RAW) +export DAQ_SYS_UNAME=$(uname -a) + +if [ -f .pdbrc ]; then + echo Found .pdbrc file, using pdb... + runcmd="python3 -m pdb" +elif [ -n "$DAQ_CODECOV" ]; then + echo Running with codecov analysis... + runcmd="coverage run --source=daq -a" +else + runcmd="python3" +fi + +if [ -d venv ]; then + echo Entering virtual python environment... + source venv/bin/activate +fi + +if [ -z `which ifconfig` ]; then + export PATH=/sbin:$PATH +fi + +if [ -z `which tcpdump` ]; then + export PATH=/usr/sbin:$PATH +fi + +echo Using python3 at `which python3` + +export PYTHONDONTWRITEBYTECODE=True +export PYTHONUNBUFFERED=True +export TERM=dumb + +echo Prepending $ROOT/binhack to PATH +export OVSVSCTL_ORIG=`which ovs-vsctl` +export PATH=$ROOT/binhack:$PATH + +echo Executing: $runcmd daq/daq.py $@ +$runcmd daq/daq.py $@ 2>&1 From 6643326afc46f386e3e9f929f0cf185afbea156c Mon Sep 17 00:00:00 2001 From: Trevor Date: Mon, 26 Oct 2020 15:58:13 -0700 Subject: [PATCH 188/212] Create EXT_STACK mode for DAQ (#698) --- cmd/exrun | 7 +++++-- config/system/alt.yaml | 3 ++- config/system/ext.conf | 25 ------------------------- config/system/ext.yaml | 2 +- daq/topology.py | 5 +++++ docs/switcher.md | 8 ++++---- testing/test_base.sh | 19 ++++++++++++++----- 7 files changed, 31 insertions(+), 38 deletions(-) delete mode 100644 config/system/ext.conf diff --git a/cmd/exrun b/cmd/exrun index a391027623..daeec10bb3 100755 --- a/cmd/exrun +++ b/cmd/exrun @@ -67,7 +67,10 @@ fi export PYTHONPATH=$FORCH:$FAUCET:$MININET:$LIBS:$PROTO mkdir -p $INSTDIR -rm -rf $INSTDIR/faucet* $cleanup_file +rm -f $cleanup_file +if [ "$switch_setup_model" != EXT_STACK ]; then + rm -rf $INSTDIR/faucet* +fi docker ps > /dev/null 2>&1 || service docker start @@ -104,7 +107,7 @@ if [ -n "$switch_setup_alt_port" ]; then autostart bin/alt_faucet fi -if [ -n "$switch_setup_model" ]; then +if [ -n "$switch_setup_model" -a "$switch_setup_model" != EXT_STACK ]; then autostart bin/physical_sec else echo No external switch model specified. diff --git a/config/system/alt.yaml b/config/system/alt.yaml index 678a1ab85a..c99374270f 100644 --- a/config/system/alt.yaml +++ b/config/system/alt.yaml @@ -4,7 +4,7 @@ include: config/system/default.yaml # Description for dashboard. -site_description: "Alternate (not managed by DAQ) OVS switch configuration" +site_description: "Alternate switch (not managed by DAQ) configuration" # Network switch configuration. switch_setup: @@ -12,6 +12,7 @@ switch_setup: alt_port: 6669 uplink_port: 100 ext_br: alt-switch + model: EXT_STACK # Faux device connection for testing. interfaces: diff --git a/config/system/ext.conf b/config/system/ext.conf deleted file mode 100644 index 28dc34b707..0000000000 --- a/config/system/ext.conf +++ /dev/null @@ -1,25 +0,0 @@ -# Base configuration file for using an OVS switch external to DAQ itself. - -# Load defaults. -source config/system/default.yaml - -# Description for dashboard. -site_description="External (not integrated with DAQ) OVS switch configuration" - -# Network switch configuration. -switch_setup.of_dpid=0x123456789 -switch_setup.ext_br=ext-ovs -switch_setup.ctrl_intf=ext-ovs-ctl -switch_setup.data_intf=ext-ovs-pri -switch_setup.lo_port=6666 -switch_setup.uplink_port=7 -switch_setup.lo_addr=192.0.2.10/24 -switch_setup.mods_addr=192.0.2.1%d/24 -switch_setup.ip_addr=192.0.2.138 -switch_setup.model=FAUX_SWITCH -switch_setup.username=aardvark -switch_setup.password=anteater - -# Faux device connection for testing. -interfaces.faux.opts= -interfaces.faux.port=2 diff --git a/config/system/ext.yaml b/config/system/ext.yaml index 4fef079c1e..6661e9d7d8 100644 --- a/config/system/ext.yaml +++ b/config/system/ext.yaml @@ -4,7 +4,7 @@ include: config/system/default.yaml # Description for dashboard. -site_description: "External (not integrated with DAQ) OVS switch configuration" +site_description: "External switch (not integrated with DAQ) configuration" # Network switch configuration. switch_setup: diff --git a/daq/topology.py b/daq/topology.py index 9faff2ae3a..f419ab6c61 100644 --- a/daq/topology.py +++ b/daq/topology.py @@ -41,6 +41,7 @@ class FaucetTopology: PRI_TRUNK_PORT = 1 PRI_TRUNK_NAME = 'trunk_pri' _NO_VLAN = "0x0000/0x1000" + _EXT_STACK = 'EXT_STACK' def __init__(self, config): self.config = config @@ -52,6 +53,7 @@ def __init__(self, config): self.sec_dpid = int(switch_setup['of_dpid'], 0) self.ext_ofip = switch_setup.get('lo_addr') self.ext_intf = switch_setup.get('data_intf') + self._ext_faucet = switch_setup.get('model') == self._EXT_STACK self._settle_sec = int(config['settle_sec']) self._device_specs = self._load_device_specs() self._port_targets = {} @@ -67,6 +69,9 @@ def initialize(self, pri): def start(self): """Start this instance""" + if self._ext_faucet: + LOGGER.info('Relying on external faucet...') + return LOGGER.info("Starting faucet...") output = self.pri.cmd('cmd/faucet && echo SUCCESS') if not output.strip().endswith('SUCCESS'): diff --git a/docs/switcher.md b/docs/switcher.md index 3cb07196e7..b50e7a7862 100644 --- a/docs/switcher.md +++ b/docs/switcher.md @@ -20,13 +20,13 @@ the switch for unit testing. This is a sample test run while using a simulated docker switch container along with an 'external' OVS switch as per the automated integration tests.
      -~/daq$ cp config/system/ext.conf local/system.conf
      +~/daq$ cp config/system/ext.yaml local/system.yaml
       ~/daq$ cmd/run -s
      -Loading config from local/system.conf
      +Loading config from local/system.yaml
       Starting Sun Dec 23 08:36:09 PST 2018
       Clearing previous reports...
       Running as root...
      -Loading config from local/system.conf
      +Loading config from local/system.yaml
       Release version 0.9.0
       cleanup='echo cleanup'
       ext_addr=192.0.2.138
      @@ -37,7 +37,7 @@ ext_ofip=192.0.2.10/24
       ext_ofpt=6666
       sec_port=7
       …
      -Loading config from local/system.conf
      +Loading config from local/system.yaml
       Using default cplane_mac f8:39:71:c9:7a:09
       Cleaning old setup...
       Creating ovs-link interfaces...
      diff --git a/testing/test_base.sh b/testing/test_base.sh
      index a8147a9c55..b3f3e1857c 100755
      --- a/testing/test_base.sh
      +++ b/testing/test_base.sh
      @@ -54,20 +54,29 @@ echo switch ping $count | tee -a $TEST_RESULTS
       
       echo %%%%%%%%%%%%%%%%%%%%%% Alt switch tests | tee -a $TEST_RESULTS
       cp config/system/alt.yaml local/system.yaml
      +cmd/faucet
      +
       # TODO: Replace this with proper test once VLAN-triggers are added.
      -function run_cmds {
      +function configure_networking {
           docker exec daq-networking-2 ifconfig eth0 down
           docker exec daq-networking-2 ifconfig faux-eth0 up
           docker exec daq-networking-2 ip addr add 10.20.255.254/16 dev faux-eth0
           docker exec daq-networking-2 bash -c "echo dhcp-range=10.20.99.100,10.20.99.254 >> /etc/dnsmasq.conf"
       }
       
      -monitor_log "Added link faux-2 as port 3 on alt-switch" run_cmds
      -monitor_log "Target device 9a02571e8f01 waiting for ip" 'docker exec daq-networking-2 bash -c "./autorestart_dnsmasq &"'
      +function restart_networking {
      +    docker exec daq-networking-2 bash -c "./autorestart_dnsmasq &"
      +}
      +
      +monitor_log "Added link faux-2 as port 3 on alt-switch" configure_networking
      +monitor_log "Target device 9a02571e8f01 waiting for ip" restart_networking
       timeout 1200s cmd/run -s
       fgrep '9a:02:57:1e:8f:01 learned on vid 2000' inst/cmdrun.log | head -1 | redact | tee -a $TEST_RESULTS
      -echo Correct IP: $(fgrep '10.20.99' inst/run-9a02571e8f01/scans/ip_triggers.txt | wc -l) | tee -a $TEST_RESULTS 
      -cat inst/result.log | grep 9a02571e8f01 | tee -a $TEST_RESULTS # ping test should fail since there are no dhcp packets captured
      +correct_ips=$(fgrep '10.20.99' inst/run-9a02571e8f01/scans/ip_triggers.txt | wc -l)
      +echo Correct IP: $correct_ips | tee -a $TEST_RESULTS
      +cat inst/result.log | grep 9a02571e8f01 | tee -a $TEST_RESULTS
      +# ping test should fail since there are no dhcp packets captured
      +
       echo %%%%%%%%%%%%%%%%%%%%%% Mud profile tests | tee -a $TEST_RESULTS
       rm -f local/system.yaml
       cp config/system/muddy.conf local/system.conf
      
      From 5774d742845f9d53b6fc53406a5c9270a2e03e20 Mon Sep 17 00:00:00 2001
      From: Trevor 
      Date: Thu, 29 Oct 2020 16:14:14 -0700
      Subject: [PATCH 189/212] Clean up VLAN trigger setup for FOT integration
       (#700)
      
      ---
       config/faucet/faucet_alt-switch.yaml |  13 +-
       config/system/alt.yaml               |   7 +-
       daq/host.py                          |  14 +-
       daq/network.py                       |   5 +
       daq/runner.py                        |   8 +-
       daq/test_modules/ipaddr_module.py    |   4 +-
       daq/topology.py                      |  46 +++---
       firebase/public/protos.hash          |   2 +-
       firebase/public/protos.html          |  17 ++-
       libs/proto/system_config_pb2.py      | 204 +++++++++++++++------------
       proto/system_config.proto            |   9 +-
       testing/test_base.out                |   2 +-
       testing/test_base.sh                 |   2 +-
       13 files changed, 186 insertions(+), 147 deletions(-)
      
      diff --git a/config/faucet/faucet_alt-switch.yaml b/config/faucet/faucet_alt-switch.yaml
      index 5da1ea4a76..d4883b5a85 100644
      --- a/config/faucet/faucet_alt-switch.yaml
      +++ b/config/faucet/faucet_alt-switch.yaml
      @@ -3,18 +3,21 @@ dps:
           dp_id: 2
           interfaces:
             1:
      -        native_vlan: 1002
      +        native_vlan: 1001
             2:
      -        native_vlan: 2000 
      +        native_vlan: 1002
             3:
      -        native_vlan: 2000
      +        native_vlan: 1002
             4:
               native_vlan: 1004
             5:
               native_vlan: 1005
      -      100:
      -        tagged_vlans: [1001, 1002, 1003, 1004, 1005, 2000]
      +      10:
      +        tagged_vlans: [1001, 1002, 1003, 1004, 1005, 121]
      +      11:
      +        native_vlan: 121
       vlans:
      +  121:
         1001:
         1002:
         1003:
      diff --git a/config/system/alt.yaml b/config/system/alt.yaml
      index c99374270f..8c2216db3f 100644
      --- a/config/system/alt.yaml
      +++ b/config/system/alt.yaml
      @@ -10,7 +10,7 @@ site_description: "Alternate switch (not managed by DAQ) configuration"
       switch_setup:
         data_intf: alt-intf
         alt_port: 6669
      -  uplink_port: 100
      +  uplink_port: 10
         ext_br: alt-switch
         model: EXT_STACK
       
      @@ -27,5 +27,6 @@ default_timeout_sec: 120
       
       # use vlan trigger
       run_trigger:
      -  vlan_start: 2000
      -  vlan_end: 2050
      +  vlan_start: 1001
      +  vlan_end: 1009
      +  egress_vlan: 121
      diff --git a/daq/host.py b/daq/host.py
      index 5a8ff66d58..8232bd274f 100644
      --- a/daq/host.py
      +++ b/daq/host.py
      @@ -12,7 +12,7 @@
       from report import ResultType, ReportGenerator
       from proto import usi_pb2 as usi
       from proto import usi_pb2_grpc as usi_service
      -from proto.system_config_pb2 import DHCPMode
      +from proto.system_config_pb2 import DhcpMode
       
       import configurator
       from test_modules import DockerModule, IpAddrModule, NativeModule
      @@ -207,7 +207,7 @@ def _get_static_ip(self):
       
           def _get_dhcp_mode(self):
               mode_str = self._loaded_config['modules'].get('ipaddr', {}).get('dhcp_mode', "NORMAL")
      -        return DHCPMode.Value(mode_str)
      +        return DhcpMode.Value(mode_str)
       
           def _get_unique_upload_path(self, file_name):
               base = os.path.basename(file_name)
      @@ -357,7 +357,7 @@ def _prepare(self):
               static_ip = self._get_static_ip()
               if static_ip:
                   self.logger.info('Target device %s using static ip', self)
      -            self.device.dhcp_mode = DHCPMode.STATIC_IP
      +            self.device.dhcp_mode = DhcpMode.STATIC_IP
                   time.sleep(self._STARTUP_MIN_TIME_SEC)
                   self.runner.ip_notify(MODE.NOPE, {
                       'mac': self.target_mac,
      @@ -370,10 +370,10 @@ def _prepare(self):
                       self.device.dhcp_mode = dhcp_mode
                   # enables dhcp response for this device
                   wait_time = self.runner.config.get("long_dhcp_response_sec") \
      -                if self.device.dhcp_mode == DHCPMode.LONG_RESPONSE else 0
      +                if self.device.dhcp_mode == DhcpMode.LONG_RESPONSE else 0
                   self.logger.info('Target device %s using %s DHCP mode, wait %s',
      -                             self, DHCPMode.Name(self.device.dhcp_mode), wait_time)
      -            if self.device.dhcp_mode != DHCPMode.EXTERNAL:
      +                             self, DhcpMode.Name(self.device.dhcp_mode), wait_time)
      +            if self.device.dhcp_mode != DhcpMode.EXTERNAL:
                       self.gateway.change_dhcp_response_time(self.target_mac, wait_time)
               _ = [listener(self.device) for listener in self._dhcp_listeners]
       
      @@ -465,7 +465,7 @@ def trigger_ready(self):
               delta_t = datetime.now() - self._startup_time
               if delta_t < timedelta(seconds=self._STARTUP_MIN_TIME_SEC):
                   return False
      -        if self._get_dhcp_mode() == DHCPMode.IP_CHANGE:
      +        if self._get_dhcp_mode() == DhcpMode.IP_CHANGE:
                   return len(set(map(lambda ip: ip["ip"], self._all_ips))) > 1
               return True
       
      diff --git a/daq/network.py b/daq/network.py
      index adc95addca..3480ec82b3 100644
      --- a/daq/network.py
      +++ b/daq/network.py
      @@ -2,6 +2,7 @@
       
       import os
       from shutil import copyfile
      +import time
       import yaml
       
       import logger
      @@ -50,6 +51,7 @@ def __init__(self, config):
               self.sec = None
               self.sec_dpid = None
               self.sec_port = None
      +        self._settle_sec = int(config['settle_sec'])
               self.topology = FaucetTopology(self.config)
               self.ext_intf = self.topology.get_ext_intf()
               switch_setup = config.get('switch_setup', {})
      @@ -211,6 +213,9 @@ def _generate_behavioral_config(self):
                   copyfile(src_name, dst_name)
       
               self.faucitizer.reload_structural_config(self.INTERMEDIATE_FAUCET_FILE)
      +        if self._settle_sec:
      +            LOGGER.info('Waiting %ds for network to settle', self._settle_sec)
      +            time.sleep(self._settle_sec)
       
           def direct_vlan_traffic(self, port_set, vlan):
               """Modify gateway set's vlan to match triggering vlan"""
      diff --git a/daq/runner.py b/daq/runner.py
      index ec79fc4ee5..afe4cf89ab 100644
      --- a/daq/runner.py
      +++ b/daq/runner.py
      @@ -25,7 +25,7 @@
       import stream_monitor
       from wrappers import DaqException
       import logger
      -from proto.system_config_pb2 import DHCPMode
      +from proto.system_config_pb2 import DhcpMode
       
       LOGGER = logger.get_logger('runner')
       
      @@ -356,7 +356,7 @@ def _handle_device_learn(self, vid, target_mac):
                   device = self._devices.new_device(target_mac, vlan=vid)
               else:
                   device = self._devices.get(target_mac)
      -        device.dhcp_mode = DHCPMode.EXTERNAL
      +        device.dhcp_mode = DhcpMode.EXTERNAL
               self._target_set_trigger(device)
       
           def _queue_callback(self, callback):
      @@ -498,7 +498,7 @@ def _target_set_trigger(self, device):
       
               # Stops all DHCP response initially
               # Selectively enables dhcp response at ipaddr stage based on dhcp mode
      -        if device.dhcp_mode != DHCPMode.EXTERNAL:
      +        if device.dhcp_mode != DhcpMode.EXTERNAL:
                   gateway.stop_dhcp_response(device.mac)
               gateway.attach_target(device)
               device.gateway = gateway
      @@ -593,7 +593,7 @@ def _activate_device_group(self, device):
               set_num = self._find_gateway_set(device)
               LOGGER.info('Gateway for device group %s not found, initializing base %d...',
                           device.group, set_num)
      -        if device.dhcp_mode == DHCPMode.EXTERNAL:
      +        if device.dhcp_mode == DhcpMode.EXTERNAL:
                   # Under vlan trigger, start a external gateway that doesn't utilize a DHCP server.
                   gateway = external_gateway.ExternalGateway(self, group_name, set_num)
               else:
      diff --git a/daq/test_modules/ipaddr_module.py b/daq/test_modules/ipaddr_module.py
      index 8723f7e7d6..4f4d895dee 100644
      --- a/daq/test_modules/ipaddr_module.py
      +++ b/daq/test_modules/ipaddr_module.py
      @@ -10,7 +10,7 @@
       import logger
       from .docker_module import DockerModule
       from .base_module import HostModule
      -from proto.system_config_pb2 import DHCPMode
      +from proto.system_config_pb2 import DhcpMode
       
       _LOG_FORMAT = "%(asctime)s %(levelname)-7s %(message)s"
       LEASE_TIME_UNITS_CONVERTER = {
      @@ -52,7 +52,7 @@ def __init__(self, host, tmpdir, test_name, module_config):
           def start(self, port, params, callback, finish_hook):
               """Start the ip-addr tests"""
               super().start(port, params, callback, finish_hook)
      -        assert self.host.device.dhcp_mode != DHCPMode.EXTERNAL, "device DHCP is not enabled."
      +        assert self.host.device.dhcp_mode != DhcpMode.EXTERNAL, "device DHCP is not enabled."
               self._logger.debug('Target device %s starting ipaddr test %s', self.device, self.test_name)
               self._next_test()
       
      diff --git a/daq/topology.py b/daq/topology.py
      index f419ab6c61..95ba7bbe41 100644
      --- a/daq/topology.py
      +++ b/daq/topology.py
      @@ -2,7 +2,6 @@
       
       import copy
       import os
      -import time
       import yaml
       
       from base_gateway import BaseGateway
      @@ -36,7 +35,8 @@ class FaucetTopology:
           _MIRROR_IFACE_FORMAT = "mirror-%d"
           _MIRROR_PORT_BASE = 1000
           _SWITCH_LOCAL_PORT = _MIRROR_PORT_BASE
      -    _VLAN_BASE = 1000
      +    _LOCAL_VLAN = 1000
      +    _DUMP_VLAN = 999
           PRI_DPID = 1
           PRI_TRUNK_PORT = 1
           PRI_TRUNK_NAME = 'trunk_pri'
      @@ -54,7 +54,6 @@ def __init__(self, config):
               self.ext_ofip = switch_setup.get('lo_addr')
               self.ext_intf = switch_setup.get('data_intf')
               self._ext_faucet = switch_setup.get('model') == self._EXT_STACK
      -        self._settle_sec = int(config['settle_sec'])
               self._device_specs = self._load_device_specs()
               self._port_targets = {}
               self.topology = None
      @@ -130,10 +129,8 @@ def direct_port_traffic(self, target_mac, port_no, target):
                   return
               self._generate_acls()
               port_set = target['port_set'] if target else None
      -        self._update_port_vlan(port_no, port_set)
      -        if self._settle_sec:
      -            LOGGER.info('Waiting %ds for network to settle', self._settle_sec)
      -            time.sleep(self._settle_sec)
      +        interface = self.topology['dps'][self.sec_name]['interfaces'][port_no]
      +        interface['native_vlan'] = self._port_set_vlan(port_set)
       
           def _ensure_entry(self, root, key, value):
               if key not in root:
      @@ -166,25 +163,22 @@ def _make_mirror_interface(self, input_port):
               interface['output_only'] = True
               return interface
       
      -    def _make_switch_interface(self):
      +    def _make_local_interface(self):
               interface = {}
               interface['name'] = 'local_switch'
      -        interface['native_vlan'] = self._VLAN_BASE
      +        interface['native_vlan'] = self._LOCAL_VLAN
               interface['acl_in'] = self.LOCAL_ACL_FORMAT % (self.pri_name)
               return interface
       
           def _make_gw_interface(self, port_set):
               interface = {}
               interface['acl_in'] = self.PORTSET_ACL_FORMAT % (self.pri_name, port_set)
      -        interface['native_vlan'] = self._port_set_vlan(port_set)
      +        vlan_id = self._DUMP_VLAN if self._use_vlan_triggers() else self._port_set_vlan(port_set)
      +        interface['native_vlan'] = vlan_id
               return interface
       
      -    def _update_port_vlan(self, port_no, port_set):
      -        interface = self.topology['dps'][self.sec_name]['interfaces'][port_no]
      -        interface['native_vlan'] = self._port_set_vlan(port_set)
      -
      -    def _port_set_vlan(self, port_set=None):
      -        return self._VLAN_BASE + (port_set if port_set else 0)
      +    def _port_set_vlan(self, port_set):
      +        return self._LOCAL_VLAN + port_set if port_set else self._DUMP_VLAN
       
           def _make_pri_trunk_interface(self):
               interface = {}
      @@ -200,14 +194,17 @@ def _make_sec_trunk_interface(self):
               interface['name'] = self.get_ext_intf() or self._DEFAULT_SEC_TRUNK_NAME
               return interface
       
      +    def _use_vlan_triggers(self):
      +        vlan_range_config = self.config.get("run_trigger", {})
      +        return bool(vlan_range_config.get("vlan_start"))
      +
           def _vlan_tags(self):
               vlan_range_config = self.config.get("run_trigger", {})
      -        test_vlan_start = vlan_range_config.get("vlan_start")
      -        test_vlan_end = vlan_range_config.get("vlan_end")
      -        if test_vlan_start is not None and test_vlan_end is not None:
      -            return [*range(self._VLAN_BASE, self._VLAN_BASE + self.sec_port),
      -                    *range(test_vlan_start, test_vlan_end + 1)]
      -        return list(range(self._VLAN_BASE, self._VLAN_BASE + self.sec_port))
      +        vlan_start = vlan_range_config.get("vlan_start")
      +        vlan_end = vlan_range_config.get("vlan_end")
      +        if self._use_vlan_triggers():
      +            return [*range(vlan_start, vlan_end + 1)] + [self._LOCAL_VLAN]
      +        return list(range(self._LOCAL_VLAN, self._LOCAL_VLAN + self.sec_port))
       
           def _make_default_acl_rules(self):
               rules = []
      @@ -218,7 +215,8 @@ def _make_default_acl_rules(self):
           def _make_sec_port_interface(self, port_no):
               interface = {}
               interface['acl_in'] = self.PORT_ACL_NAME_FORMAT % (self.sec_name, port_no)
      -        interface['native_vlan'] = self._port_set_vlan()
      +        vlan_id = self._port_set_vlan(port_no) if self._use_vlan_triggers() else self._DUMP_VLAN
      +        interface['native_vlan'] = vlan_id
               return interface
       
           def _make_pri_interfaces(self):
      @@ -229,7 +227,7 @@ def _make_pri_interfaces(self):
                       interfaces[port] = self._make_gw_interface(port_set)
                   mirror_port = self.mirror_port(port_set)
                   interfaces[mirror_port] = self._make_mirror_interface(port_set)
      -        interfaces[self._SWITCH_LOCAL_PORT] = self._make_switch_interface()
      +        interfaces[self._SWITCH_LOCAL_PORT] = self._make_local_interface()
               return interfaces
       
           def _make_sec_interfaces(self):
      diff --git a/firebase/public/protos.hash b/firebase/public/protos.hash
      index 0e00dc5b0c..e8117458c0 100644
      --- a/firebase/public/protos.hash
      +++ b/firebase/public/protos.hash
      @@ -1 +1 @@
      -57a09959d00dcb455cff637de1ac9aba897a6517  proto/system_config.proto
      +d0774fd8d947d144780f99ea2034c9a650f1ecdd  proto/system_config.proto
      diff --git a/firebase/public/protos.html b/firebase/public/protos.html
      index 03c67b466e..7819ad028b 100644
      --- a/firebase/public/protos.html
      +++ b/firebase/public/protos.html
      @@ -207,12 +207,12 @@ 

      Table of Contents

    • - MUSISetup + MUsiSetup
    • - EDHCPMode + EDhcpMode
    • @@ -496,7 +496,7 @@

      DaqConfig

      usi_setup - USISetup + UsiSetup

      USI url

      @@ -677,6 +677,13 @@

      RunTrigger

      end of vlan range

      + + egress_vlan + int32 + +

      egress vlan

      + + @@ -792,7 +799,7 @@

      SwitchSetup

      -

      USISetup

      +

      UsiSetup

      USI paramters

      @@ -825,7 +832,7 @@

      USISetup

      -

      DHCPMode

      +

      DhcpMode

      diff --git a/libs/proto/system_config_pb2.py b/libs/proto/system_config_pb2.py index 14d3092b62..a65af762cf 100644 --- a/libs/proto/system_config_pb2.py +++ b/libs/proto/system_config_pb2.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # Generated by the protocol buffer compiler. DO NOT EDIT! # source: daq/proto/system_config.proto - +"""Generated protocol buffer code.""" from google.protobuf.internal import enum_type_wrapper from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message @@ -19,44 +19,51 @@ package='', syntax='proto3', serialized_options=None, - serialized_pb=b'\n\x1d\x64\x61q/proto/system_config.proto\"\x94\t\n\tDaqConfig\x12\x18\n\x10site_description\x18\x01 \x01(\t\x12\x18\n\x10monitor_scan_sec\x18\x02 \x01(\x05\x12\x1b\n\x13\x64\x65\x66\x61ult_timeout_sec\x18\x03 \x01(\x05\x12\x12\n\nsettle_sec\x18& \x01(\x05\x12\x11\n\tbase_conf\x18\x04 \x01(\t\x12\x11\n\tsite_path\x18\x05 \x01(\t\x12\x1f\n\x17initial_dhcp_lease_time\x18\x06 \x01(\t\x12\x17\n\x0f\x64hcp_lease_time\x18\x07 \x01(\t\x12\x19\n\x11\x64hcp_response_sec\x18\' \x01(\x05\x12\x1e\n\x16long_dhcp_response_sec\x18\x08 \x01(\x05\x12\"\n\x0cswitch_setup\x18\t \x01(\x0b\x32\x0c.SwitchSetup\x12\x12\n\nhost_tests\x18\x10 \x01(\t\x12\x13\n\x0b\x62uild_tests\x18$ \x01(\x08\x12\x11\n\trun_limit\x18\x11 \x01(\x05\x12\x11\n\tfail_mode\x18\x12 \x01(\x08\x12\x13\n\x0bsingle_shot\x18\" \x01(\x08\x12\x15\n\rresult_linger\x18\x13 \x01(\x08\x12\x0f\n\x07no_test\x18\x14 \x01(\x08\x12\x11\n\tkeep_hold\x18( \x01(\x08\x12\x14\n\x0c\x64\x61q_loglevel\x18\x15 \x01(\t\x12\x18\n\x10mininet_loglevel\x18\x16 \x01(\t\x12\x13\n\x0b\x66inish_hook\x18# \x01(\t\x12\x10\n\x08gcp_cred\x18\x17 \x01(\t\x12\x11\n\tgcp_topic\x18\x18 \x01(\t\x12\x13\n\x0bschema_path\x18\x19 \x01(\t\x12\x11\n\tmud_files\x18\x1a \x01(\t\x12\x14\n\x0c\x64\x65vice_specs\x18\x1b \x01(\t\x12\x13\n\x0btest_config\x18\x1c \x01(\t\x12\x19\n\x11port_debounce_sec\x18\x1d \x01(\x05\x12\x15\n\rtopology_hook\x18\x1e \x01(\t\x12\x17\n\x0f\x64\x65vice_template\x18\x1f \x01(\t\x12\x14\n\x0csite_reports\x18 \x01(\t\x12\x1f\n\x17run_data_retention_days\x18! \x01(\x02\x12.\n\ninterfaces\x18% \x03(\x0b\x32\x1a.DaqConfig.InterfacesEntry\x12/\n\x0b\x66\x61il_module\x18/ \x03(\x0b\x32\x1a.DaqConfig.FailModuleEntry\x12\x1d\n\x15port_flap_timeout_sec\x18\x30 \x01(\x05\x12\x1c\n\tusi_setup\x18\x31 \x01(\x0b\x32\t.USISetup\x12 \n\x0brun_trigger\x18\x32 \x01(\x0b\x32\x0b.RunTrigger\x12\x12\n\ndebug_mode\x18\x33 \x01(\x08\x12\x13\n\x0buse_console\x18\x34 \x01(\x08\x12*\n\x10\x64\x65vice_reporting\x18\x35 \x01(\x0b\x32\x10.DeviceReporting\x1a=\n\x0fInterfacesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x19\n\x05value\x18\x02 \x01(\x0b\x32\n.Interface:\x02\x38\x01\x1a\x31\n\x0f\x46\x61ilModuleEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"0\n\x08USISetup\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x17\n\x0frpc_timeout_sec\x18\x02 \x01(\x05\"\xf4\x01\n\x0bSwitchSetup\x12\x11\n\tctrl_intf\x18\t \x01(\t\x12\x0f\n\x07ip_addr\x18\x0b \x01(\t\x12\x13\n\x0buplink_port\x18\r \x01(\x05\x12\x0f\n\x07lo_port\x18\x0e \x01(\x05\x12\x10\n\x08\x61lt_port\x18\x10 \x01(\x05\x12\x0f\n\x07lo_addr\x18\x12 \x01(\t\x12\x11\n\tmods_addr\x18\x14 \x01(\t\x12\x0f\n\x07of_dpid\x18) \x01(\t\x12\x11\n\tdata_intf\x18* \x01(\t\x12\x0e\n\x06\x65xt_br\x18+ \x01(\t\x12\r\n\x05model\x18, \x01(\t\x12\x10\n\x08username\x18- \x01(\t\x12\x10\n\x08password\x18. \x01(\t\"2\n\nRunTrigger\x12\x12\n\nvlan_start\x18\x01 \x01(\x05\x12\x10\n\x08vlan_end\x18\x02 \x01(\x05\"\'\n\tInterface\x12\x0c\n\x04opts\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05\"&\n\x0f\x44\x65viceReporting\x12\x13\n\x0bserver_port\x18\x01 \x01(\x05*U\n\x08\x44HCPMode\x12\n\n\x06NORMAL\x10\x00\x12\r\n\tSTATIC_IP\x10\x01\x12\x0c\n\x08\x45XTERNAL\x10\x02\x12\x11\n\rLONG_RESPONSE\x10\x03\x12\r\n\tIP_CHANGE\x10\x04\x62\x06proto3' + create_key=_descriptor._internal_create_key, + serialized_pb=b'\n\x1d\x64\x61q/proto/system_config.proto\"\x94\t\n\tDaqConfig\x12\x18\n\x10site_description\x18\x01 \x01(\t\x12\x18\n\x10monitor_scan_sec\x18\x02 \x01(\x05\x12\x1b\n\x13\x64\x65\x66\x61ult_timeout_sec\x18\x03 \x01(\x05\x12\x12\n\nsettle_sec\x18& \x01(\x05\x12\x11\n\tbase_conf\x18\x04 \x01(\t\x12\x11\n\tsite_path\x18\x05 \x01(\t\x12\x1f\n\x17initial_dhcp_lease_time\x18\x06 \x01(\t\x12\x17\n\x0f\x64hcp_lease_time\x18\x07 \x01(\t\x12\x19\n\x11\x64hcp_response_sec\x18\' \x01(\x05\x12\x1e\n\x16long_dhcp_response_sec\x18\x08 \x01(\x05\x12\"\n\x0cswitch_setup\x18\t \x01(\x0b\x32\x0c.SwitchSetup\x12\x12\n\nhost_tests\x18\x10 \x01(\t\x12\x13\n\x0b\x62uild_tests\x18$ \x01(\x08\x12\x11\n\trun_limit\x18\x11 \x01(\x05\x12\x11\n\tfail_mode\x18\x12 \x01(\x08\x12\x13\n\x0bsingle_shot\x18\" \x01(\x08\x12\x15\n\rresult_linger\x18\x13 \x01(\x08\x12\x0f\n\x07no_test\x18\x14 \x01(\x08\x12\x11\n\tkeep_hold\x18( \x01(\x08\x12\x14\n\x0c\x64\x61q_loglevel\x18\x15 \x01(\t\x12\x18\n\x10mininet_loglevel\x18\x16 \x01(\t\x12\x13\n\x0b\x66inish_hook\x18# \x01(\t\x12\x10\n\x08gcp_cred\x18\x17 \x01(\t\x12\x11\n\tgcp_topic\x18\x18 \x01(\t\x12\x13\n\x0bschema_path\x18\x19 \x01(\t\x12\x11\n\tmud_files\x18\x1a \x01(\t\x12\x14\n\x0c\x64\x65vice_specs\x18\x1b \x01(\t\x12\x13\n\x0btest_config\x18\x1c \x01(\t\x12\x19\n\x11port_debounce_sec\x18\x1d \x01(\x05\x12\x15\n\rtopology_hook\x18\x1e \x01(\t\x12\x17\n\x0f\x64\x65vice_template\x18\x1f \x01(\t\x12\x14\n\x0csite_reports\x18 \x01(\t\x12\x1f\n\x17run_data_retention_days\x18! \x01(\x02\x12.\n\ninterfaces\x18% \x03(\x0b\x32\x1a.DaqConfig.InterfacesEntry\x12/\n\x0b\x66\x61il_module\x18/ \x03(\x0b\x32\x1a.DaqConfig.FailModuleEntry\x12\x1d\n\x15port_flap_timeout_sec\x18\x30 \x01(\x05\x12\x1c\n\tusi_setup\x18\x31 \x01(\x0b\x32\t.UsiSetup\x12 \n\x0brun_trigger\x18\x32 \x01(\x0b\x32\x0b.RunTrigger\x12\x12\n\ndebug_mode\x18\x33 \x01(\x08\x12\x13\n\x0buse_console\x18\x34 \x01(\x08\x12*\n\x10\x64\x65vice_reporting\x18\x35 \x01(\x0b\x32\x10.DeviceReporting\x1a=\n\x0fInterfacesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x19\n\x05value\x18\x02 \x01(\x0b\x32\n.Interface:\x02\x38\x01\x1a\x31\n\x0f\x46\x61ilModuleEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"0\n\x08UsiSetup\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x17\n\x0frpc_timeout_sec\x18\x02 \x01(\x05\"\xf4\x01\n\x0bSwitchSetup\x12\x11\n\tctrl_intf\x18\t \x01(\t\x12\x0f\n\x07ip_addr\x18\x0b \x01(\t\x12\x13\n\x0buplink_port\x18\r \x01(\x05\x12\x0f\n\x07lo_port\x18\x0e \x01(\x05\x12\x10\n\x08\x61lt_port\x18\x10 \x01(\x05\x12\x0f\n\x07lo_addr\x18\x12 \x01(\t\x12\x11\n\tmods_addr\x18\x14 \x01(\t\x12\x0f\n\x07of_dpid\x18) \x01(\t\x12\x11\n\tdata_intf\x18* \x01(\t\x12\x0e\n\x06\x65xt_br\x18+ \x01(\t\x12\r\n\x05model\x18, \x01(\t\x12\x10\n\x08username\x18- \x01(\t\x12\x10\n\x08password\x18. \x01(\t\"G\n\nRunTrigger\x12\x12\n\nvlan_start\x18\x01 \x01(\x05\x12\x10\n\x08vlan_end\x18\x02 \x01(\x05\x12\x13\n\x0b\x65gress_vlan\x18\x03 \x01(\x05\"\'\n\tInterface\x12\x0c\n\x04opts\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05\"&\n\x0f\x44\x65viceReporting\x12\x13\n\x0bserver_port\x18\x01 \x01(\x05*U\n\x08\x44hcpMode\x12\n\n\x06NORMAL\x10\x00\x12\r\n\tSTATIC_IP\x10\x01\x12\x0c\n\x08\x45XTERNAL\x10\x02\x12\x11\n\rLONG_RESPONSE\x10\x03\x12\r\n\tIP_CHANGE\x10\x04\x62\x06proto3' ) _DHCPMODE = _descriptor.EnumDescriptor( - name='DHCPMode', - full_name='DHCPMode', + name='DhcpMode', + full_name='DhcpMode', filename=None, file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, values=[ _descriptor.EnumValueDescriptor( name='NORMAL', index=0, number=0, serialized_options=None, - type=None), + type=None, + create_key=_descriptor._internal_create_key), _descriptor.EnumValueDescriptor( name='STATIC_IP', index=1, number=1, serialized_options=None, - type=None), + type=None, + create_key=_descriptor._internal_create_key), _descriptor.EnumValueDescriptor( name='EXTERNAL', index=2, number=2, serialized_options=None, - type=None), + type=None, + create_key=_descriptor._internal_create_key), _descriptor.EnumValueDescriptor( name='LONG_RESPONSE', index=3, number=3, serialized_options=None, - type=None), + type=None, + create_key=_descriptor._internal_create_key), _descriptor.EnumValueDescriptor( name='IP_CHANGE', index=4, number=4, serialized_options=None, - type=None), + type=None, + create_key=_descriptor._internal_create_key), ], containing_type=None, serialized_options=None, - serialized_start=1638, - serialized_end=1723, + serialized_start=1659, + serialized_end=1744, ) _sym_db.RegisterEnumDescriptor(_DHCPMODE) -DHCPMode = enum_type_wrapper.EnumTypeWrapper(_DHCPMODE) +DhcpMode = enum_type_wrapper.EnumTypeWrapper(_DHCPMODE) NORMAL = 0 STATIC_IP = 1 EXTERNAL = 2 @@ -71,6 +78,7 @@ filename=None, file=DESCRIPTOR, containing_type=None, + create_key=_descriptor._internal_create_key, fields=[ _descriptor.FieldDescriptor( name='key', full_name='DaqConfig.InterfacesEntry.key', index=0, @@ -78,14 +86,14 @@ has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='value', full_name='DaqConfig.InterfacesEntry.value', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), ], extensions=[ ], @@ -108,6 +116,7 @@ filename=None, file=DESCRIPTOR, containing_type=None, + create_key=_descriptor._internal_create_key, fields=[ _descriptor.FieldDescriptor( name='key', full_name='DaqConfig.FailModuleEntry.key', index=0, @@ -115,14 +124,14 @@ has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='value', full_name='DaqConfig.FailModuleEntry.value', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), ], extensions=[ ], @@ -145,6 +154,7 @@ filename=None, file=DESCRIPTOR, containing_type=None, + create_key=_descriptor._internal_create_key, fields=[ _descriptor.FieldDescriptor( name='site_description', full_name='DaqConfig.site_description', index=0, @@ -152,287 +162,287 @@ has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='monitor_scan_sec', full_name='DaqConfig.monitor_scan_sec', index=1, number=2, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='default_timeout_sec', full_name='DaqConfig.default_timeout_sec', index=2, number=3, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='settle_sec', full_name='DaqConfig.settle_sec', index=3, number=38, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='base_conf', full_name='DaqConfig.base_conf', index=4, number=4, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='site_path', full_name='DaqConfig.site_path', index=5, number=5, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='initial_dhcp_lease_time', full_name='DaqConfig.initial_dhcp_lease_time', index=6, number=6, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='dhcp_lease_time', full_name='DaqConfig.dhcp_lease_time', index=7, number=7, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='dhcp_response_sec', full_name='DaqConfig.dhcp_response_sec', index=8, number=39, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='long_dhcp_response_sec', full_name='DaqConfig.long_dhcp_response_sec', index=9, number=8, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='switch_setup', full_name='DaqConfig.switch_setup', index=10, number=9, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='host_tests', full_name='DaqConfig.host_tests', index=11, number=16, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='build_tests', full_name='DaqConfig.build_tests', index=12, number=36, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='run_limit', full_name='DaqConfig.run_limit', index=13, number=17, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='fail_mode', full_name='DaqConfig.fail_mode', index=14, number=18, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='single_shot', full_name='DaqConfig.single_shot', index=15, number=34, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='result_linger', full_name='DaqConfig.result_linger', index=16, number=19, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='no_test', full_name='DaqConfig.no_test', index=17, number=20, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='keep_hold', full_name='DaqConfig.keep_hold', index=18, number=40, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='daq_loglevel', full_name='DaqConfig.daq_loglevel', index=19, number=21, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='mininet_loglevel', full_name='DaqConfig.mininet_loglevel', index=20, number=22, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='finish_hook', full_name='DaqConfig.finish_hook', index=21, number=35, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='gcp_cred', full_name='DaqConfig.gcp_cred', index=22, number=23, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='gcp_topic', full_name='DaqConfig.gcp_topic', index=23, number=24, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='schema_path', full_name='DaqConfig.schema_path', index=24, number=25, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='mud_files', full_name='DaqConfig.mud_files', index=25, number=26, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='device_specs', full_name='DaqConfig.device_specs', index=26, number=27, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='test_config', full_name='DaqConfig.test_config', index=27, number=28, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='port_debounce_sec', full_name='DaqConfig.port_debounce_sec', index=28, number=29, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='topology_hook', full_name='DaqConfig.topology_hook', index=29, number=30, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='device_template', full_name='DaqConfig.device_template', index=30, number=31, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='site_reports', full_name='DaqConfig.site_reports', index=31, number=32, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='run_data_retention_days', full_name='DaqConfig.run_data_retention_days', index=32, number=33, type=2, cpp_type=6, label=1, has_default_value=False, default_value=float(0), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='interfaces', full_name='DaqConfig.interfaces', index=33, number=37, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='fail_module', full_name='DaqConfig.fail_module', index=34, number=47, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='port_flap_timeout_sec', full_name='DaqConfig.port_flap_timeout_sec', index=35, number=48, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='usi_setup', full_name='DaqConfig.usi_setup', index=36, number=49, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='run_trigger', full_name='DaqConfig.run_trigger', index=37, number=50, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='debug_mode', full_name='DaqConfig.debug_mode', index=38, number=51, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='use_console', full_name='DaqConfig.use_console', index=39, number=52, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='device_reporting', full_name='DaqConfig.device_reporting', index=40, number=53, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), ], extensions=[ ], @@ -451,26 +461,27 @@ _USISETUP = _descriptor.Descriptor( - name='USISetup', - full_name='USISetup', + name='UsiSetup', + full_name='UsiSetup', filename=None, file=DESCRIPTOR, containing_type=None, + create_key=_descriptor._internal_create_key, fields=[ _descriptor.FieldDescriptor( - name='url', full_name='USISetup.url', index=0, + name='url', full_name='UsiSetup.url', index=0, number=1, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( - name='rpc_timeout_sec', full_name='USISetup.rpc_timeout_sec', index=1, + name='rpc_timeout_sec', full_name='UsiSetup.rpc_timeout_sec', index=1, number=2, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), ], extensions=[ ], @@ -494,6 +505,7 @@ filename=None, file=DESCRIPTOR, containing_type=None, + create_key=_descriptor._internal_create_key, fields=[ _descriptor.FieldDescriptor( name='ctrl_intf', full_name='SwitchSetup.ctrl_intf', index=0, @@ -501,91 +513,91 @@ has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='ip_addr', full_name='SwitchSetup.ip_addr', index=1, number=11, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='uplink_port', full_name='SwitchSetup.uplink_port', index=2, number=13, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='lo_port', full_name='SwitchSetup.lo_port', index=3, number=14, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='alt_port', full_name='SwitchSetup.alt_port', index=4, number=16, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='lo_addr', full_name='SwitchSetup.lo_addr', index=5, number=18, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='mods_addr', full_name='SwitchSetup.mods_addr', index=6, number=20, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='of_dpid', full_name='SwitchSetup.of_dpid', index=7, number=41, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='data_intf', full_name='SwitchSetup.data_intf', index=8, number=42, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='ext_br', full_name='SwitchSetup.ext_br', index=9, number=43, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='model', full_name='SwitchSetup.model', index=10, number=44, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='username', full_name='SwitchSetup.username', index=11, number=45, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='password', full_name='SwitchSetup.password', index=12, number=46, type=9, cpp_type=9, label=1, has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), ], extensions=[ ], @@ -609,6 +621,7 @@ filename=None, file=DESCRIPTOR, containing_type=None, + create_key=_descriptor._internal_create_key, fields=[ _descriptor.FieldDescriptor( name='vlan_start', full_name='RunTrigger.vlan_start', index=0, @@ -616,14 +629,21 @@ has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='vlan_end', full_name='RunTrigger.vlan_end', index=1, number=2, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='egress_vlan', full_name='RunTrigger.egress_vlan', index=2, + number=3, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), ], extensions=[ ], @@ -637,7 +657,7 @@ oneofs=[ ], serialized_start=1505, - serialized_end=1555, + serialized_end=1576, ) @@ -647,6 +667,7 @@ filename=None, file=DESCRIPTOR, containing_type=None, + create_key=_descriptor._internal_create_key, fields=[ _descriptor.FieldDescriptor( name='opts', full_name='Interface.opts', index=0, @@ -654,14 +675,14 @@ has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='port', full_name='Interface.port', index=1, number=2, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), ], extensions=[ ], @@ -674,8 +695,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1557, - serialized_end=1596, + serialized_start=1578, + serialized_end=1617, ) @@ -685,6 +706,7 @@ filename=None, file=DESCRIPTOR, containing_type=None, + create_key=_descriptor._internal_create_key, fields=[ _descriptor.FieldDescriptor( name='server_port', full_name='DeviceReporting.server_port', index=0, @@ -692,7 +714,7 @@ has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), ], extensions=[ ], @@ -705,8 +727,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1598, - serialized_end=1636, + serialized_start=1619, + serialized_end=1657, ) _DAQCONFIG_INTERFACESENTRY.fields_by_name['value'].message_type = _INTERFACE @@ -719,12 +741,12 @@ _DAQCONFIG.fields_by_name['run_trigger'].message_type = _RUNTRIGGER _DAQCONFIG.fields_by_name['device_reporting'].message_type = _DEVICEREPORTING DESCRIPTOR.message_types_by_name['DaqConfig'] = _DAQCONFIG -DESCRIPTOR.message_types_by_name['USISetup'] = _USISETUP +DESCRIPTOR.message_types_by_name['UsiSetup'] = _USISETUP DESCRIPTOR.message_types_by_name['SwitchSetup'] = _SWITCHSETUP DESCRIPTOR.message_types_by_name['RunTrigger'] = _RUNTRIGGER DESCRIPTOR.message_types_by_name['Interface'] = _INTERFACE DESCRIPTOR.message_types_by_name['DeviceReporting'] = _DEVICEREPORTING -DESCRIPTOR.enum_types_by_name['DHCPMode'] = _DHCPMODE +DESCRIPTOR.enum_types_by_name['DhcpMode'] = _DHCPMODE _sym_db.RegisterFileDescriptor(DESCRIPTOR) DaqConfig = _reflection.GeneratedProtocolMessageType('DaqConfig', (_message.Message,), { @@ -750,12 +772,12 @@ _sym_db.RegisterMessage(DaqConfig.InterfacesEntry) _sym_db.RegisterMessage(DaqConfig.FailModuleEntry) -USISetup = _reflection.GeneratedProtocolMessageType('USISetup', (_message.Message,), { +UsiSetup = _reflection.GeneratedProtocolMessageType('UsiSetup', (_message.Message,), { 'DESCRIPTOR' : _USISETUP, '__module__' : 'daq.proto.system_config_pb2' - # @@protoc_insertion_point(class_scope:USISetup) + # @@protoc_insertion_point(class_scope:UsiSetup) }) -_sym_db.RegisterMessage(USISetup) +_sym_db.RegisterMessage(UsiSetup) SwitchSetup = _reflection.GeneratedProtocolMessageType('SwitchSetup', (_message.Message,), { 'DESCRIPTOR' : _SWITCHSETUP, diff --git a/proto/system_config.proto b/proto/system_config.proto index 812d55eafa..3d479ad6cf 100644 --- a/proto/system_config.proto +++ b/proto/system_config.proto @@ -116,7 +116,7 @@ message DaqConfig { int32 port_flap_timeout_sec = 48; // USI url - USISetup usi_setup = 49; + UsiSetup usi_setup = 49; // Configures events that trigger a DAQ run RunTrigger run_trigger = 50; @@ -131,7 +131,7 @@ message DaqConfig { DeviceReporting device_reporting = 53; } -enum DHCPMode { +enum DhcpMode { NORMAL = 0; STATIC_IP = 1; EXTERNAL = 2; @@ -142,7 +142,7 @@ enum DHCPMode { /** * USI paramters **/ -message USISetup { +message UsiSetup { string url = 1; int32 rpc_timeout_sec = 2; } @@ -201,6 +201,9 @@ message RunTrigger { // end of vlan range int32 vlan_end = 2; + + // egress vlan + int32 egress_vlan = 3; } /* diff --git a/testing/test_base.out b/testing/test_base.out index 1e6a149ff4..22b48a6e2d 100644 --- a/testing/test_base.out +++ b/testing/test_base.out @@ -158,7 +158,7 @@ Switch test with target 192.0.2.138:2 Monolog processing base.switch.ping... switch ping 2 %%%%%%%%%%%%%%%%%%%%%% Alt switch tests -XXX runner INFO 9a:02:57:1e:8f:01 learned on vid 2000 +XXX runner INFO 9a:02:57:1e:8f:01 learned on vid 1002 Correct IP: 1 9a02571e8f01: ['9a02571e8f01:ping:1'] %%%%%%%%%%%%%%%%%%%%%% Mud profile tests diff --git a/testing/test_base.sh b/testing/test_base.sh index b3f3e1857c..3d76b41e52 100755 --- a/testing/test_base.sh +++ b/testing/test_base.sh @@ -71,7 +71,7 @@ function restart_networking { monitor_log "Added link faux-2 as port 3 on alt-switch" configure_networking monitor_log "Target device 9a02571e8f01 waiting for ip" restart_networking timeout 1200s cmd/run -s -fgrep '9a:02:57:1e:8f:01 learned on vid 2000' inst/cmdrun.log | head -1 | redact | tee -a $TEST_RESULTS +fgrep '9a:02:57:1e:8f:01 learned on vid 1002' inst/cmdrun.log | head -1 | redact | tee -a $TEST_RESULTS correct_ips=$(fgrep '10.20.99' inst/run-9a02571e8f01/scans/ip_triggers.txt | wc -l) echo Correct IP: $correct_ips | tee -a $TEST_RESULTS cat inst/result.log | grep 9a02571e8f01 | tee -a $TEST_RESULTS From c8d5d8c44f7275e80eb044d39b2672407f2a126f Mon Sep 17 00:00:00 2001 From: Trevor Date: Sun, 1 Nov 2020 18:52:20 -0800 Subject: [PATCH 190/212] Minor refactor of port activation logic (#705) --- daq/runner.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/daq/runner.py b/daq/runner.py index afe4cf89ab..0212af2491 100644 --- a/daq/runner.py +++ b/daq/runner.py @@ -82,6 +82,11 @@ def new_device(self, mac, port_info=None, vlan=None): device.set_id = set_id return device + def create_if_absent(self, mac, port_info=None, vlan=None): + """Create a new device if none found, else return the previous one""" + prev_device = self._devices.get(mac) + return prev_device if prev_device else self.new_device(mac, port_info=port_info, vlan=vlan) + def _allocate_set_id(self): set_id = 1 while set_id in self._set_ids: @@ -307,11 +312,7 @@ def _handle_port_state(self, dpid, port, active): LOGGER.debug('Unknown port %s on dpid %s is active %s', port, dpid, active) return - if port not in self._ports: - self._ports[port] = PortInfo() - self._ports[port].port_no = port - - if active != self._ports[port].active: + if active != self._is_port_active(port): LOGGER.info('Port %s dpid %s is now %s', port, dpid, "active" if active else "inactive") if active: self._activate_port(port) @@ -327,10 +328,16 @@ def _handle_port_state(self, dpid, port, active): self._send_heartbeat() def _activate_port(self, port): + if port not in self._ports: + self._ports[port] = PortInfo() + self._ports[port].port_no = port port_info = self._ports[port] port_info.flapping_start = 0 port_info.active = True + def _is_port_active(self, port): + return port in self._ports and self._ports[port].active + def _deactivate_port(self, port): port_info = self._ports[port] port_info.active = False @@ -339,14 +346,10 @@ def _direct_port_traffic(self, mac, port, target): self.network.direct_port_traffic(mac, port, target) def _handle_port_learn(self, dpid, port, vid, target_mac): - if self.network.is_device_port(dpid, port): + if self.network.is_device_port(dpid, port) and self._is_port_active(port): LOGGER.info('Port %s dpid %s learned %s', port, dpid, target_mac) - if port not in self._ports: - self._ports[port] = PortInfo() - self._ports[port].port_no = port - if not self._devices.get(target_mac): - self._devices.new_device(target_mac, port_info=self._ports[port]) - self._target_set_trigger(self._devices.get(target_mac)) + device = self._devices.create_if_absent(target_mac, port_info=self._ports[port]) + self._target_set_trigger(device) else: LOGGER.debug('Port %s dpid %s learned %s (ignored)', port, dpid, target_mac) From 245bb0a087410003edef5dba62a8114404b9d842 Mon Sep 17 00:00:00 2001 From: Trevor Date: Sun, 1 Nov 2020 18:53:20 -0800 Subject: [PATCH 191/212] Dynamically generate dhcp reflection for vlan triggers (#701) --- .gitignore | 3 + cmd/exrun | 3 + cmd/faucet | 2 + cmd/faux | 23 ++++--- config/faucet/faucet_alt-switch.yaml | 2 +- config/system/alt.yaml | 2 +- daq/dhcp_monitor.py | 52 +++++++++------ daq/host.py | 23 ++++--- daq/network.py | 13 ++-- daq/runner.py | 28 ++++---- daq/topology.py | 64 +++++++++++++++++-- .../network/scripts/autorestart_dnsmasq | 3 +- .../include/network/scripts/start_networking | 12 +++- etc/FAUCET_VERSION | 2 +- subset/ping/test_ping | 3 +- testing/test_base.out | 11 +++- testing/test_base.sh | 27 +++----- 17 files changed, 188 insertions(+), 85 deletions(-) diff --git a/.gitignore b/.gitignore index 0ee48512c9..5212e1d450 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,9 @@ protoc-gen-doc/ firebase/public/firebase_config.js firebase/public/deploy_version.js +# Kleudgy apparmor workaround +binhack/tcpdump + validations/ \#* diff --git a/cmd/exrun b/cmd/exrun index daeec10bb3..30ef0e02e2 100755 --- a/cmd/exrun +++ b/cmd/exrun @@ -86,6 +86,9 @@ $ovsctl status || sudo $ovsctl start sudo rm -f $cleanup_file +# Hacky workaround for apparmor protection of tcpdump. Without this, the process can not be killed. +cp `which tcpdump` binhack/ + function autostart { tmp=`mktemp` echo DAQ autostart $@ diff --git a/cmd/faucet b/cmd/faucet index 65a9347c48..f2e091e821 100755 --- a/cmd/faucet +++ b/cmd/faucet @@ -5,6 +5,7 @@ CONTAINER=daq-faucet INSTDIR=$ROOT/inst IMAGE=daqf/faucet FAUCET_SOCK=faucet_event.sock +FAUCET_LOG=faucet.log SYSTEM_CONF=system.conf LOCAL_CONFIG=local/$SYSTEM_CONF @@ -51,6 +52,7 @@ fi echo Creating $IMAGE instance $CONTAINER on port $faucet_pt in $INSTDIR mkdir -p $INSTDIR +rm -f $INSTDIR/$FAUCET_LOG if docker container inspect $CONTAINER --format '{{ .Name }}' > /dev/null 2>&1; then echo -n "Clensing old container " diff --git a/cmd/faux b/cmd/faux index 9180732935..e3eb7b57e4 100755 --- a/cmd/faux +++ b/cmd/faux @@ -11,6 +11,7 @@ networking= alt_faux= image=daqf/faux1 build= +realintf= cd $ROOT source etc/config_base.sh @@ -63,6 +64,7 @@ if [ -n "$networking" ]; then container_prefix=daq-networking image=daqf/networking net_opt= + docker_args+=" -e IP_SUBNET=99" else container_prefix=daq-faux net_opt=--net=none @@ -75,6 +77,7 @@ fi FAUX_ARGS="$*" CONTAINER=$container_prefix$postfix +virtintf=faux$postfix if [ -z "$FAUX_ARGS" ]; then FAUX_ARGS="$faux_args" @@ -105,7 +108,11 @@ elif [ -n "$test_config" ]; then echo Config dir $CONFIG_DIR not found. fi -docker_args="$docker_args -e LOCAL_IF=$realintf" +if [ -n "$realintf" ]; then + docker_args+=" -e LOCAL_IF=$realintf" +else + docker_args+=" -e LOCAL_IF=faux-eth0" +fi cid=$(docker run -d --privileged --name $CONTAINER --hostname $CONTAINER $net_opt $docker_args $image $FAUX_ARGS) pid=$(docker inspect --format="{{ .State.Pid }}" $cid) @@ -118,19 +125,19 @@ if [ -n "$realintf" ]; then docker exec $CONTAINER ip link set $realintf up docker exec $CONTAINER ip link show $realintf else - intf=faux$postfix - echo Removing old interface $intf - sudo ip link del $intf 2>/dev/null || true + echo Removing old interface $virtintf + sudo ip link del $virtintf 2>/dev/null || true echo Adding new interface to $pid... - sudo ip link add $intf type veth peer name faux-eth0 addr $intf_mac netns $pid - sudo ip link set $intf up + sudo ip link add $virtintf type veth peer name faux-eth0 addr $intf_mac netns $pid + sudo ip link set $virtintf up + docker exec $CONTAINER ip link set faux-eth0 up fi if [ -n "$create_local" ]; then - sudo ip addr add 10.20.0.1/16 broadcast 10.20.255.255 dev $intf - sudo ip addr show dev $intf + sudo ip addr add 10.20.0.1/16 broadcast 10.20.255.255 dev $virtintf + sudo ip addr show dev $virtintf fi echo Done with faux device launch. diff --git a/config/faucet/faucet_alt-switch.yaml b/config/faucet/faucet_alt-switch.yaml index d4883b5a85..a5ed5e606c 100644 --- a/config/faucet/faucet_alt-switch.yaml +++ b/config/faucet/faucet_alt-switch.yaml @@ -7,7 +7,7 @@ dps: 2: native_vlan: 1002 3: - native_vlan: 1002 + native_vlan: 1003 4: native_vlan: 1004 5: diff --git a/config/system/alt.yaml b/config/system/alt.yaml index 8c2216db3f..1ed1450d5b 100644 --- a/config/system/alt.yaml +++ b/config/system/alt.yaml @@ -21,7 +21,7 @@ interfaces: port: 2 faux-2: opts: -n - port: 3 + port: 11 default_timeout_sec: 120 diff --git a/daq/dhcp_monitor.py b/daq/dhcp_monitor.py index 8896ce91e2..15124eac2c 100644 --- a/daq/dhcp_monitor.py +++ b/daq/dhcp_monitor.py @@ -13,10 +13,14 @@ class DhcpMonitor: """Class to handle DHCP monitoring""" + DHCP_START_PATTERN = 'BOOTP/DHCP' DHCP_IP_PATTERN = 'Your-IP ([0-9.]+)' - DHCP_TYPE_PATTERN = 'DHCP-Message Option 53, length 1: ([a-zA-Z]+)' DHCP_MAC_PATTERN = 'Client-Ethernet-Address ([a-z0-9:]+)' - DHCP_PATTERN = '(%s)|(%s)|(%s)' % (DHCP_IP_PATTERN, DHCP_TYPE_PATTERN, DHCP_MAC_PATTERN) + DHCP_TYPE_PATTERN = 'DHCP-Message Option 53, length 1: ([a-zA-Z]+)' + DHCP_PATTERN = '(%s)|(%s)|(%s)|(%s)' % (DHCP_START_PATTERN, + DHCP_IP_PATTERN, + DHCP_MAC_PATTERN, + DHCP_TYPE_PATTERN) DHCP_THRESHHOLD_SEC = 80 # pylint: disable=too-many-arguments @@ -59,14 +63,24 @@ def _dhcp_line(self): self.dhcp_log.write(dhcp_line) match = re.search(self.DHCP_PATTERN, dhcp_line) if match: - if match.group(2): - self.target_ip = match.group(2) - if match.group(6): - self.target_mac = match.group(6) - if match.group(4) == "ACK": - if not self.target_ip or not self.target_mac: - LOGGER.warning('dhcp ACK incomplete: %s', dhcp_line) - self._dhcp_success() + LOGGER.debug('dhcp_line: %s', dhcp_line.strip()) + if match.group(1): + self.target_mac = None + self.target_ip = None + LOGGER.debug('Reset dhcp') + elif match.group(2): + assert not self.target_ip + self.target_ip = match.group(3) + LOGGER.debug('Found ip %s', self.target_ip) + elif match.group(4): + assert not self.target_mac + self.target_mac = match.group(5) + LOGGER.debug('Found mac %s', self.target_mac) + elif match.group(6): + LOGGER.debug('Message type %s', match.group(7)) + self._dhcp_complete(match.group(7)) + else: + LOGGER.info('Unknown dhcp match: %s', dhcp_line.strip()) def cleanup(self): """Cleanup any ongoing dhcp activity""" @@ -78,22 +92,24 @@ def cleanup(self): self.dhcp_traffic.terminate() self.dhcp_traffic = None - def _dhcp_success(self): - assert self.target_ip, 'dhcp ACK missing ip address' - assert self.target_mac, 'dhcp ACK missing mac address' + def _dhcp_complete(self, dhcp_type): + if dhcp_type not in ('ACK', 'Offer'): + return + assert self.target_ip, 'dhcp missing ip address' + assert self.target_mac, 'dhcp missing mac address' delta = int(time.time()) - self.device_dhcps.get(self.target_mac, self.scan_start) - LOGGER.debug('DHCP monitor %s received reply after %ds: %s/%s', - self.name, delta, self.target_ip, self.target_mac) + LOGGER.info('DHCP monitor %s received %s reply after %ds: %s/%s', + self.name, dhcp_type, delta, self.target_ip, self.target_mac) mode = MODE.LONG if delta > self.DHCP_THRESHHOLD_SEC else MODE.DONE target = { + 'type': dhcp_type, 'ip': self.target_ip, 'mac': self.target_mac, 'delta': delta } - self.device_dhcps[self.target_mac] = int(time.time()) + if dhcp_type == 'ACK': + self.device_dhcps[self.target_mac] = int(time.time()) self.callback(mode, target) - self.target_ip = None - self.target_mac = None def _dhcp_hangup(self): self.dhcp_traffic = None diff --git a/daq/host.py b/daq/host.py index 8232bd274f..88c770f918 100644 --- a/daq/host.py +++ b/daq/host.py @@ -69,15 +69,16 @@ class ConnectedHost: _STARTUP_MIN_TIME_SEC = 5 _RPC_TIMEOUT_SEC = 20 - _INST_DIR = "inst/" - _DEVICE_PATH = "device/%s" - _NETWORK_DIR = "inst/network" - _MODULE_CONFIG = "module_config.json" - _CONTROL_PATH = "control/port-%s" + _INST_DIR = 'inst/' + _DEVICE_PATH = 'device/%s' + _NETWORK_DIR = 'inst/network' + _MODULE_CONFIG = 'module_config.json' + _CONTROL_PATH = 'control/port-%s' _CORE_TESTS = ['pass', 'fail', 'ping', 'hold'] - _AUX_DIR = "aux/" - _CONFIG_DIR = "config/" + _AUX_DIR = 'aux/' + _CONFIG_DIR = 'config/' _TIMEOUT_EXCEPTION = TimeoutError('Timeout expired') + _PATH_PREFIX = os.path.abspath('.') + '/' + _INST_DIR # pylint: disable=too-many-statements def __init__(self, runner, device, config): @@ -360,6 +361,7 @@ def _prepare(self): self.device.dhcp_mode = DhcpMode.STATIC_IP time.sleep(self._STARTUP_MIN_TIME_SEC) self.runner.ip_notify(MODE.NOPE, { + 'type': 'STATIC', 'mac': self.target_mac, 'ip': static_ip, 'delta': -1 @@ -501,13 +503,18 @@ def _startup_scan(self): self.logger.info('Target device %s startup pcap capture', self) self._monitor_scan(self._startup_file) + def _shorten_filename(self, long_name): + if long_name and long_name.startswith(self._PATH_PREFIX): + return long_name[len(self._PATH_PREFIX):] + return long_name + def _monitor_scan(self, output_file, timeout=None): assert not self._monitor_ref, 'tcp_monitor already active' network = self.runner.network tcp_filter = '' self.logger.info('Target device %s pcap intf %s for %s seconds output in %s', self, self._mirror_intf_name, timeout if timeout else 'infinite', - output_file) + self._shorten_filename(output_file)) helper = tcpdump_helper.TcpdumpHelper(network.pri, tcp_filter, packets=None, intf_name=self._mirror_intf_name, timeout=timeout, pcap_out=output_file, diff --git a/daq/network.py b/daq/network.py index 3480ec82b3..87a5081885 100644 --- a/daq/network.py +++ b/daq/network.py @@ -217,11 +217,12 @@ def _generate_behavioral_config(self): LOGGER.info('Waiting %ds for network to settle', self._settle_sec) time.sleep(self._settle_sec) - def direct_vlan_traffic(self, port_set, vlan): + def direct_device_traffic(self, device, port_set): """Modify gateway set's vlan to match triggering vlan""" - LOGGER.info('Directing traffic for port set %s to vlan %s', port_set, vlan) + LOGGER.info('Directing traffic for %s on vlan %s to %s', + device.mac, device.vlan, port_set) # TODO: Convert this to use faucitizer to change vlan - self.topology.direct_vlan_traffic(port_set, vlan) + self.topology.direct_device_traffic(device, port_set) self._generate_behavioral_config() def _attach_switch_interface(self, switch_intf_name): @@ -252,9 +253,9 @@ def create_mirror_interface(self, port, delete=False): 'set', 'interface', mirror_intf_name, 'ofport_request=%s' % mirror_port) return mirror_intf_name - def device_group_for(self, target_mac): - """Find the target device group for the given address.""" - return self.topology.device_group_for(target_mac) + def device_group_for(self, device): + """Find the target device group for the given device.""" + return self.topology.device_group_for(device) def device_group_size(self, group_name): """Return the size of the given group.""" diff --git a/daq/runner.py b/daq/runner.py index 0212af2491..967ed21087 100644 --- a/daq/runner.py +++ b/daq/runner.py @@ -351,10 +351,10 @@ def _handle_port_learn(self, dpid, port, vid, target_mac): device = self._devices.create_if_absent(target_mac, port_info=self._ports[port]) self._target_set_trigger(device) else: - LOGGER.debug('Port %s dpid %s learned %s (ignored)', port, dpid, target_mac) + LOGGER.info('Port %s dpid %s learned %s (ignored)', port, dpid, target_mac) def _handle_device_learn(self, vid, target_mac): - LOGGER.info('%s learned on vid %s', target_mac, vid) + LOGGER.info('Learned %s on vid %s', target_mac, vid) if not self._devices.get(target_mac): device = self._devices.new_device(target_mac, vlan=vid) else: @@ -486,7 +486,7 @@ def _target_set_trigger(self, device): return False try: - group_name = self.network.device_group_for(device.mac) + group_name = self.network.device_group_for(device) device.group = group_name gateway = self._activate_device_group(device) if gateway.activated: @@ -522,11 +522,14 @@ def _target_set_trigger(self, device): } self._direct_port_traffic(device.mac, device.port.port_no, target) else: - self.network.direct_vlan_traffic(gateway.port_set, device.vlan) + self._direct_device_traffic(device, gateway.port_set) return True except Exception as e: self.target_set_error(device, e) + def _direct_device_traffic(self, device, port_set): + self.network.direct_device_traffic(device, port_set) + def _get_test_list(self, test_file): no_test = self.config.get('no_test', False) if no_test: @@ -621,19 +624,20 @@ def ip_notify(self, state, target, gateway, exception=None): self._terminate_gateway_set(gateway) return + target_type = target['type'] target_mac, target_ip, delta_sec = target['mac'], target['ip'], target['delta'] - LOGGER.info('IP notify %s is %s on %s (%s/%d)', target_mac, + LOGGER.info('IP notify %s %s is %s on %s (%s/%d)', target_type, target_mac, target_ip, gateway, state, delta_sec) - if not target_mac: - LOGGER.warning('IP target mac missing') - return + assert target_mac + assert target_ip + assert delta_sec is not None device = self._devices.get(target_mac) device.ip_info.ip_addr = target_ip device.ip_info.state = state device.ip_info.delta_sec = delta_sec - if device and device.host: + if device and device.host and target_type in ('ACK', 'STATIC'): device.host.ip_notify(target_ip, state, delta_sec) self._check_and_activate_gateway(device) @@ -808,11 +812,13 @@ def _detach_gateway(self, device): target_gateway = device.gateway if not target_gateway: return - device.gateway = None if not target_gateway.detach_target(device): LOGGER.info('Retiring %s. Last device: %s', target_gateway, device) - self.gateway_sets.add(target_gateway.port_set) target_gateway.terminate() + self.gateway_sets.add(target_gateway.port_set) + if device.vlan: + self._direct_device_traffic(device, None) + device.gateway = None def monitor_stream(self, *args, **kwargs): """Monitor a stream""" diff --git a/daq/topology.py b/daq/topology.py index 95ba7bbe41..ad451078d6 100644 --- a/daq/topology.py +++ b/daq/topology.py @@ -42,6 +42,7 @@ class FaucetTopology: PRI_TRUNK_NAME = 'trunk_pri' _NO_VLAN = "0x0000/0x1000" _EXT_STACK = 'EXT_STACK' + _OFPP_IN_PORT = 0xfffffff8 def __init__(self, config): self.config = config @@ -56,6 +57,8 @@ def __init__(self, config): self._ext_faucet = switch_setup.get('model') == self._EXT_STACK self._device_specs = self._load_device_specs() self._port_targets = {} + self._set_devices = {} + self._egress_vlan = self.config.setdefault('run_trigger', {}).get('egress_vlan') self.topology = None def initialize(self, pri): @@ -111,11 +114,22 @@ def get_device_intfs(self): device_intfs.append(intf_names[port-1] if named_port else default_name) return device_intfs - def direct_vlan_traffic(self, port_set, vlan): + def direct_device_traffic(self, device, port_set): """Modify gateway set's vlan to match triggering vlan""" + device_set = device.gateway.port_set + assert port_set == device_set or not port_set + if port_set: + self._set_devices.setdefault(device_set, set()).add(device) + else: + self._set_devices[device_set].remove(device) + set_active = bool(self._set_devices[device_set]) + vlan = device.vlan if set_active else self._DUMP_VLAN + LOGGER.info('Setting port set %s to vlan %s', device_set, vlan) + assert vlan interfaces = self.topology['dps'][self.pri_name]['interfaces'] - for port in self._get_gw_ports(port_set): + for port in self._get_gw_ports(device_set): interfaces[port]['native_vlan'] = vlan + self._generate_acls() def direct_port_traffic(self, target_mac, port_no, target): """Direct traffic from a port to specified port set""" @@ -180,6 +194,12 @@ def _make_gw_interface(self, port_set): def _port_set_vlan(self, port_set): return self._LOCAL_VLAN + port_set if port_set else self._DUMP_VLAN + def _make_in_port_interface(self): + interface = {} + interface['description'] = 'OFPP_IN_PORT' + interface['output_only'] = True + return interface + def _make_pri_trunk_interface(self): interface = {} interface['acl_in'] = self.INCOMING_ACL_FORMAT % self.pri_name @@ -222,6 +242,7 @@ def _make_sec_port_interface(self, port_no): def _make_pri_interfaces(self): interfaces = {} interfaces[self.PRI_TRUNK_PORT] = self._make_pri_trunk_interface() + interfaces[self._OFPP_IN_PORT] = self._make_in_port_interface() for port_set in range(1, self.sec_port): for port in self._get_gw_ports(port_set): interfaces[port] = self._make_gw_interface(port_set) @@ -338,6 +359,31 @@ def _generate_mirror_acls(self, port_set_mirrors, incoming_acl, portset_acls): self._add_acl_rule(portset_acls[port_set], dl_dst=self.BROADCAST_MAC, ports=bcast_mirror_ports, allow=1) + def _add_dhcp_reflectors(self, acl_list): + if not self._ext_faucet or not self._egress_vlan: + return + for devices in self._set_devices.values(): + if devices: + LOGGER.info('Reflecting dhcp to %s for %s', list(devices)[0].vlan, devices) + for device in devices: + # Rule for DHCP request to server. Convert device vlan to egress vlan. + self._add_acl_rule(acl_list, dl_type='0x800', + nw_proto=17, udp_src=68, udp_dst=67, + vlan_vid=device.vlan, + swap_vid=self._egress_vlan, port=self._OFPP_IN_PORT) + self._add_acl_rule(acl_list, dl_type='0x800', dl_dst=device.mac, + nw_proto=17, udp_src=67, udp_dst=68, + vlan_vid=self._egress_vlan, + swap_vid=device.vlan, port=self._OFPP_IN_PORT, allow=True) + + # Allow any unrecognized requests for learning, but don't reflect. + self._add_acl_rule(acl_list, dl_type='0x800', allow=True, + nw_proto=17, udp_src=68, udp_dst=67) + + # Deny any unrecognized replies. + self._add_acl_rule(acl_list, dl_type='0x800', allow=False, + nw_proto=17, udp_src=67, udp_dst=68) + def _generate_main_acls(self): incoming_acl = [] portset_acls = {} @@ -354,6 +400,7 @@ def _generate_main_acls(self): self._generate_mirror_acls(port_set_mirrors, incoming_acl, portset_acls) + self._add_dhcp_reflectors(incoming_acl) self._add_acl_rule(incoming_acl, allow=1) acls[self.INCOMING_ACL_FORMAT % self.pri_name] = incoming_acl @@ -383,7 +430,7 @@ def _write_acl_file(self, filename, pri_acls): def _maybe_apply(self, target, keyword, origin, source=None): source_keyword = source if source else keyword - if source_keyword in origin: + if source_keyword in origin and origin[source_keyword] is not None: assert not keyword in target, 'duplicate acl rule keyword %s' % keyword target[keyword] = origin[source_keyword] @@ -397,6 +444,7 @@ def _make_acl_rule(self, **kwargs): self._maybe_apply(output, 'port', kwargs) self._maybe_apply(output, 'ports', kwargs) self._maybe_apply(output, 'vlan_vid', kwargs, 'out_vlan') + self._maybe_apply(output, 'swap_vid', kwargs) self._maybe_apply(output, 'pop_vlans', in_vlan) actions = {} @@ -410,6 +458,9 @@ def _make_acl_rule(self, **kwargs): self._maybe_apply(subrule, 'dl_type', kwargs) self._maybe_apply(subrule, 'dl_src', kwargs) self._maybe_apply(subrule, 'dl_dst', kwargs) + self._maybe_apply(subrule, 'nw_proto', kwargs) + self._maybe_apply(subrule, 'udp_src', kwargs) + self._maybe_apply(subrule, 'udp_dst', kwargs) self._maybe_apply(subrule, 'vlan_vid', in_vlan) self._maybe_apply(subrule, 'vlan_vid', kwargs) self._maybe_apply(subrule, 'ipv4_dst', kwargs) @@ -478,8 +529,11 @@ def _add_acl_port_rules(self, rules, target_mac, port): def _sanitize_mac(self, mac_addr): return mac_addr.replace(':', '') - def device_group_for(self, target_mac): - """Find the target device group for the given address""" + def device_group_for(self, device): + """Return the target device group for the given device""" + if self._ext_faucet: + return 'vlan-%s' % device.vlan + target_mac = device.mac if not self._device_specs: return self._sanitize_mac(target_mac) mac_map = self._device_specs['macAddrs'] diff --git a/docker/include/network/scripts/autorestart_dnsmasq b/docker/include/network/scripts/autorestart_dnsmasq index c9e997fdf1..8be90582f8 100755 --- a/docker/include/network/scripts/autorestart_dnsmasq +++ b/docker/include/network/scripts/autorestart_dnsmasq @@ -5,6 +5,7 @@ config_file='/etc/dnsmasq.conf' PID_FILE=/var/run/dnsmasq.pid +# Wait for first client so tcpdump has a chance to attach first. echo Waiting for first DHCP device... while [ $(cat $config_file | grep "dhcp-host=\*,ignore" | wc -l) -ne 0 ]; do sleep 1 @@ -28,7 +29,7 @@ while true; do fi checksum=$new_checksum echo Starting dnsmasq at $(date) - dnsmasq --dhcp-broadcast --log-facility=/tmp/dnsmasq.log --log-dhcp & + dnsmasq --log-facility=/tmp/dnsmasq.log --log-dhcp & while [ ! -f $PID_FILE ]; do echo Waiting for $PID_FILE... sleep 2 diff --git a/docker/include/network/scripts/start_networking b/docker/include/network/scripts/start_networking index eb7afe827b..5891f219bf 100755 --- a/docker/include/network/scripts/start_networking +++ b/docker/include/network/scripts/start_networking @@ -26,7 +26,8 @@ iptables -A FORWARD -i $EXT_IF -o $LOCAL_IF -m state --state RELATED,ESTABLISHED iptables -A FORWARD -i $LOCAL_IF -o $EXT_IF -j ACCEPT # Pick a random DHCP range to force clients to pick a new address. -subnet=$((RANDOM % 99 + 1)) +random_subnet=$((RANDOM % 99 + 1)) +subnet=${IP_SUBNET:-$random_subnet} echo Configuring with subnet 10.20.$subnet.XX echo dhcp-range=10.20.$subnet.100,10.20.$subnet.254 >> /etc/dnsmasq.conf @@ -40,8 +41,13 @@ if ! ip addr show dev $LOCAL_IF | fgrep -q 'inet '; then ip addr add 10.20.$subnet.1/16 dev $LOCAL_IF fi -ip addr add 10.20.255.254/16 dev $LOCAL_IF #For static ip devices' default gateway IP -echo dhcp-host=*,ignore >> /etc/dnsmasq.conf +# For static ip devices' default gateway IP +ip addr add 10.20.255.254/16 dev $LOCAL_IF + +# Block execution until first host attaches unless being used as a faux device. +if [ "$LOCAL_IF" != faux-eth0 ]; then + echo dhcp-host=*,ignore >> /etc/dnsmasq.conf +fi # Start the NTP server service ntp start diff --git a/etc/FAUCET_VERSION b/etc/FAUCET_VERSION index 908ced3cfb..f4e580d8d2 100644 --- a/etc/FAUCET_VERSION +++ b/etc/FAUCET_VERSION @@ -1 +1 @@ -1.9.43 +1.9.51 diff --git a/subset/ping/test_ping b/subset/ping/test_ping index 9a6631dbd8..7c519e2b3f 100755 --- a/subset/ping/test_ping +++ b/subset/ping/test_ping @@ -68,12 +68,13 @@ fi # First ping might fail b/c of warm-up delays. summary="" local_status=pass -ping -n -c 10 $TARGET_IP || (local_status=fail && status=fail) +ping -n -c 10 $TARGET_IP || local_status=fail if [ $local_status == pass ]; then summary="target reached" else summary="could not reach target" + status=fail fi echo RESULT $local_status connection.base.target_ping $summary %% $TARGET_IP | tee -a $RESULT_LINES diff --git a/testing/test_base.out b/testing/test_base.out index 22b48a6e2d..c54fc2d8e7 100644 --- a/testing/test_base.out +++ b/testing/test_base.out @@ -158,9 +158,14 @@ Switch test with target 192.0.2.138:2 Monolog processing base.switch.ping... switch ping 2 %%%%%%%%%%%%%%%%%%%%%% Alt switch tests -XXX runner INFO 9a:02:57:1e:8f:01 learned on vid 1002 -Correct IP: 1 -9a02571e8f01: ['9a02571e8f01:ping:1'] +XXX runner INFO Learned 9a:02:57:1e:8f:01 on vid 1002 +Unique IPs: 1 +RESULT fail base.startup.dhcp missing dhcp packets +RESULT skip base.switch.ping No local IP has been set, check system config +RESULT pass connection.base.target_ping target reached %% 10.20.99.164 +RESULT skip base.startup.ntp No NTP traffic detected %% NTP server 10.20.99.2 +RESULT fail base.startup.dns Invalid DNS server address %% DNS server 10.20.99.2 +9a02571e8f02: ['9a02571e8f02:acquire:TimeoutError'] %%%%%%%%%%%%%%%%%%%%%% Mud profile tests result open 9a02571e8f01: [] 9a02571e8f02: [] 9a02571e8f03: [] device open 1 1 1 diff --git a/testing/test_base.sh b/testing/test_base.sh index 3d76b41e52..51d24891fd 100755 --- a/testing/test_base.sh +++ b/testing/test_base.sh @@ -56,26 +56,17 @@ echo %%%%%%%%%%%%%%%%%%%%%% Alt switch tests | tee -a $TEST_RESULTS cp config/system/alt.yaml local/system.yaml cmd/faucet -# TODO: Replace this with proper test once VLAN-triggers are added. -function configure_networking { - docker exec daq-networking-2 ifconfig eth0 down - docker exec daq-networking-2 ifconfig faux-eth0 up - docker exec daq-networking-2 ip addr add 10.20.255.254/16 dev faux-eth0 - docker exec daq-networking-2 bash -c "echo dhcp-range=10.20.99.100,10.20.99.254 >> /etc/dnsmasq.conf" -} +timeout 1200s cmd/run -s -function restart_networking { - docker exec daq-networking-2 bash -c "./autorestart_dnsmasq &" -} +fgrep 'Learned 9a:02:57:1e:8f:01 on vid 1002' inst/cmdrun.log | head -1 | redact | tee -a $TEST_RESULTS +unqie_ips=$(fgrep '10.20.99' inst/run-9a02571e8f01/scans/ip_triggers.txt | awk '{print $1}' | sort | uniq | wc -l) +echo Unique IPs: $unqie_ips | tee -a $TEST_RESULTS -monitor_log "Added link faux-2 as port 3 on alt-switch" configure_networking -monitor_log "Target device 9a02571e8f01 waiting for ip" restart_networking -timeout 1200s cmd/run -s -fgrep '9a:02:57:1e:8f:01 learned on vid 1002' inst/cmdrun.log | head -1 | redact | tee -a $TEST_RESULTS -correct_ips=$(fgrep '10.20.99' inst/run-9a02571e8f01/scans/ip_triggers.txt | wc -l) -echo Correct IP: $correct_ips | tee -a $TEST_RESULTS -cat inst/result.log | grep 9a02571e8f01 | tee -a $TEST_RESULTS -# ping test should fail since there are no dhcp packets captured +# ping test will fail since DNS is not properly handled +fgrep RESULT inst/run-9a02571e8f01/nodes/ping01/activate.log | tee -a $TEST_RESULTS + +# acquire test will fail since the DHCP server never even tries +fgrep 9a02571e8f02 inst/result.log | tee -a $TEST_RESULTS echo %%%%%%%%%%%%%%%%%%%%%% Mud profile tests | tee -a $TEST_RESULTS rm -f local/system.yaml From 10bfc865e9499c074d28e249a9dabb62b97ed2ea Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 5 Nov 2020 08:58:45 -0800 Subject: [PATCH 192/212] Update dependency firebase-admin to v9.3.0 (#692) --- firebase/functions/package-lock.json | 217 +++++++++++++-------------- firebase/functions/package.json | 2 +- 2 files changed, 104 insertions(+), 115 deletions(-) diff --git a/firebase/functions/package-lock.json b/firebase/functions/package-lock.json index e662329985..12756d3f27 100644 --- a/firebase/functions/package-lock.json +++ b/firebase/functions/package-lock.json @@ -23,9 +23,9 @@ } }, "@firebase/database": { - "version": "0.6.12", - "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.6.12.tgz", - "integrity": "sha512-OLUxp8TkXiML4X5LWM5IACsSDvo3fcf4mTbTe5RF+N6TRFv0Svzlet5OgGIa3ET1dQvNiisrMX7zzRa0OTLs7Q==", + "version": "0.6.13", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.6.13.tgz", + "integrity": "sha512-NommVkAPzU7CKd1gyehmi3lz0K78q0KOfiex7Nfy7MBMwknLm7oNqKovXSgQV1PCLvKXvvAplDSFhDhzIf9obA==", "requires": { "@firebase/auth-interop-types": "0.1.5", "@firebase/component": "0.1.19", @@ -58,9 +58,9 @@ } }, "@google-cloud/common": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-3.4.0.tgz", - "integrity": "sha512-bVMQlK4aZEeopo2oJwDUJiBhPVjRRQHfFCCv9JowmKS3L//PBHNDJzC/LxJixGZEU3fh3YXkUwm67JZ5TBCCNQ==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-3.4.1.tgz", + "integrity": "sha512-e5z0CwsM0RXky+PnyPtQ3QK46ksqm+kE7kX8pm8X+ddBwZJipHchKeazMM5fLlGCS+AALalzXb+uYmH72TRnpQ==", "optional": true, "requires": { "@google-cloud/projectify": "^2.0.0", @@ -69,15 +69,15 @@ "duplexify": "^4.1.1", "ent": "^2.2.0", "extend": "^3.0.2", - "google-auth-library": "^6.0.0", + "google-auth-library": "^6.1.1", "retry-request": "^4.1.1", "teeny-request": "^7.0.0" }, "dependencies": { "bignumber.js": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", - "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", + "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==", "optional": true }, "duplexify": { @@ -116,9 +116,9 @@ } }, "google-auth-library": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.0.6.tgz", - "integrity": "sha512-fWYdRdg55HSJoRq9k568jJA1lrhg9i2xgfhVIMJbskUmbDpJGHsbv9l41DGhCDXM21F9Kn4kUwdysgxSYBYJUw==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.1.2.tgz", + "integrity": "sha512-X9EUX8R+kIpsf55KdSPhFWF0RNyBGuBc1zeYc/5Sjuk65eIYqq91rINJVBD22pp+w/PuM2fasHiA6H2xYjxTIQ==", "optional": true, "requires": { "arrify": "^2.0.0", @@ -126,8 +126,8 @@ "ecdsa-sig-formatter": "^1.0.11", "fast-text-encoding": "^1.0.0", "gaxios": "^3.0.0", - "gcp-metadata": "^4.1.0", - "gtoken": "^5.0.0", + "gcp-metadata": "^4.2.0", + "gtoken": "^5.0.4", "jws": "^4.0.0", "lru-cache": "^6.0.0" } @@ -142,13 +142,13 @@ } }, "gtoken": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.3.tgz", - "integrity": "sha512-Nyd1wZCMRc2dj/mAD0LlfQLcAO06uKdpKJXvK85SGrF5+5+Bpfil9u/2aw35ltvEHjvl0h5FMKN5knEU+9JrOg==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.4.tgz", + "integrity": "sha512-U9wnSp4GZ7ov6zRdPuRHG4TuqEWqRRgT1gfXGNArhzBUn9byrPeH8uTmBWU/ZiWJJvTEmkjhDIC3mqHWdVi3xQ==", "optional": true, "requires": { "gaxios": "^3.0.0", - "google-p12-pem": "^3.0.0", + "google-p12-pem": "^3.0.3", "jws": "^4.0.0", "mime": "^2.2.0" } @@ -171,12 +171,6 @@ "yallist": "^4.0.0" } }, - "node-forge": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", - "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", - "optional": true - }, "readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -197,9 +191,9 @@ } }, "@google-cloud/firestore": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-4.2.0.tgz", - "integrity": "sha512-YCiKaTYCbXSoEvZ8cTmpgg4ebAvmFUOu3hj/aX+lHiOK7LsoFVi4jgNknogSqIiv04bxAysTBodpgn8XoZ4l5g==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@google-cloud/firestore/-/firestore-4.4.0.tgz", + "integrity": "sha512-nixsumd4C7eL+hHEgyihspzhBBNe3agsvNFRX0xfqO3uR/6ro4CUj9XdcCvdnSSd3yTyqKfdBSRK2fEj1jIbYg==", "optional": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -208,9 +202,9 @@ }, "dependencies": { "@grpc/grpc-js": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.1.6.tgz", - "integrity": "sha512-bUeaMN/dHTkt9AqU0Tc1xdHMB3jVLyPNfg8gZ5cMyhFyMeCwoJbFcJrNBgYqRCbvYhvtaEgzQwkw91NnY4Oktg==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.1.7.tgz", + "integrity": "sha512-EuxMstI0u778dp0nk6Fe3gHXYPeV6FYsWOe0/QFwxv1NQ6bc5Wl/0Yxa4xl9uBlKElL6AIxuASmSfu7KEJhqiw==", "optional": true, "requires": { "@grpc/proto-loader": "^0.6.0-pre14", @@ -235,17 +229,29 @@ } }, "@types/node": { - "version": "12.12.58", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.58.tgz", - "integrity": "sha512-Be46CNIHWAagEfINOjmriSxuv7IVcqbGe+sDSg2SYCEz/0CRBy7LRASGfRbD8KZkqoePU73Wsx3UvOSFcq/9hA==", + "version": "12.19.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.1.tgz", + "integrity": "sha512-/xaVmBBjOGh55WCqumLAHXU9VhjGtmyTGqJzFBXRWZzByOXI5JAJNx9xPVGEsNizrNwcec92fQMj458MWfjN1A==", "optional": true }, "bignumber.js": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", - "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", + "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==", "optional": true }, + "duplexify": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.1.tgz", + "integrity": "sha512-DY3xVEmVHTv1wSzKNbwoU6nVjzI369Y6sPoqfYr0/xlx3IdX2n94xIszTcjPO8W8ZIv0Wb0PXNcjuZyT4wiICA==", + "optional": true, + "requires": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.0" + } + }, "gaxios": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.2.0.tgz", @@ -270,9 +276,9 @@ } }, "google-auth-library": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.0.6.tgz", - "integrity": "sha512-fWYdRdg55HSJoRq9k568jJA1lrhg9i2xgfhVIMJbskUmbDpJGHsbv9l41DGhCDXM21F9Kn4kUwdysgxSYBYJUw==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.1.2.tgz", + "integrity": "sha512-X9EUX8R+kIpsf55KdSPhFWF0RNyBGuBc1zeYc/5Sjuk65eIYqq91rINJVBD22pp+w/PuM2fasHiA6H2xYjxTIQ==", "optional": true, "requires": { "arrify": "^2.0.0", @@ -280,32 +286,28 @@ "ecdsa-sig-formatter": "^1.0.11", "fast-text-encoding": "^1.0.0", "gaxios": "^3.0.0", - "gcp-metadata": "^4.1.0", - "gtoken": "^5.0.0", + "gcp-metadata": "^4.2.0", + "gtoken": "^5.0.4", "jws": "^4.0.0", "lru-cache": "^6.0.0" } }, "google-gax": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-2.8.0.tgz", - "integrity": "sha512-MPaADY/FHittX5xfOUU2EVqIoE850e+OZ1ys8aO2GnUMaP4U0Bde2wop6kw5sp4fIOjKNlan4GATKAURsYbxSw==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-2.9.0.tgz", + "integrity": "sha512-MFMwA7Fb8PEwjnYwfGXjZMidCNyMl3gSnvS/+kS8TQioJZQDpzK+W3dmwyNyig/U13+kbABqDnbkkAXJ5NiUkw==", "optional": true, "requires": { "@grpc/grpc-js": "~1.1.1", "@grpc/proto-loader": "^0.5.1", "@types/long": "^4.0.0", "abort-controller": "^3.0.0", - "duplexify": "^3.6.0", + "duplexify": "^4.0.0", "google-auth-library": "^6.0.0", "is-stream-ended": "^0.1.4", - "lodash.at": "^4.6.0", - "lodash.has": "^4.5.2", - "node-fetch": "^2.6.0", + "node-fetch": "^2.6.1", "protobufjs": "^6.9.0", - "retry-request": "^4.0.0", - "semver": "^6.0.0", - "walkdir": "^0.4.0" + "retry-request": "^4.0.0" } }, "google-p12-pem": { @@ -318,13 +320,13 @@ } }, "gtoken": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.3.tgz", - "integrity": "sha512-Nyd1wZCMRc2dj/mAD0LlfQLcAO06uKdpKJXvK85SGrF5+5+Bpfil9u/2aw35ltvEHjvl0h5FMKN5knEU+9JrOg==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.4.tgz", + "integrity": "sha512-U9wnSp4GZ7ov6zRdPuRHG4TuqEWqRRgT1gfXGNArhzBUn9byrPeH8uTmBWU/ZiWJJvTEmkjhDIC3mqHWdVi3xQ==", "optional": true, "requires": { "gaxios": "^3.0.0", - "google-p12-pem": "^3.0.0", + "google-p12-pem": "^3.0.3", "jws": "^4.0.0", "mime": "^2.2.0" } @@ -347,12 +349,6 @@ "yallist": "^4.0.0" } }, - "node-forge": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", - "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", - "optional": true - }, "protobufjs": { "version": "6.10.1", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.10.1.tgz", @@ -375,13 +371,24 @@ }, "dependencies": { "@types/node": { - "version": "13.13.19", - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.19.tgz", - "integrity": "sha512-IVsULCpTdafcHhBDLYEPnV5l15xV0q065zvOHC1ZmzFYaBCMzku078eXnazoSG8907vZjRgEN/EQjku7GwwFyQ==", + "version": "13.13.28", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.28.tgz", + "integrity": "sha512-EM/qFeRH8ZCD+TlsaIPULyyFm9vOhFIvgskY2JmHbEsWsOPgN+rtjSXrcHGgJpob4Nu17VfO95FKewr0XY7iOQ==", "optional": true } } }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "optional": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -773,12 +780,6 @@ "@types/node": "*" } }, - "@types/color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", - "optional": true - }, "@types/connect": { "version": "3.4.33", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz", @@ -889,12 +890,11 @@ "optional": true }, "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "optional": true, "requires": { - "@types/color-name": "^1.1.1", "color-convert": "^2.0.1" } }, @@ -1328,9 +1328,9 @@ } }, "firebase-admin": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-9.2.0.tgz", - "integrity": "sha512-LhnMYl71B4gP1FlTLfwaYlOWhBCAcNF+byb2CPTfaW/T4hkp4qlXOgo2bws/zbAv5X9GTFqGir3KexMslVGsIA==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-9.3.0.tgz", + "integrity": "sha512-qMUITOp2QKLLc2o0/wSiDC2OO2knejjieZN/8Or9AzfFk8ftTcUKq5ALNlQXu+7aUzGe0IwSJq9TVnkIU0h1xw==", "requires": { "@firebase/database": "^0.6.10", "@firebase/database-types": "^0.5.2", @@ -1343,14 +1343,9 @@ }, "dependencies": { "@types/node": { - "version": "10.17.33", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.33.tgz", - "integrity": "sha512-Z761mij1nxISY1GhZv2Ie/6ofe0JQTcMtcyFCJ9ItZzRvCwLyktyoPKzpugFqW2T7lCwUCSqpQbDo8Eol9r2EA==" - }, - "node-forge": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", - "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" + "version": "10.17.42", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.42.tgz", + "integrity": "sha512-HElxYF7C/MSkuvlaHB2c+82zhXiuO49Cq056Dol8AQuTph7oJtduo2n6J8rFa+YhJyNgQ/Lm20ZaxqD0vxU0+Q==" } } }, @@ -1418,9 +1413,9 @@ }, "dependencies": { "bignumber.js": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", - "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", + "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==", "optional": true }, "gaxios": { @@ -1447,9 +1442,9 @@ } }, "google-auth-library": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.0.6.tgz", - "integrity": "sha512-fWYdRdg55HSJoRq9k568jJA1lrhg9i2xgfhVIMJbskUmbDpJGHsbv9l41DGhCDXM21F9Kn4kUwdysgxSYBYJUw==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.1.2.tgz", + "integrity": "sha512-X9EUX8R+kIpsf55KdSPhFWF0RNyBGuBc1zeYc/5Sjuk65eIYqq91rINJVBD22pp+w/PuM2fasHiA6H2xYjxTIQ==", "optional": true, "requires": { "arrify": "^2.0.0", @@ -1457,8 +1452,8 @@ "ecdsa-sig-formatter": "^1.0.11", "fast-text-encoding": "^1.0.0", "gaxios": "^3.0.0", - "gcp-metadata": "^4.1.0", - "gtoken": "^5.0.0", + "gcp-metadata": "^4.2.0", + "gtoken": "^5.0.4", "jws": "^4.0.0", "lru-cache": "^6.0.0" } @@ -1473,13 +1468,13 @@ } }, "gtoken": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.3.tgz", - "integrity": "sha512-Nyd1wZCMRc2dj/mAD0LlfQLcAO06uKdpKJXvK85SGrF5+5+Bpfil9u/2aw35ltvEHjvl0h5FMKN5knEU+9JrOg==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.4.tgz", + "integrity": "sha512-U9wnSp4GZ7ov6zRdPuRHG4TuqEWqRRgT1gfXGNArhzBUn9byrPeH8uTmBWU/ZiWJJvTEmkjhDIC3mqHWdVi3xQ==", "optional": true, "requires": { "gaxios": "^3.0.0", - "google-p12-pem": "^3.0.0", + "google-p12-pem": "^3.0.3", "jws": "^4.0.0", "mime": "^2.2.0" } @@ -1502,12 +1497,6 @@ "yallist": "^4.0.0" } }, - "node-forge": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", - "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", - "optional": true - }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -2306,14 +2295,14 @@ "optional": true }, "teeny-request": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-7.0.0.tgz", - "integrity": "sha512-kWD3sdGmIix6w7c8ZdVKxWq+3YwVPGWz+Mq0wRZXayEKY/YHb63b8uphfBzcFDmyq8frD9+UTc3wLyOhltRbtg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-7.0.1.tgz", + "integrity": "sha512-sasJmQ37klOlplL4Ia/786M5YlOcoLGQyq2TE4WHSRupbAuDaQW0PfVxV4MtdBtRJ4ngzS+1qim8zP6Zp35qCw==", "optional": true, "requires": { "http-proxy-agent": "^4.0.0", "https-proxy-agent": "^5.0.0", - "node-fetch": "^2.2.0", + "node-fetch": "^2.6.1", "stream-events": "^1.0.5", "uuid": "^8.0.0" } @@ -2332,9 +2321,9 @@ "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, "tslib": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", - "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==" + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "type-is": { "version": "1.6.18", @@ -2385,9 +2374,9 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.0.tgz", - "integrity": "sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ==", + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", + "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==", "optional": true }, "vary": { diff --git a/firebase/functions/package.json b/firebase/functions/package.json index 9cc0a5d7e6..535c1c5ca8 100644 --- a/firebase/functions/package.json +++ b/firebase/functions/package.json @@ -14,7 +14,7 @@ "dependencies": { "@google-cloud/pubsub": "2.5.0", "@google-cloud/iot": "1.8.0", - "firebase-admin": "9.2.0", + "firebase-admin": "9.3.0", "firebase-functions": "3.11.0", "node-forge": "0.10.0", "extend": "3.0.2" From 858e9f77f91bc424ca89cf5a3f837fdec6d524f0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 6 Nov 2020 14:41:20 -0800 Subject: [PATCH 193/212] Update dependency io.grpc:grpc-netty-shaded to v1.33.1 (#703) --- subset/switches/pom.xml | 2 +- usi/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subset/switches/pom.xml b/subset/switches/pom.xml index 7385c45bb6..7d483efb87 100644 --- a/subset/switches/pom.xml +++ b/subset/switches/pom.xml @@ -38,7 +38,7 @@ io.grpc grpc-netty-shaded - 1.33.0 + 1.33.1 io.grpc diff --git a/usi/pom.xml b/usi/pom.xml index 29de9f5df7..a727b222da 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -38,7 +38,7 @@ io.grpc grpc-netty-shaded - 1.33.0 + 1.33.1 io.grpc From 1e4f832b7ba4da7bc7d4ad8b5ad41d68b72c8b47 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 6 Nov 2020 14:42:38 -0800 Subject: [PATCH 194/212] Update dependency @google-cloud/pubsub to v2.6.0 (#690) --- firebase/functions/package-lock.json | 191 ++++++++++++++++----------- firebase/functions/package.json | 2 +- 2 files changed, 118 insertions(+), 75 deletions(-) diff --git a/firebase/functions/package-lock.json b/firebase/functions/package-lock.json index 12756d3f27..2da2359117 100644 --- a/firebase/functions/package-lock.json +++ b/firebase/functions/package-lock.json @@ -430,21 +430,21 @@ "integrity": "sha512-EvuabjzzZ9E2+OaYf+7P9OAiiwbTxKYL0oGLnREQd+Su2NTQBpomkdlkBowFvyWsaV0d1sSGxrKpSNcrhPqbxg==" }, "@google-cloud/pubsub": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@google-cloud/pubsub/-/pubsub-2.5.0.tgz", - "integrity": "sha512-7bbbQqa+LSTopVjt20EZ8maO6rEpbO7v8EvDImHMsbRS30HJ5+kClbaQTRvhNzhc1qy221A1GbHPHMCQ/U5E3Q==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@google-cloud/pubsub/-/pubsub-2.6.0.tgz", + "integrity": "sha512-NfF35l8Hi9k2BqrjweR4HWmfL4U3jL3HrX+rp46vEqjFgD+l7JXw4k4KpEzDYvFhHu3SxjH5e18+yW1b4/6hsA==", "requires": { "@google-cloud/paginator": "^3.0.0", "@google-cloud/precise-date": "^2.0.0", "@google-cloud/projectify": "^2.0.0", "@google-cloud/promisify": "^2.0.0", - "@opentelemetry/api": "^0.10.0", - "@opentelemetry/tracing": "^0.10.0", + "@opentelemetry/api": "^0.11.0", + "@opentelemetry/tracing": "^0.11.0", "@types/duplexify": "^3.6.0", "@types/long": "^4.0.0", "arrify": "^2.0.0", "extend": "^3.0.2", - "google-auth-library": "^6.0.0", + "google-auth-library": "^6.1.2", "google-gax": "^2.7.0", "is-stream-ended": "^0.1.4", "lodash.snakecase": "^4.1.1", @@ -452,22 +452,55 @@ }, "dependencies": { "@grpc/grpc-js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.1.3.tgz", - "integrity": "sha512-HtOsk2YUofBcm1GkPqGzb6pwHhv+74eC2CUO229USIDKRtg30ycbZmqC+HdNtY3nHqoc9IgcRlntFgopyQoYCA==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.1.7.tgz", + "integrity": "sha512-EuxMstI0u778dp0nk6Fe3gHXYPeV6FYsWOe0/QFwxv1NQ6bc5Wl/0Yxa4xl9uBlKElL6AIxuASmSfu7KEJhqiw==", "requires": { + "@grpc/proto-loader": "^0.6.0-pre14", + "@types/node": "^12.12.47", + "google-auth-library": "^6.0.0", "semver": "^6.2.0" + }, + "dependencies": { + "@grpc/proto-loader": { + "version": "0.6.0-pre9", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.6.0-pre9.tgz", + "integrity": "sha512-oM+LjpEjNzW5pNJjt4/hq1HYayNeQT+eGrOPABJnYHv7TyNPDNzkQ76rDYZF86X5swJOa4EujEMzQ9iiTdPgww==", + "requires": { + "@types/long": "^4.0.1", + "lodash.camelcase": "^4.3.0", + "long": "^4.0.0", + "protobufjs": "^6.9.0", + "yargs": "^15.3.1" + } + } } }, + "@types/node": { + "version": "12.12.70", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.70.tgz", + "integrity": "sha512-i5y7HTbvhonZQE+GnUM2rz1Bi8QkzxdQmEv1LKOv4nWyaQk/gdeiTApuQR3PDJHX7WomAbpx2wlWSEpxXGZ/UQ==" + }, "bignumber.js": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", - "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", + "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==" + }, + "duplexify": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.1.tgz", + "integrity": "sha512-DY3xVEmVHTv1wSzKNbwoU6nVjzI369Y6sPoqfYr0/xlx3IdX2n94xIszTcjPO8W8ZIv0Wb0PXNcjuZyT4wiICA==", + "requires": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.0" + } }, "gaxios": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.1.0.tgz", - "integrity": "sha512-DDTn3KXVJJigtz+g0J3vhcfbDbKtAroSTxauWsdnP57sM5KZ3d2c/3D9RKFJ86s43hfw6WULg6TXYw/AYiBlpA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.2.0.tgz", + "integrity": "sha512-+6WPeVzPvOshftpxJwRi2Ozez80tn/hdtOUag7+gajDHRJvAblKxTFSSMPtr2hmnLy7p0mvYz0rMXLBl8pSO7Q==", "requires": { "abort-controller": "^3.0.0", "extend": "^3.0.2", @@ -477,73 +510,62 @@ } }, "gcp-metadata": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.1.4.tgz", - "integrity": "sha512-5J/GIH0yWt/56R3dNaNWPGQ/zXsZOddYECfJaqxFWgrZ9HC2Kvc5vl9upOgUUHKzURjAVf2N+f6tEJiojqXUuA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.2.0.tgz", + "integrity": "sha512-vQZD57cQkqIA6YPGXM/zc+PIZfNRFdukWGsGZ5+LcJzesi5xp6Gn7a02wRJi4eXPyArNMIYpPET4QMxGqtlk6Q==", "requires": { "gaxios": "^3.0.0", "json-bigint": "^1.0.0" } }, "google-auth-library": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.0.6.tgz", - "integrity": "sha512-fWYdRdg55HSJoRq9k568jJA1lrhg9i2xgfhVIMJbskUmbDpJGHsbv9l41DGhCDXM21F9Kn4kUwdysgxSYBYJUw==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.1.2.tgz", + "integrity": "sha512-X9EUX8R+kIpsf55KdSPhFWF0RNyBGuBc1zeYc/5Sjuk65eIYqq91rINJVBD22pp+w/PuM2fasHiA6H2xYjxTIQ==", "requires": { "arrify": "^2.0.0", "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "fast-text-encoding": "^1.0.0", "gaxios": "^3.0.0", - "gcp-metadata": "^4.1.0", - "gtoken": "^5.0.0", + "gcp-metadata": "^4.2.0", + "gtoken": "^5.0.4", "jws": "^4.0.0", "lru-cache": "^6.0.0" } }, "google-gax": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-2.7.0.tgz", - "integrity": "sha512-0dBATy8mMVlfOBrT85Q+NzBpZ4OJZUMrPI9wJULpiIDq2w1zlN30Duor+fQUcMEjanYEc72G58M4iUVve0jfXw==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-2.9.0.tgz", + "integrity": "sha512-MFMwA7Fb8PEwjnYwfGXjZMidCNyMl3gSnvS/+kS8TQioJZQDpzK+W3dmwyNyig/U13+kbABqDnbkkAXJ5NiUkw==", "requires": { "@grpc/grpc-js": "~1.1.1", "@grpc/proto-loader": "^0.5.1", "@types/long": "^4.0.0", "abort-controller": "^3.0.0", - "duplexify": "^3.6.0", + "duplexify": "^4.0.0", "google-auth-library": "^6.0.0", "is-stream-ended": "^0.1.4", - "lodash.at": "^4.6.0", - "lodash.has": "^4.5.2", - "node-fetch": "^2.6.0", + "node-fetch": "^2.6.1", "protobufjs": "^6.9.0", - "retry-request": "^4.0.0", - "semver": "^6.0.0", - "walkdir": "^0.4.0" + "retry-request": "^4.0.0" } }, "google-p12-pem": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.2.tgz", - "integrity": "sha512-tbjzndQvSIHGBLzHnhDs3cL4RBjLbLXc2pYvGH+imGVu5b4RMAttUTdnmW2UH0t11QeBTXZ7wlXPS7hrypO/tg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.3.tgz", + "integrity": "sha512-wS0ek4ZtFx/ACKYF3JhyGe5kzH7pgiQ7J5otlumqR9psmWMYc+U9cErKlCYVYHoUaidXHdZ2xbo34kB+S+24hA==", "requires": { - "node-forge": "^0.9.0" - }, - "dependencies": { - "node-forge": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.2.tgz", - "integrity": "sha512-naKSScof4Wn+aoHU6HBsifh92Zeicm1GDQKd1vp3Y/kOi8ub0DozCa9KpvYNCXslFHYRmLNiqRopGdTGwNLpNw==" - } + "node-forge": "^0.10.0" } }, "gtoken": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.3.tgz", - "integrity": "sha512-Nyd1wZCMRc2dj/mAD0LlfQLcAO06uKdpKJXvK85SGrF5+5+Bpfil9u/2aw35ltvEHjvl0h5FMKN5knEU+9JrOg==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.4.tgz", + "integrity": "sha512-U9wnSp4GZ7ov6zRdPuRHG4TuqEWqRRgT1gfXGNArhzBUn9byrPeH8uTmBWU/ZiWJJvTEmkjhDIC3mqHWdVi3xQ==", "requires": { "gaxios": "^3.0.0", - "google-p12-pem": "^3.0.0", + "google-p12-pem": "^3.0.3", "jws": "^4.0.0", "mime": "^2.2.0" } @@ -582,6 +604,23 @@ "@types/long": "^4.0.1", "@types/node": "^13.7.0", "long": "^4.0.0" + }, + "dependencies": { + "@types/node": { + "version": "13.13.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.27.tgz", + "integrity": "sha512-IeZlpkPnUqO45iBxJocIQzwV+K6phdSVaCxRwlvHHQ0YL+Gb1fvuv9GmIMYllZcjyzqoRKDNJeNo6p8dNWSPSQ==" + } + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" } }, "yallist": { @@ -661,25 +700,25 @@ } }, "@opentelemetry/api": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-0.10.2.tgz", - "integrity": "sha512-GtpMGd6vkzDMYcpu2t9LlhEgMy/SzBwRnz48EejlRArYqZzqSzAsKmegUK7zHgl+EOIaK9mKHhnRaQu3qw20cA==", + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-0.11.0.tgz", + "integrity": "sha512-K+1ADLMxduhsXoZ0GRfi9Pw162FvzBQLDQlHru1lg86rpIU+4XqdJkSGo6y3Kg+GmOWq1HNHOA/ydw/rzHQkRg==", "requires": { - "@opentelemetry/context-base": "^0.10.2" + "@opentelemetry/context-base": "^0.11.0" } }, "@opentelemetry/context-base": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@opentelemetry/context-base/-/context-base-0.10.2.tgz", - "integrity": "sha512-hZNKjKOYsckoOEgBziGMnBcX0M7EtstnCmwz5jZUOUYwlZ+/xxX6z3jPu1XVO2Jivk0eLfuP9GP+vFD49CMetw==" + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-base/-/context-base-0.11.0.tgz", + "integrity": "sha512-ESRk+572bftles7CVlugAj5Azrz61VO0MO0TS2pE9MLVL/zGmWuUBQryART6/nsrFqo+v9HPt37GPNcECTZR1w==" }, "@opentelemetry/core": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-0.10.2.tgz", - "integrity": "sha512-DhkiTp5eje2zTGd+HAIKWpGE6IR6lq7tUpYt4nnkhOi6Hq9WQAANVDCWEZEbYOw57LkdXbE50FZ/kMvHDm450Q==", + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-0.11.0.tgz", + "integrity": "sha512-ZEKjBXeDGBqzouz0uJmrbEKNExEsQOhsZ3tJDCLcz5dUNoVw642oIn2LYWdQK2YdIfZbEmltiF65/csGsaBtFA==", "requires": { - "@opentelemetry/api": "^0.10.2", - "@opentelemetry/context-base": "^0.10.2", + "@opentelemetry/api": "^0.11.0", + "@opentelemetry/context-base": "^0.11.0", "semver": "^7.1.3" }, "dependencies": { @@ -691,24 +730,29 @@ } }, "@opentelemetry/resources": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-0.10.2.tgz", - "integrity": "sha512-5JGC2TPSAIHth615IURt+sSsTljY43zTfJD0JE9PHC6ipZPiQ0dpQDZOrLn8NAMfOHY1jeWwpIuLASjqbXUfuw==", + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-0.11.0.tgz", + "integrity": "sha512-o7DwV1TcezqBtS5YW2AWBcn01nVpPptIbTr966PLlVBcS//w8LkjeOShiSZxQ0lmV4b2en0FiSouSDoXk/5qIQ==", "requires": { - "@opentelemetry/api": "^0.10.2", - "@opentelemetry/core": "^0.10.2", - "gcp-metadata": "^3.5.0" + "@opentelemetry/api": "^0.11.0", + "@opentelemetry/core": "^0.11.0" } }, + "@opentelemetry/semantic-conventions": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-0.11.0.tgz", + "integrity": "sha512-xsthnI/J+Cx0YVDGgUzvrH0ZTtfNtl866M454NarYwDrc0JvC24sYw+XS5PJyk2KDzAHtb0vlrumUc1OAut/Fw==" + }, "@opentelemetry/tracing": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@opentelemetry/tracing/-/tracing-0.10.2.tgz", - "integrity": "sha512-mNAhARn4dEdOjTa9OdysjI4fRHMbvr4YSbPuH7jhkyPzgoa+DnvnbY3GGpEay6kpuYJsrW8Ef9OIKAV/GndhbQ==", + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/tracing/-/tracing-0.11.0.tgz", + "integrity": "sha512-QweFmxzl32BcyzwdWCNjVXZT1WeENNS/RWETq/ohqu+fAsTcMyGcr6cOq/yDdFmtBy+bm5WVVdeByEjNS+c4/w==", "requires": { - "@opentelemetry/api": "^0.10.2", - "@opentelemetry/context-base": "^0.10.2", - "@opentelemetry/core": "^0.10.2", - "@opentelemetry/resources": "^0.10.2" + "@opentelemetry/api": "^0.11.0", + "@opentelemetry/context-base": "^0.11.0", + "@opentelemetry/core": "^0.11.0", + "@opentelemetry/resources": "^0.11.0", + "@opentelemetry/semantic-conventions": "^0.11.0" } }, "@protobufjs/aspromise": { @@ -2459,7 +2503,6 @@ "version": "15.4.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "optional": true, "requires": { "cliui": "^6.0.0", "decamelize": "^1.2.0", diff --git a/firebase/functions/package.json b/firebase/functions/package.json index 535c1c5ca8..1efb9d77ae 100644 --- a/firebase/functions/package.json +++ b/firebase/functions/package.json @@ -12,7 +12,7 @@ "node": "10" }, "dependencies": { - "@google-cloud/pubsub": "2.5.0", + "@google-cloud/pubsub": "2.6.0", "@google-cloud/iot": "1.8.0", "firebase-admin": "9.3.0", "firebase-functions": "3.11.0", From f2e7c0c14e3d1d080873b16bd4efba47ef5cbd82 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 6 Nov 2020 14:43:11 -0800 Subject: [PATCH 195/212] Update dependency commons-net:commons-net to v3.7.2 (#683) --- subset/switches/pom.xml | 2 +- usi/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subset/switches/pom.xml b/subset/switches/pom.xml index 7d483efb87..1ef432bb45 100644 --- a/subset/switches/pom.xml +++ b/subset/switches/pom.xml @@ -33,7 +33,7 @@ commons-net commons-net - 3.7.1 + 3.7.2 io.grpc diff --git a/usi/pom.xml b/usi/pom.xml index a727b222da..6c614fa83d 100644 --- a/usi/pom.xml +++ b/usi/pom.xml @@ -33,7 +33,7 @@ commons-net commons-net - 3.7.1 + 3.7.2 io.grpc From 35d9314a45a698f706d9adce81dc483d2e5e3e80 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 9 Nov 2020 13:02:30 -0800 Subject: [PATCH 196/212] Update dependency jsoneditor to v9.1.2 (#707) --- firebase/public/config.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firebase/public/config.html b/firebase/public/config.html index 097ede4b42..29dd7f4932 100644 --- a/firebase/public/config.html +++ b/firebase/public/config.html @@ -11,8 +11,8 @@ - - + +
      From 2756daaca1b2f224cbff82a028ead3190d1c8475 Mon Sep 17 00:00:00 2001 From: henry54809 Date: Tue, 17 Nov 2020 20:06:01 -0500 Subject: [PATCH 197/212] Adding a IP that falls in device ip's subnet to test hosts (#710) (#713) --- cmd/exrun | 4 ++++ daq/runner.py | 4 ++-- daq/test_modules/native_host.py | 7 +++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/cmd/exrun b/cmd/exrun index 30ef0e02e2..101eefbf26 100755 --- a/cmd/exrun +++ b/cmd/exrun @@ -86,6 +86,10 @@ $ovsctl status || sudo $ovsctl start sudo rm -f $cleanup_file +if [ -z `which tcpdump` ]; then + export PATH=/usr/sbin:$PATH +fi + # Hacky workaround for apparmor protection of tcpdump. Without this, the process can not be killed. cp `which tcpdump` binhack/ diff --git a/daq/runner.py b/daq/runner.py index 967ed21087..5735dd5ceb 100644 --- a/daq/runner.py +++ b/daq/runner.py @@ -316,9 +316,9 @@ def _handle_port_state(self, dpid, port, active): LOGGER.info('Port %s dpid %s is now %s', port, dpid, "active" if active else "inactive") if active: self._activate_port(port) - else: - device = self._devices.get_by_port_info(self._ports[port]) + elif port in self._ports: port_info = self._ports[port] + device = self._devices.get_by_port_info(port_info) if device and device.host and not port_info.flapping_start: port_info.flapping_start = time.time() if port_info.active: diff --git a/daq/test_modules/native_host.py b/daq/test_modules/native_host.py index fe15ec1609..7bbef61729 100644 --- a/daq/test_modules/native_host.py +++ b/daq/test_modules/native_host.py @@ -42,6 +42,13 @@ def activate(self, log_name='activate.log'): assert not self.active_pipe, '%s already activated' % self.name env = dict(self.env_vars) + # for devcies with ips that are not in the same subnet as test hosts' ips. + # TODO: ip added assumes a /16 subnet + if self.intf() and "TARGET_IP" in env and not env["TARGET_IP"].startswith('10.20'): + parts = env["TARGET_IP"].split('.') + parts[-1] = str((int(parts[-1]) + 1) % 256) + self.cmd('ip addr add %s/16 dev %s' % (".".join(parts), self.intf())) + self.cmd('mkdir %s' % os.path.join(self.basedir, "config")) for vol_map in self.vol_maps: From 0a9fd52ab714c684cd3b28385b4feae078c4cf12 Mon Sep 17 00:00:00 2001 From: henry54809 Date: Thu, 19 Nov 2020 16:38:03 -0500 Subject: [PATCH 198/212] Add external DHCP subnet config (#714) --- config/system/alt.yaml | 7 + config/system/default.yaml | 4 + daq/network.py | 13 +- daq/test_modules/external_module.py | 17 ++ daq/test_modules/native_host.py | 6 - firebase/public/protos.hash | 2 +- firebase/public/protos.html | 42 +++ libs/proto/system_config_pb2.py | 387 +++++++++++++++------------- proto/system_config.proto | 13 + 9 files changed, 310 insertions(+), 181 deletions(-) diff --git a/config/system/alt.yaml b/config/system/alt.yaml index 1ed1450d5b..df3aa454c8 100644 --- a/config/system/alt.yaml +++ b/config/system/alt.yaml @@ -30,3 +30,10 @@ run_trigger: vlan_start: 1001 vlan_end: 1009 egress_vlan: 121 + +internal_subnet: + subnet: 192.168.1.0/24 + +# Define external DHCP subnets to be used by test hosts +external_subnets: + - subnet: 10.20.0.0/16 diff --git a/config/system/default.yaml b/config/system/default.yaml index f750b5a71f..4f4be85953 100644 --- a/config/system/default.yaml +++ b/config/system/default.yaml @@ -45,3 +45,7 @@ topology_hook: bin/dump_network usi_setup: url: localhost:5000 rpc_timeout_sec: 20 + +# internal test host subnet +internal_subnet: + subnet: 10.20.0.0/16 diff --git a/daq/network.py b/daq/network.py index 87a5081885..6d6c715cb3 100644 --- a/daq/network.py +++ b/daq/network.py @@ -1,5 +1,9 @@ """Networking module""" +from __future__ import absolute_import + +from ipaddress import ip_network +import copy import os from shutil import copyfile import time @@ -40,6 +44,7 @@ class TestNetwork: OVS_CLS = mininet_node.OVSSwitch MAX_INTERNAL_DPID = 100 DEFAULT_OF_PORT = 6653 + DEFAULT_MININET_SUBNET = "10.20.0.0/16" _CTRL_PRI_IFACE = 'ctrl-pri' INTERMEDIATE_FAUCET_FILE = "inst/faucet_intermediate.yaml" OUTPUT_FAUCET_FILE = "inst/faucet.yaml" @@ -52,6 +57,8 @@ def __init__(self, config): self.sec_dpid = None self.sec_port = None self._settle_sec = int(config['settle_sec']) + subnet = config.get('internal_subnet', {}).get('subnet', self.DEFAULT_MININET_SUBNET) + self._mininet_subnet = ip_network(subnet) self.topology = FaucetTopology(self.config) self.ext_intf = self.topology.get_ext_intf() switch_setup = config.get('switch_setup', {}) @@ -111,6 +118,10 @@ def remove_host(self, host): intf.delete() del self.net.links[self.net.links.index(switch_link)] + def get_subnet(self): + """Gets the internal mininet subnet""" + return copy.copy(self._mininet_subnet) + def _create_secondary(self): self.sec_dpid = self.topology.get_sec_dpid() self.sec_port = self.topology.get_sec_port() @@ -164,7 +175,7 @@ def initialize(self): """Initialize network""" LOGGER.debug("Creating miniet...") - self.net = mininet_net.Mininet(ipBase='10.20.0.0/16') + self.net = mininet_net.Mininet(ipBase=str(self._mininet_subnet)) LOGGER.debug("Adding primary...") self.pri = self.net.addSwitch('pri', dpid='1', cls=self.OVS_CLS) diff --git a/daq/test_modules/external_module.py b/daq/test_modules/external_module.py index ef0dbf0a28..9cf3d1b6b5 100644 --- a/daq/test_modules/external_module.py +++ b/daq/test_modules/external_module.py @@ -4,6 +4,7 @@ import datetime import abc import os +from ipaddress import ip_network, ip_address import logger import wrappers @@ -24,6 +25,7 @@ def __init__(self, host, tmpdir, test_name, module_config, basedir="/"): self.host = None self.pipe = None self.basedir = basedir + self.external_subnets = self.runner.config.get('external_subnets', []) @abc.abstractmethod def _get_module_class(self): @@ -46,6 +48,10 @@ def start(self, port, params, callback, finish_hook): try: pipe = host.activate(log_name=None) + # For devcies with ips that are not in the same subnet as test hosts' ips. + host_ip = self._get_host_ip(params) + if host.intf() and host_ip: + host.cmd('ip addr add %s dev %s' % (host_ip, host.intf())) self.log = host.open_log() if self._should_raise_test_exception('initialize'): LOGGER.error('%s inducing initialization failure', self) @@ -73,6 +79,17 @@ def terminate(self): LOGGER.info("%s terminating", self) return self._finalize() + def _get_host_ip(self, params): + target_subnet = ip_network(params['target_ip']) + if not target_subnet.overlaps(self.runner.network.get_subnet()): + for subnet_spec in self.external_subnets: + subnet = ip_network(subnet_spec['subnet']) + if target_subnet.overlaps(subnet): + target_ip = ip_address(params['target_ip']) + new_ip = target_ip + (-1 if target_ip == subnet.broadcast_address - 1 else 1) + return "%s/%s" % (str(new_ip), subnet.prefixlen) + return None + def _get_env_vars(self, params): def opt_param(key): return params.get(key) or '' # Substitute empty string for None diff --git a/daq/test_modules/native_host.py b/daq/test_modules/native_host.py index 7bbef61729..7f732e42e0 100644 --- a/daq/test_modules/native_host.py +++ b/daq/test_modules/native_host.py @@ -42,12 +42,6 @@ def activate(self, log_name='activate.log'): assert not self.active_pipe, '%s already activated' % self.name env = dict(self.env_vars) - # for devcies with ips that are not in the same subnet as test hosts' ips. - # TODO: ip added assumes a /16 subnet - if self.intf() and "TARGET_IP" in env and not env["TARGET_IP"].startswith('10.20'): - parts = env["TARGET_IP"].split('.') - parts[-1] = str((int(parts[-1]) + 1) % 256) - self.cmd('ip addr add %s/16 dev %s' % (".".join(parts), self.intf())) self.cmd('mkdir %s' % os.path.join(self.basedir, "config")) diff --git a/firebase/public/protos.hash b/firebase/public/protos.hash index e8117458c0..611e042c88 100644 --- a/firebase/public/protos.hash +++ b/firebase/public/protos.hash @@ -1 +1 @@ -d0774fd8d947d144780f99ea2034c9a650f1ecdd proto/system_config.proto +290dd93561cbf47c11b3aac26d8327d45fa74328 proto/system_config.proto diff --git a/firebase/public/protos.html b/firebase/public/protos.html index 7819ad028b..6247c44e65 100644 --- a/firebase/public/protos.html +++ b/firebase/public/protos.html @@ -202,6 +202,10 @@

      Table of Contents

      MRunTrigger +
    • + MSubnetSpec +
    • +
    • MSwitchSetup
    • @@ -529,6 +533,20 @@

      DaqConfig

      + + + + + + + + + + + + + +

      Reporting device result

      external_subnetsSubnetSpecrepeated

      For specifying ip subnets assigned by external DHCP server / static ips

      internal_subnetSubnetSpec

      IP subnet used by test hosts

      @@ -691,6 +709,30 @@

      RunTrigger

      +

      SubnetSpec

      +

      For specifying internal / external subnets information

      + + + + + + + + + + + + + + + + +
      FieldTypeLabelDescription
      subnetstring

      + + + + +

      SwitchSetup

      System configuraiton of the access switch. This is used by the system

      to setup and configure the switch itself.

      diff --git a/libs/proto/system_config_pb2.py b/libs/proto/system_config_pb2.py index a65af762cf..6e7accfe3b 100644 --- a/libs/proto/system_config_pb2.py +++ b/libs/proto/system_config_pb2.py @@ -1,7 +1,8 @@ -# -*- coding: utf-8 -*- # Generated by the protocol buffer compiler. DO NOT EDIT! # source: daq/proto/system_config.proto -"""Generated protocol buffer code.""" + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) from google.protobuf.internal import enum_type_wrapper from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message @@ -19,8 +20,7 @@ package='', syntax='proto3', serialized_options=None, - create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\x1d\x64\x61q/proto/system_config.proto\"\x94\t\n\tDaqConfig\x12\x18\n\x10site_description\x18\x01 \x01(\t\x12\x18\n\x10monitor_scan_sec\x18\x02 \x01(\x05\x12\x1b\n\x13\x64\x65\x66\x61ult_timeout_sec\x18\x03 \x01(\x05\x12\x12\n\nsettle_sec\x18& \x01(\x05\x12\x11\n\tbase_conf\x18\x04 \x01(\t\x12\x11\n\tsite_path\x18\x05 \x01(\t\x12\x1f\n\x17initial_dhcp_lease_time\x18\x06 \x01(\t\x12\x17\n\x0f\x64hcp_lease_time\x18\x07 \x01(\t\x12\x19\n\x11\x64hcp_response_sec\x18\' \x01(\x05\x12\x1e\n\x16long_dhcp_response_sec\x18\x08 \x01(\x05\x12\"\n\x0cswitch_setup\x18\t \x01(\x0b\x32\x0c.SwitchSetup\x12\x12\n\nhost_tests\x18\x10 \x01(\t\x12\x13\n\x0b\x62uild_tests\x18$ \x01(\x08\x12\x11\n\trun_limit\x18\x11 \x01(\x05\x12\x11\n\tfail_mode\x18\x12 \x01(\x08\x12\x13\n\x0bsingle_shot\x18\" \x01(\x08\x12\x15\n\rresult_linger\x18\x13 \x01(\x08\x12\x0f\n\x07no_test\x18\x14 \x01(\x08\x12\x11\n\tkeep_hold\x18( \x01(\x08\x12\x14\n\x0c\x64\x61q_loglevel\x18\x15 \x01(\t\x12\x18\n\x10mininet_loglevel\x18\x16 \x01(\t\x12\x13\n\x0b\x66inish_hook\x18# \x01(\t\x12\x10\n\x08gcp_cred\x18\x17 \x01(\t\x12\x11\n\tgcp_topic\x18\x18 \x01(\t\x12\x13\n\x0bschema_path\x18\x19 \x01(\t\x12\x11\n\tmud_files\x18\x1a \x01(\t\x12\x14\n\x0c\x64\x65vice_specs\x18\x1b \x01(\t\x12\x13\n\x0btest_config\x18\x1c \x01(\t\x12\x19\n\x11port_debounce_sec\x18\x1d \x01(\x05\x12\x15\n\rtopology_hook\x18\x1e \x01(\t\x12\x17\n\x0f\x64\x65vice_template\x18\x1f \x01(\t\x12\x14\n\x0csite_reports\x18 \x01(\t\x12\x1f\n\x17run_data_retention_days\x18! \x01(\x02\x12.\n\ninterfaces\x18% \x03(\x0b\x32\x1a.DaqConfig.InterfacesEntry\x12/\n\x0b\x66\x61il_module\x18/ \x03(\x0b\x32\x1a.DaqConfig.FailModuleEntry\x12\x1d\n\x15port_flap_timeout_sec\x18\x30 \x01(\x05\x12\x1c\n\tusi_setup\x18\x31 \x01(\x0b\x32\t.UsiSetup\x12 \n\x0brun_trigger\x18\x32 \x01(\x0b\x32\x0b.RunTrigger\x12\x12\n\ndebug_mode\x18\x33 \x01(\x08\x12\x13\n\x0buse_console\x18\x34 \x01(\x08\x12*\n\x10\x64\x65vice_reporting\x18\x35 \x01(\x0b\x32\x10.DeviceReporting\x1a=\n\x0fInterfacesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x19\n\x05value\x18\x02 \x01(\x0b\x32\n.Interface:\x02\x38\x01\x1a\x31\n\x0f\x46\x61ilModuleEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"0\n\x08UsiSetup\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x17\n\x0frpc_timeout_sec\x18\x02 \x01(\x05\"\xf4\x01\n\x0bSwitchSetup\x12\x11\n\tctrl_intf\x18\t \x01(\t\x12\x0f\n\x07ip_addr\x18\x0b \x01(\t\x12\x13\n\x0buplink_port\x18\r \x01(\x05\x12\x0f\n\x07lo_port\x18\x0e \x01(\x05\x12\x10\n\x08\x61lt_port\x18\x10 \x01(\x05\x12\x0f\n\x07lo_addr\x18\x12 \x01(\t\x12\x11\n\tmods_addr\x18\x14 \x01(\t\x12\x0f\n\x07of_dpid\x18) \x01(\t\x12\x11\n\tdata_intf\x18* \x01(\t\x12\x0e\n\x06\x65xt_br\x18+ \x01(\t\x12\r\n\x05model\x18, \x01(\t\x12\x10\n\x08username\x18- \x01(\t\x12\x10\n\x08password\x18. \x01(\t\"G\n\nRunTrigger\x12\x12\n\nvlan_start\x18\x01 \x01(\x05\x12\x10\n\x08vlan_end\x18\x02 \x01(\x05\x12\x13\n\x0b\x65gress_vlan\x18\x03 \x01(\x05\"\'\n\tInterface\x12\x0c\n\x04opts\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05\"&\n\x0f\x44\x65viceReporting\x12\x13\n\x0bserver_port\x18\x01 \x01(\x05*U\n\x08\x44hcpMode\x12\n\n\x06NORMAL\x10\x00\x12\r\n\tSTATIC_IP\x10\x01\x12\x0c\n\x08\x45XTERNAL\x10\x02\x12\x11\n\rLONG_RESPONSE\x10\x03\x12\r\n\tIP_CHANGE\x10\x04\x62\x06proto3' + serialized_pb=_b('\n\x1d\x64\x61q/proto/system_config.proto\"\xe1\t\n\tDaqConfig\x12\x18\n\x10site_description\x18\x01 \x01(\t\x12\x18\n\x10monitor_scan_sec\x18\x02 \x01(\x05\x12\x1b\n\x13\x64\x65\x66\x61ult_timeout_sec\x18\x03 \x01(\x05\x12\x12\n\nsettle_sec\x18& \x01(\x05\x12\x11\n\tbase_conf\x18\x04 \x01(\t\x12\x11\n\tsite_path\x18\x05 \x01(\t\x12\x1f\n\x17initial_dhcp_lease_time\x18\x06 \x01(\t\x12\x17\n\x0f\x64hcp_lease_time\x18\x07 \x01(\t\x12\x19\n\x11\x64hcp_response_sec\x18\' \x01(\x05\x12\x1e\n\x16long_dhcp_response_sec\x18\x08 \x01(\x05\x12\"\n\x0cswitch_setup\x18\t \x01(\x0b\x32\x0c.SwitchSetup\x12\x12\n\nhost_tests\x18\x10 \x01(\t\x12\x13\n\x0b\x62uild_tests\x18$ \x01(\x08\x12\x11\n\trun_limit\x18\x11 \x01(\x05\x12\x11\n\tfail_mode\x18\x12 \x01(\x08\x12\x13\n\x0bsingle_shot\x18\" \x01(\x08\x12\x15\n\rresult_linger\x18\x13 \x01(\x08\x12\x0f\n\x07no_test\x18\x14 \x01(\x08\x12\x11\n\tkeep_hold\x18( \x01(\x08\x12\x14\n\x0c\x64\x61q_loglevel\x18\x15 \x01(\t\x12\x18\n\x10mininet_loglevel\x18\x16 \x01(\t\x12\x13\n\x0b\x66inish_hook\x18# \x01(\t\x12\x10\n\x08gcp_cred\x18\x17 \x01(\t\x12\x11\n\tgcp_topic\x18\x18 \x01(\t\x12\x13\n\x0bschema_path\x18\x19 \x01(\t\x12\x11\n\tmud_files\x18\x1a \x01(\t\x12\x14\n\x0c\x64\x65vice_specs\x18\x1b \x01(\t\x12\x13\n\x0btest_config\x18\x1c \x01(\t\x12\x19\n\x11port_debounce_sec\x18\x1d \x01(\x05\x12\x15\n\rtopology_hook\x18\x1e \x01(\t\x12\x17\n\x0f\x64\x65vice_template\x18\x1f \x01(\t\x12\x14\n\x0csite_reports\x18 \x01(\t\x12\x1f\n\x17run_data_retention_days\x18! \x01(\x02\x12.\n\ninterfaces\x18% \x03(\x0b\x32\x1a.DaqConfig.InterfacesEntry\x12/\n\x0b\x66\x61il_module\x18/ \x03(\x0b\x32\x1a.DaqConfig.FailModuleEntry\x12\x1d\n\x15port_flap_timeout_sec\x18\x30 \x01(\x05\x12\x1c\n\tusi_setup\x18\x31 \x01(\x0b\x32\t.UsiSetup\x12 \n\x0brun_trigger\x18\x32 \x01(\x0b\x32\x0b.RunTrigger\x12\x12\n\ndebug_mode\x18\x33 \x01(\x08\x12\x13\n\x0buse_console\x18\x34 \x01(\x08\x12*\n\x10\x64\x65vice_reporting\x18\x35 \x01(\x0b\x32\x10.DeviceReporting\x12%\n\x10\x65xternal_subnets\x18\x36 \x03(\x0b\x32\x0b.SubnetSpec\x12$\n\x0finternal_subnet\x18\x37 \x01(\x0b\x32\x0b.SubnetSpec\x1a=\n\x0fInterfacesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\x19\n\x05value\x18\x02 \x01(\x0b\x32\n.Interface:\x02\x38\x01\x1a\x31\n\x0f\x46\x61ilModuleEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x1c\n\nSubnetSpec\x12\x0e\n\x06subnet\x18\x01 \x01(\t\"0\n\x08UsiSetup\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x17\n\x0frpc_timeout_sec\x18\x02 \x01(\x05\"\xf4\x01\n\x0bSwitchSetup\x12\x11\n\tctrl_intf\x18\t \x01(\t\x12\x0f\n\x07ip_addr\x18\x0b \x01(\t\x12\x13\n\x0buplink_port\x18\r \x01(\x05\x12\x0f\n\x07lo_port\x18\x0e \x01(\x05\x12\x10\n\x08\x61lt_port\x18\x10 \x01(\x05\x12\x0f\n\x07lo_addr\x18\x12 \x01(\t\x12\x11\n\tmods_addr\x18\x14 \x01(\t\x12\x0f\n\x07of_dpid\x18) \x01(\t\x12\x11\n\tdata_intf\x18* \x01(\t\x12\x0e\n\x06\x65xt_br\x18+ \x01(\t\x12\r\n\x05model\x18, \x01(\t\x12\x10\n\x08username\x18- \x01(\t\x12\x10\n\x08password\x18. \x01(\t\"G\n\nRunTrigger\x12\x12\n\nvlan_start\x18\x01 \x01(\x05\x12\x10\n\x08vlan_end\x18\x02 \x01(\x05\x12\x13\n\x0b\x65gress_vlan\x18\x03 \x01(\x05\"\'\n\tInterface\x12\x0c\n\x04opts\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05\"&\n\x0f\x44\x65viceReporting\x12\x13\n\x0bserver_port\x18\x01 \x01(\x05*U\n\x08\x44hcpMode\x12\n\n\x06NORMAL\x10\x00\x12\r\n\tSTATIC_IP\x10\x01\x12\x0c\n\x08\x45XTERNAL\x10\x02\x12\x11\n\rLONG_RESPONSE\x10\x03\x12\r\n\tIP_CHANGE\x10\x04\x62\x06proto3') ) _DHCPMODE = _descriptor.EnumDescriptor( @@ -28,38 +28,32 @@ full_name='DhcpMode', filename=None, file=DESCRIPTOR, - create_key=_descriptor._internal_create_key, values=[ _descriptor.EnumValueDescriptor( name='NORMAL', index=0, number=0, serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), + type=None), _descriptor.EnumValueDescriptor( name='STATIC_IP', index=1, number=1, serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), + type=None), _descriptor.EnumValueDescriptor( name='EXTERNAL', index=2, number=2, serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), + type=None), _descriptor.EnumValueDescriptor( name='LONG_RESPONSE', index=3, number=3, serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), + type=None), _descriptor.EnumValueDescriptor( name='IP_CHANGE', index=4, number=4, serialized_options=None, - type=None, - create_key=_descriptor._internal_create_key), + type=None), ], containing_type=None, serialized_options=None, - serialized_start=1659, - serialized_end=1744, + serialized_start=1766, + serialized_end=1851, ) _sym_db.RegisterEnumDescriptor(_DHCPMODE) @@ -78,36 +72,35 @@ filename=None, file=DESCRIPTOR, containing_type=None, - create_key=_descriptor._internal_create_key, fields=[ _descriptor.FieldDescriptor( name='key', full_name='DaqConfig.InterfacesEntry.key', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='value', full_name='DaqConfig.InterfacesEntry.value', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - serialized_options=b'8\001', + serialized_options=_b('8\001'), is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=1094, - serialized_end=1155, + serialized_start=1171, + serialized_end=1232, ) _DAQCONFIG_FAILMODULEENTRY = _descriptor.Descriptor( @@ -116,36 +109,35 @@ filename=None, file=DESCRIPTOR, containing_type=None, - create_key=_descriptor._internal_create_key, fields=[ _descriptor.FieldDescriptor( name='key', full_name='DaqConfig.FailModuleEntry.key', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='value', full_name='DaqConfig.FailModuleEntry.value', index=1, number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - serialized_options=b'8\001', + serialized_options=_b('8\001'), is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=1157, - serialized_end=1206, + serialized_start=1234, + serialized_end=1283, ) _DAQCONFIG = _descriptor.Descriptor( @@ -154,295 +146,308 @@ filename=None, file=DESCRIPTOR, containing_type=None, - create_key=_descriptor._internal_create_key, fields=[ _descriptor.FieldDescriptor( name='site_description', full_name='DaqConfig.site_description', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='monitor_scan_sec', full_name='DaqConfig.monitor_scan_sec', index=1, number=2, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='default_timeout_sec', full_name='DaqConfig.default_timeout_sec', index=2, number=3, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='settle_sec', full_name='DaqConfig.settle_sec', index=3, number=38, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='base_conf', full_name='DaqConfig.base_conf', index=4, number=4, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='site_path', full_name='DaqConfig.site_path', index=5, number=5, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='initial_dhcp_lease_time', full_name='DaqConfig.initial_dhcp_lease_time', index=6, number=6, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='dhcp_lease_time', full_name='DaqConfig.dhcp_lease_time', index=7, number=7, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='dhcp_response_sec', full_name='DaqConfig.dhcp_response_sec', index=8, number=39, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='long_dhcp_response_sec', full_name='DaqConfig.long_dhcp_response_sec', index=9, number=8, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='switch_setup', full_name='DaqConfig.switch_setup', index=10, number=9, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='host_tests', full_name='DaqConfig.host_tests', index=11, number=16, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='build_tests', full_name='DaqConfig.build_tests', index=12, number=36, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='run_limit', full_name='DaqConfig.run_limit', index=13, number=17, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='fail_mode', full_name='DaqConfig.fail_mode', index=14, number=18, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='single_shot', full_name='DaqConfig.single_shot', index=15, number=34, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='result_linger', full_name='DaqConfig.result_linger', index=16, number=19, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='no_test', full_name='DaqConfig.no_test', index=17, number=20, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='keep_hold', full_name='DaqConfig.keep_hold', index=18, number=40, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='daq_loglevel', full_name='DaqConfig.daq_loglevel', index=19, number=21, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='mininet_loglevel', full_name='DaqConfig.mininet_loglevel', index=20, number=22, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='finish_hook', full_name='DaqConfig.finish_hook', index=21, number=35, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='gcp_cred', full_name='DaqConfig.gcp_cred', index=22, number=23, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='gcp_topic', full_name='DaqConfig.gcp_topic', index=23, number=24, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='schema_path', full_name='DaqConfig.schema_path', index=24, number=25, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='mud_files', full_name='DaqConfig.mud_files', index=25, number=26, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='device_specs', full_name='DaqConfig.device_specs', index=26, number=27, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='test_config', full_name='DaqConfig.test_config', index=27, number=28, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='port_debounce_sec', full_name='DaqConfig.port_debounce_sec', index=28, number=29, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='topology_hook', full_name='DaqConfig.topology_hook', index=29, number=30, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='device_template', full_name='DaqConfig.device_template', index=30, number=31, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='site_reports', full_name='DaqConfig.site_reports', index=31, number=32, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='run_data_retention_days', full_name='DaqConfig.run_data_retention_days', index=32, number=33, type=2, cpp_type=6, label=1, has_default_value=False, default_value=float(0), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='interfaces', full_name='DaqConfig.interfaces', index=33, number=37, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='fail_module', full_name='DaqConfig.fail_module', index=34, number=47, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='port_flap_timeout_sec', full_name='DaqConfig.port_flap_timeout_sec', index=35, number=48, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='usi_setup', full_name='DaqConfig.usi_setup', index=36, number=49, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='run_trigger', full_name='DaqConfig.run_trigger', index=37, number=50, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='debug_mode', full_name='DaqConfig.debug_mode', index=38, number=51, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='use_console', full_name='DaqConfig.use_console', index=39, number=52, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='device_reporting', full_name='DaqConfig.device_reporting', index=40, number=53, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='external_subnets', full_name='DaqConfig.external_subnets', index=41, + number=54, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='internal_subnet', full_name='DaqConfig.internal_subnet', index=42, + number=55, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], @@ -456,7 +461,38 @@ oneofs=[ ], serialized_start=34, - serialized_end=1206, + serialized_end=1283, +) + + +_SUBNETSPEC = _descriptor.Descriptor( + name='SubnetSpec', + full_name='SubnetSpec', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='subnet', full_name='SubnetSpec.subnet', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1285, + serialized_end=1313, ) @@ -466,22 +502,21 @@ filename=None, file=DESCRIPTOR, containing_type=None, - create_key=_descriptor._internal_create_key, fields=[ _descriptor.FieldDescriptor( name='url', full_name='UsiSetup.url', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='rpc_timeout_sec', full_name='UsiSetup.rpc_timeout_sec', index=1, number=2, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], @@ -494,8 +529,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1208, - serialized_end=1256, + serialized_start=1315, + serialized_end=1363, ) @@ -505,99 +540,98 @@ filename=None, file=DESCRIPTOR, containing_type=None, - create_key=_descriptor._internal_create_key, fields=[ _descriptor.FieldDescriptor( name='ctrl_intf', full_name='SwitchSetup.ctrl_intf', index=0, number=9, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='ip_addr', full_name='SwitchSetup.ip_addr', index=1, number=11, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='uplink_port', full_name='SwitchSetup.uplink_port', index=2, number=13, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='lo_port', full_name='SwitchSetup.lo_port', index=3, number=14, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='alt_port', full_name='SwitchSetup.alt_port', index=4, number=16, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='lo_addr', full_name='SwitchSetup.lo_addr', index=5, number=18, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='mods_addr', full_name='SwitchSetup.mods_addr', index=6, number=20, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='of_dpid', full_name='SwitchSetup.of_dpid', index=7, number=41, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='data_intf', full_name='SwitchSetup.data_intf', index=8, number=42, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='ext_br', full_name='SwitchSetup.ext_br', index=9, number=43, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='model', full_name='SwitchSetup.model', index=10, number=44, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='username', full_name='SwitchSetup.username', index=11, number=45, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='password', full_name='SwitchSetup.password', index=12, number=46, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], @@ -610,8 +644,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1259, - serialized_end=1503, + serialized_start=1366, + serialized_end=1610, ) @@ -621,7 +655,6 @@ filename=None, file=DESCRIPTOR, containing_type=None, - create_key=_descriptor._internal_create_key, fields=[ _descriptor.FieldDescriptor( name='vlan_start', full_name='RunTrigger.vlan_start', index=0, @@ -629,21 +662,21 @@ has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='vlan_end', full_name='RunTrigger.vlan_end', index=1, number=2, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='egress_vlan', full_name='RunTrigger.egress_vlan', index=2, number=3, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], @@ -656,8 +689,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1505, - serialized_end=1576, + serialized_start=1612, + serialized_end=1683, ) @@ -667,22 +700,21 @@ filename=None, file=DESCRIPTOR, containing_type=None, - create_key=_descriptor._internal_create_key, fields=[ _descriptor.FieldDescriptor( name='opts', full_name='Interface.opts', index=0, number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=b"".decode('utf-8'), + has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='port', full_name='Interface.port', index=1, number=2, type=5, cpp_type=1, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], @@ -695,8 +727,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1578, - serialized_end=1617, + serialized_start=1685, + serialized_end=1724, ) @@ -706,7 +738,6 @@ filename=None, file=DESCRIPTOR, containing_type=None, - create_key=_descriptor._internal_create_key, fields=[ _descriptor.FieldDescriptor( name='server_port', full_name='DeviceReporting.server_port', index=0, @@ -714,7 +745,7 @@ has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], @@ -727,8 +758,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1619, - serialized_end=1657, + serialized_start=1726, + serialized_end=1764, ) _DAQCONFIG_INTERFACESENTRY.fields_by_name['value'].message_type = _INTERFACE @@ -740,7 +771,10 @@ _DAQCONFIG.fields_by_name['usi_setup'].message_type = _USISETUP _DAQCONFIG.fields_by_name['run_trigger'].message_type = _RUNTRIGGER _DAQCONFIG.fields_by_name['device_reporting'].message_type = _DEVICEREPORTING +_DAQCONFIG.fields_by_name['external_subnets'].message_type = _SUBNETSPEC +_DAQCONFIG.fields_by_name['internal_subnet'].message_type = _SUBNETSPEC DESCRIPTOR.message_types_by_name['DaqConfig'] = _DAQCONFIG +DESCRIPTOR.message_types_by_name['SubnetSpec'] = _SUBNETSPEC DESCRIPTOR.message_types_by_name['UsiSetup'] = _USISETUP DESCRIPTOR.message_types_by_name['SwitchSetup'] = _SWITCHSETUP DESCRIPTOR.message_types_by_name['RunTrigger'] = _RUNTRIGGER @@ -749,62 +783,69 @@ DESCRIPTOR.enum_types_by_name['DhcpMode'] = _DHCPMODE _sym_db.RegisterFileDescriptor(DESCRIPTOR) -DaqConfig = _reflection.GeneratedProtocolMessageType('DaqConfig', (_message.Message,), { +DaqConfig = _reflection.GeneratedProtocolMessageType('DaqConfig', (_message.Message,), dict( - 'InterfacesEntry' : _reflection.GeneratedProtocolMessageType('InterfacesEntry', (_message.Message,), { - 'DESCRIPTOR' : _DAQCONFIG_INTERFACESENTRY, - '__module__' : 'daq.proto.system_config_pb2' + InterfacesEntry = _reflection.GeneratedProtocolMessageType('InterfacesEntry', (_message.Message,), dict( + DESCRIPTOR = _DAQCONFIG_INTERFACESENTRY, + __module__ = 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:DaqConfig.InterfacesEntry) - }) + )) , - 'FailModuleEntry' : _reflection.GeneratedProtocolMessageType('FailModuleEntry', (_message.Message,), { - 'DESCRIPTOR' : _DAQCONFIG_FAILMODULEENTRY, - '__module__' : 'daq.proto.system_config_pb2' + FailModuleEntry = _reflection.GeneratedProtocolMessageType('FailModuleEntry', (_message.Message,), dict( + DESCRIPTOR = _DAQCONFIG_FAILMODULEENTRY, + __module__ = 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:DaqConfig.FailModuleEntry) - }) + )) , - 'DESCRIPTOR' : _DAQCONFIG, - '__module__' : 'daq.proto.system_config_pb2' + DESCRIPTOR = _DAQCONFIG, + __module__ = 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:DaqConfig) - }) + )) _sym_db.RegisterMessage(DaqConfig) _sym_db.RegisterMessage(DaqConfig.InterfacesEntry) _sym_db.RegisterMessage(DaqConfig.FailModuleEntry) -UsiSetup = _reflection.GeneratedProtocolMessageType('UsiSetup', (_message.Message,), { - 'DESCRIPTOR' : _USISETUP, - '__module__' : 'daq.proto.system_config_pb2' +SubnetSpec = _reflection.GeneratedProtocolMessageType('SubnetSpec', (_message.Message,), dict( + DESCRIPTOR = _SUBNETSPEC, + __module__ = 'daq.proto.system_config_pb2' + # @@protoc_insertion_point(class_scope:SubnetSpec) + )) +_sym_db.RegisterMessage(SubnetSpec) + +UsiSetup = _reflection.GeneratedProtocolMessageType('UsiSetup', (_message.Message,), dict( + DESCRIPTOR = _USISETUP, + __module__ = 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:UsiSetup) - }) + )) _sym_db.RegisterMessage(UsiSetup) -SwitchSetup = _reflection.GeneratedProtocolMessageType('SwitchSetup', (_message.Message,), { - 'DESCRIPTOR' : _SWITCHSETUP, - '__module__' : 'daq.proto.system_config_pb2' +SwitchSetup = _reflection.GeneratedProtocolMessageType('SwitchSetup', (_message.Message,), dict( + DESCRIPTOR = _SWITCHSETUP, + __module__ = 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:SwitchSetup) - }) + )) _sym_db.RegisterMessage(SwitchSetup) -RunTrigger = _reflection.GeneratedProtocolMessageType('RunTrigger', (_message.Message,), { - 'DESCRIPTOR' : _RUNTRIGGER, - '__module__' : 'daq.proto.system_config_pb2' +RunTrigger = _reflection.GeneratedProtocolMessageType('RunTrigger', (_message.Message,), dict( + DESCRIPTOR = _RUNTRIGGER, + __module__ = 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:RunTrigger) - }) + )) _sym_db.RegisterMessage(RunTrigger) -Interface = _reflection.GeneratedProtocolMessageType('Interface', (_message.Message,), { - 'DESCRIPTOR' : _INTERFACE, - '__module__' : 'daq.proto.system_config_pb2' +Interface = _reflection.GeneratedProtocolMessageType('Interface', (_message.Message,), dict( + DESCRIPTOR = _INTERFACE, + __module__ = 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:Interface) - }) + )) _sym_db.RegisterMessage(Interface) -DeviceReporting = _reflection.GeneratedProtocolMessageType('DeviceReporting', (_message.Message,), { - 'DESCRIPTOR' : _DEVICEREPORTING, - '__module__' : 'daq.proto.system_config_pb2' +DeviceReporting = _reflection.GeneratedProtocolMessageType('DeviceReporting', (_message.Message,), dict( + DESCRIPTOR = _DEVICEREPORTING, + __module__ = 'daq.proto.system_config_pb2' # @@protoc_insertion_point(class_scope:DeviceReporting) - }) + )) _sym_db.RegisterMessage(DeviceReporting) diff --git a/proto/system_config.proto b/proto/system_config.proto index 3d479ad6cf..94a70345d0 100644 --- a/proto/system_config.proto +++ b/proto/system_config.proto @@ -129,6 +129,12 @@ message DaqConfig { // Reporting device result DeviceReporting device_reporting = 53; + + // For specifying ip subnets assigned by external DHCP server / static ips + repeated SubnetSpec external_subnets = 54; + + // IP subnet used by test hosts + SubnetSpec internal_subnet = 55; } enum DhcpMode { @@ -139,6 +145,13 @@ enum DhcpMode { IP_CHANGE = 4; } +/** + * For specifying internal / external subnets information +**/ +message SubnetSpec { + string subnet = 1; +} + /** * USI paramters **/ From 43c398d0bb7d37ea7ab4b9dba35d5332b918c644 Mon Sep 17 00:00:00 2001 From: Noureddine Date: Fri, 20 Nov 2020 16:07:26 +0000 Subject: [PATCH 199/212] add result line for connection.network.mac_address (#697) * adding the mac_address test result in the report --- docs/device_report.md | 12 +++++++++++- subset/network/run_macoui_test | 12 ++++++++++++ testing/test_aux.out | 3 +++ testing/test_aux.sh | 1 - 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/docs/device_report.md b/docs/device_report.md index 369af071b3..44dbb8d8dc 100644 --- a/docs/device_report.md +++ b/docs/device_report.md @@ -56,7 +56,7 @@ Overall device result FAIL |---|---|---|---|---|---| |Required|1|0|0|0|0| |Recommended|1|0|0|0|1| -|Other|6|2|21|1|2| +|Other|6|2|21|2|2| |Result|Test|Category|Expectation|Notes| |---|---|---|---|---| @@ -69,6 +69,7 @@ Overall device result FAIL |pass|communication.network.min_send|Other|Other|ARP packets received. Data packets were sent at a frequency of less than 5 minutes| |info|communication.network.type|Other|Other|Broadcast packets received. Unicast packets received.| |pass|connection.base.target_ping|Connectivity|Required|target reached| +|info|connection.network.mac_address|Other|Other|Device MAC address is 9a:02:57:1e:8f:01| |fail|connection.network.mac_oui|Other|Other|Manufacturer prefix not found!| |skip|connection.switch.port_duplex|Other|Other|No local IP has been set, check system config| |skip|connection.switch.port_link|Other|Other|No local IP has been set, check system config| @@ -599,6 +600,15 @@ Mac OUI Test -------------------- RESULT fail connection.network.mac_oui Manufacturer prefix not found! +-------------------- +connection.network.mac_address +-------------------- +Reports device MAC address +-------------------- +Device MAC address is 9a:02:57:1e:8f:01 +-------------------- +RESULT info connection.network.mac_address Device MAC address is 9a:02:57:1e:8f:01 + -------------------- dns.network.hostname_resolution -------------------- diff --git a/subset/network/run_macoui_test b/subset/network/run_macoui_test index 2507147b30..39a5d2880d 100755 --- a/subset/network/run_macoui_test +++ b/subset/network/run_macoui_test @@ -28,3 +28,15 @@ write_out_result $REPORT \ "$TEST_DESCRIPTION" \ "$TEST_RESULT" \ "$RESULT_AND_SUMMARY" + +# Write result for connection.network.mac_address +TEST_NAME="connection.network.mac_address" +TEST_DESCRIPTION="Reports device MAC address" +TEST_RESULT="Device MAC address is ${TARGET_MAC}" +RESULT_AND_SUMMARY="RESULT info ${TEST_NAME} ${TEST_RESULT}" + +write_out_result $REPORT \ + "$TEST_NAME" \ + "$TEST_DESCRIPTION" \ + "$TEST_RESULT" \ + "$RESULT_AND_SUMMARY" diff --git a/testing/test_aux.out b/testing/test_aux.out index b873ced907..a34f90be51 100644 --- a/testing/test_aux.out +++ b/testing/test_aux.out @@ -55,18 +55,21 @@ RESULT info communication.network.type Broadcast packets received. Unicast packe RESULT pass ntp.network.ntp_support Using NTPv4. RESULT pass ntp.network.ntp_update Device clock synchronized. RESULT fail connection.network.mac_oui Manufacturer prefix not found! +RESULT info connection.network.mac_address Device MAC address is 9a:02:57:1e:8f:01 RESULT skip dns.network.hostname_resolution Device did not send any DNS requests RESULT pass communication.network.min_send ARP packets received. Data packets were sent at a frequency of less than 5 minutes RESULT info communication.network.type Broadcast packets received. Unicast packets received. RESULT fail ntp.network.ntp_support Not using NTPv4. RESULT fail ntp.network.ntp_update Device clock not synchronized with local NTP server. RESULT pass connection.network.mac_oui Manufacturer: Google found for address 3c:5a:b4:1e:8f:0b +RESULT info connection.network.mac_address Device MAC address is 3c:5a:b4:1e:8f:0b RESULT fail dns.network.hostname_resolution Device sent DNS requests to servers other than the DHCP provided server RESULT pass communication.network.min_send ARP packets received. Data packets were sent at a frequency of less than 5 minutes RESULT info communication.network.type Broadcast packets received. Unicast packets received. RESULT skip ntp.network.ntp_support No NTP packets received. RESULT skip ntp.network.ntp_update Not enough NTP packets received. RESULT pass connection.network.mac_oui Manufacturer: Google found for address 3c:5a:b4:1e:8f:0a +RESULT info connection.network.mac_address Device MAC address is 3c:5a:b4:1e:8f:0a RESULT pass dns.network.hostname_resolution Device sends DNS requests and resolves host names dhcp requests 1 1 1 1 3c5ab41e8f0a: [] diff --git a/testing/test_aux.sh b/testing/test_aux.sh index ed6f03dc6f..ce2b250acf 100755 --- a/testing/test_aux.sh +++ b/testing/test_aux.sh @@ -114,7 +114,6 @@ done # Add the RESULT lines from all aux test report files. capture_test_results bacext -capture_test_results macoui capture_test_results tls capture_test_results password capture_test_results discover From c3a1227aaddf0bbf3075b71a0aee9819b2c57459 Mon Sep 17 00:00:00 2001 From: Noureddine Date: Wed, 25 Nov 2020 16:32:33 +0000 Subject: [PATCH 200/212] Update report aligning to the mockup (#717) * new report summary table implementation --- daq/report.py | 103 +++++++++++-- docs/device_report.md | 75 ++++++---- .../qualification/system_module_config.json | 2 +- resources/test_site/module_config.json | 137 +++++++++++++++++- testing/test_base.out | 7 +- 5 files changed, 270 insertions(+), 54 deletions(-) diff --git a/daq/report.py b/daq/report.py index 60733ba380..e7468d5de7 100644 --- a/daq/report.py +++ b/daq/report.py @@ -67,13 +67,17 @@ class ReportGenerator: _DEFAULT_EXPECTED = 'Other' _PRE_START_MARKER = "```" _PRE_END_MARKER = "```" - _CATEGORY_HEADERS = ["Category", "Result"] + _CATEGORY_BASE_COLS = ["Category", "Total Tests", "Result"] _EXPECTED_HEADER = "Expectation" _SUMMARY_HEADERS = ["Result", "Test", "Category", "Expectation", "Notes"] _MISSING_TEST_RESULT = 'gone' _NO_REQUIRED = 'n/a' _PASS_REQUIRED = 'PASS' + _INDEX_PASS = 0 + _INDEX_FAIL = 1 + _INDEX_SKIP = 2 + def __init__(self, config, tmp_base, target_mac, module_config): self._config = config self._module_config = copy.deepcopy(module_config) @@ -101,7 +105,8 @@ def __init__(self, config, tmp_base, target_mac, module_config): self._expected_headers = list(self._module_config.get('report', {}).get('expected', [])) self._expecteds = {} self._categories = list(self._module_config.get('report', {}).get('categories', [])) - + self._category_headers = [] + self._append_notices = [] self._file_md = None def _write(self, msg=''): @@ -206,6 +211,7 @@ def _write_pdf_report(self): def _write_test_summary(self): self._writeln(self._TEST_SEPARATOR % self._SUMMARY_LINE) + self._analyse_and_write_results() self._write_test_tables() def _accumulate_result(self, test_name, result, extra='', module_name=None): @@ -246,33 +252,102 @@ def _write_test_tables(self): self._write_result_table() self._writeln() - def _write_category_table(self): + def _analyse_and_write_results(self): + """ Analyse the test results to determine if the device is a pass or fail + and identify possible issues (e.g. gone) and writes these to the report + """ passes = True + gone = False + + # Analyse results + for test_name, result_dict in self._results.items(): + test_info = self._get_test_info(test_name) + + if 'required' in test_info: + required_result = test_info['required'] + + # The device overall fails if any result is unexpected + if result_dict["result"] != required_result: + passes = False + + if result_dict["result"] == 'gone': + gone = True + + # Write Results + self._writeln('Overall device result %s' % ('PASS' if passes else 'FAIL')) + self._writeln() + + if gone: + gone_message = ('**Some tests report as GONE. ' + 'Please check for possible misconfiguration**') + self._writeln(gone_message) + self._writeln() + + def _join_category_results(self, results): + """ Used to convert list of results into the pass/fail/skip format + for category table + + Args: + results: List of results + + Returns: + String in pass/fail/skip format + """ + return '/'.join(str(value) for value in results) + + def _write_category_table(self): + """ Write the first category and expected table + """ + rows = [] + self._category_headers = self._CATEGORY_BASE_COLS + self._expected_headers + for category in self._categories: total = 0 - match = 0 + + results = [[0, 0, 0] for _ in range(len(self._expected_headers))] + result = self._NO_REQUIRED # Overall category result + for test_name, result_dict in self._results.items(): test_info = self._get_test_info(test_name) category_name = test_info.get('category', self._DEFAULT_CATEGORY) + + # all tests must have required in order to be counted if category_name == category and 'required' in test_info: - required_result = test_info['required'] total += 1 - if result_dict["result"] == required_result: - match += 1 + + expected_name = test_info.get('expected', self._DEFAULT_EXPECTED) + expected_index = self._expected_headers.index(expected_name) + + # Put test results into right location in the result matrix + if result_dict["result"] in ("pass", "info"): + results[expected_index][self._INDEX_PASS] += 1 + elif result_dict["result"] == "skip": + results[expected_index][self._INDEX_SKIP] += 1 + else: + results[expected_index][self._INDEX_FAIL] += 1 + + # Calculate overall rolling result for the category + if result not in (result_dict["result"], self._NO_REQUIRED): + # Consider info and pass alike + # TODO remove when info tests are removed + if result_dict["result"] == 'info': + result_dict["result"] = 'pass' + else: + result = "fail" else: - passes = False + result = result_dict["result"] - output = self._NO_REQUIRED if total == 0 else (self._PASS_REQUIRED \ - if match == total else '%s/%s' % (match, total)) - rows.append([category, output]) + results = list(map(self._join_category_results, results)) - self._writeln('Overall device result %s' % ('PASS' if passes else 'FAIL')) - self._writeln() - table = MdTable(self._CATEGORY_HEADERS) + row = [category, str(total), result.upper()] + results + rows.append(row) + + table = MdTable(self._category_headers) for row in rows: table.add_row(row) self._write(table.render()) + self._writeln('Syntax: Pass / Fail / Skip') def _write_expected_table(self): table = MdTable([self._EXPECTED_HEADER, *self._result_headers]) diff --git a/docs/device_report.md b/docs/device_report.md index 44dbb8d8dc..e12958aaa4 100644 --- a/docs/device_report.md +++ b/docs/device_report.md @@ -46,49 +46,68 @@ Overall device result FAIL -|Category|Result| -|---|---| -|Security|1/2| -|Other|1/2| -|Connectivity|n/a| +**Some tests report as GONE. Please check for possible misconfiguration** + +|Category|Total Tests|Result|Required Pass|Required Pass for PoE Devices|Required Pass for BACnet Devices|Recommended Pass|Information|Other| +|---|---|---|---|---|---|---|---|---| +|Connection|9|FAIL|1/4/4|0/0/0|0/0/0|0/0/0|0/0/0|0/0/0| +|Security|8|FAIL|1/0/4|0/0/0|0/0/0|1/1/0|0/0/1|0/0/0| +|Network Time|2|PASS|2/0/0|0/0/0|0/0/0|0/0/0|0/0/0|0/0/0| +|TLS|0|N/A|0/0/0|0/0/0|0/0/0|0/0/0|0/0/0|0/0/0| +|Protocol|2|FAIL|0/0/0|0/0/0|0/1/0|0/0/0|0/0/1|0/0/0| +|PoE|3|FAIL|0/0/0|0/1/1|0/0/0|0/0/0|0/1/0|0/0/0| +|BOS|1|SKIP|0/0/0|0/0/0|0/0/0|0/0/1|0/0/0|0/0/0| +|Other|2|GONE|0/0/0|0/0/0|0/0/0|0/0/0|0/0/0|0/2/0| +|Communication|2|GONE|0/1/0|0/0/0|0/0/0|0/0/0|0/1/0|0/0/0| +Syntax: Pass / Fail / Skip |Expectation|pass|fail|skip|info|gone| |---|---|---|---|---|---| -|Required|1|0|0|0|0| -|Recommended|1|0|0|0|1| -|Other|6|2|21|2|2| +|Required Pass|4|1|8|0|4| +|Required Pass for PoE Devices|0|0|1|0|1| +|Required Pass for BACnet Devices|0|1|0|0|0| +|Recommended Pass|1|0|1|0|1| +|Information|0|0|2|0|2| +|Other|3|0|9|2|2| |Result|Test|Category|Expectation|Notes| |---|---|---|---|---| |pass|base.startup.dhcp|Other|Other|| -|skip|base.switch.ping|Other|Other|No local IP has been set, check system config| -|skip|cloud.udmi.pointset|Other|Other|No device id| +|skip|base.switch.ping|Connection|Required Pass|No local IP has been set, check system config| +|skip|cloud.udmi.pointset|BOS|Recommended Pass|No device id| |skip|cloud.udmi.provision|Other|Other|No device id| |skip|cloud.udmi.state|Other|Other|No device id| |skip|cloud.udmi.system|Other|Other|No device id| |pass|communication.network.min_send|Other|Other|ARP packets received. Data packets were sent at a frequency of less than 5 minutes| |info|communication.network.type|Other|Other|Broadcast packets received. Unicast packets received.| -|pass|connection.base.target_ping|Connectivity|Required|target reached| +|pass|connection.base.target_ping|Connection|Required Pass|target reached| +|gone|connection.ipaddr.dhcp_disconnect|Connection|Required Pass|| +|gone|connection.ipaddr.private_address|Connection|Required Pass|| +|gone|connection.network.communication_min_send|Communication|Required Pass|| +|gone|connection.network.communication_type|Communication|Information|| +|gone|connection.network.dhcp_long|Connection|Required Pass|| |info|connection.network.mac_address|Other|Other|Device MAC address is 9a:02:57:1e:8f:01| -|fail|connection.network.mac_oui|Other|Other|Manufacturer prefix not found!| -|skip|connection.switch.port_duplex|Other|Other|No local IP has been set, check system config| -|skip|connection.switch.port_link|Other|Other|No local IP has been set, check system config| -|skip|connection.switch.port_speed|Other|Other|No local IP has been set, check system config| +|fail|connection.network.mac_oui|Connection|Required Pass|Manufacturer prefix not found!| +|skip|connection.switch.port_duplex|Connection|Required Pass|No local IP has been set, check system config| +|skip|connection.switch.port_link|Connection|Required Pass|No local IP has been set, check system config| +|skip|connection.switch.port_speed|Connection|Required Pass|No local IP has been set, check system config| |skip|dns.network.hostname_resolution|Other|Other|Device did not send any DNS requests| -|pass|manual.test.name|Security|Recommended|Manual test - for testing| -|pass|ntp.network.ntp_support|Other|Other|Using NTPv4.| -|pass|ntp.network.ntp_update|Other|Other|Device clock synchronized.| -|skip|poe.switch.power|Other|Other|No local IP has been set, check system config| -|fail|protocol.bacext.pic|Other|Other|PICS file defined however a BACnet device was not found.| -|skip|protocol.bacext.version|Other|Other|Bacnet device not found.| -|skip|security.discover.firmware|Other|Other|Could not retrieve a firmware version with nmap. Check bacnet port.| +|pass|manual.test.name|Security|Recommended Pass|Manual test - for testing| +|pass|ntp.network.ntp_support|Network Time|Required Pass|Using NTPv4.| +|pass|ntp.network.ntp_update|Network Time|Required Pass|Device clock synchronized.| +|gone|poe.switch.negotiation|PoE|Required Pass for PoE Devices|| +|skip|poe.switch.power|PoE|Required Pass for PoE Devices|No local IP has been set, check system config| +|gone|poe.switch.support|PoE|Information|| +|fail|protocol.bacext.pic|Protocol|Required Pass for BACnet Devices|PICS file defined however a BACnet device was not found.| +|skip|protocol.bacext.version|Protocol|Information|Bacnet device not found.| +|skip|security.discover.firmware|Security|Information|Could not retrieve a firmware version with nmap. Check bacnet port.| |pass|security.nmap.http|Other|Other|No running http servers have been found.| -|pass|security.nmap.ports|Other|Other|Only allowed ports found open.| -|skip|security.password.http|Other|Other|Port 80 not open on target device.| -|skip|security.password.https|Other|Other|Port 443 not open on target device.| -|skip|security.password.ssh|Other|Other|Port 22 not open on target device.| -|skip|security.password.telnet|Other|Other|Port 23 not open on target device.| -|gone|security.ports.nmap|Security|Recommended|| +|pass|security.nmap.ports|Security|Required Pass|Only allowed ports found open.| +|skip|security.password.http|Security|Required Pass|Port 80 not open on target device.| +|skip|security.password.https|Security|Required Pass|Port 443 not open on target device.| +|skip|security.password.ssh|Security|Required Pass|Port 22 not open on target device.| +|skip|security.password.telnet|Security|Required Pass|Port 23 not open on target device.| +|gone|security.ports.nmap|Security|Recommended Pass|| |skip|security.tls.v1_2_client|Other|Other|No client initiated TLS communication detected| |skip|security.tls.v1_2_server|Other|Other|IOException unable to connect to server.| |skip|security.tls.v1_3_client|Other|Other|No client initiated TLS communication detected| diff --git a/resources/setups/qualification/system_module_config.json b/resources/setups/qualification/system_module_config.json index 8698ded88c..c7e941e572 100644 --- a/resources/setups/qualification/system_module_config.json +++ b/resources/setups/qualification/system_module_config.json @@ -108,7 +108,7 @@ "connection.network.communication_type": { "category": "Communication", "required": "info", - "expected": "information" + "expected": "Information" }, "connection.network.communication_min_send": { "category": "Communication", diff --git a/resources/test_site/module_config.json b/resources/test_site/module_config.json index 05f4e85e48..4ecbbd036f 100644 --- a/resources/test_site/module_config.json +++ b/resources/test_site/module_config.json @@ -28,8 +28,8 @@ }, "report": { "results": [ "pass", "fail", "skip" ], - "categories": [ "Security" ], - "expected": [ "Required", "Recommended" ] + "categories": [ "Connection", "Security", "Network Time", "TLS", "Protocol", "PoE", "BOS"], + "expected": [ "Required Pass", "Required Pass for PoE Devices", "Required Pass for BACnet Devices", "Recommended Pass", "Information" ] }, "tests": { "unknown.fake.llama": { @@ -38,22 +38,143 @@ "unknown.fake.monkey": { "required": "pass" }, - "connection.base.target_ping": { - "category": "Connectivity", - "expected": "Required" - }, "security.ports.nmap": { "required": "pass", "category": "Security", - "expected": "Recommended" + "expected": "Recommended Pass" }, "manual.test.name": { "required": "pass", "category": "Security", - "expected": "Recommended", + "expected": "Recommended Pass", "type": "manual", "outcome" : "pass", "summary" : "for testing" + }, + "connection.switch.port_link": { + "category": "Connection", + "required": "pass", + "expected": "Required Pass" + }, + "connection.switch.port_speed": { + "category": "Connection", + "required": "pass", + "expected": "Required Pass" + }, + "connection.switch.port_duplex": { + "category": "Connection", + "required": "pass", + "expected": "Required Pass" + }, + "base.switch.ping": { + "category": "Connection", + "required": "pass", + "expected": "Required Pass" + }, + "connection.base.target_ping": { + "category": "Connection", + "required": "pass", + "expected": "Required Pass" + }, + "connection.ipaddr.private_address": { + "category": "Connection", + "required": "pass", + "expected": "Required Pass" + }, + "connection.ipaddr.dhcp_disconnect": { + "category": "Connection", + "required": "pass", + "expected": "Required Pass" + }, + "connection.network.dhcp_long": { + "category": "Connection", + "required": "pass", + "expected": "Required Pass" + }, + "connection.network.mac_oui": { + "category": "Connection", + "required": "pass", + "expected": "Required Pass" + }, + "ntp.network.ntp_support": { + "category": "Network Time", + "required": "pass", + "expected": "Required Pass" + }, + "ntp.network.ntp_update": { + "category": "Network Time", + "required": "pass", + "expected": "Required Pass" + }, + "connection.network.communication_type": { + "category": "Communication", + "required": "info", + "expected": "Information" + }, + "connection.network.communication_min_send": { + "category": "Communication", + "required": "pass", + "expected": "Required Pass" + }, + "security.nmap.ports": { + "category": "Security", + "required": "pass", + "expected": "Required Pass" + }, + "security.password.http": { + "category": "Security", + "required": "pass", + "expected": "Required Pass" + }, + "security.password.https": { + "category": "Security", + "required": "pass", + "expected": "Required Pass" + }, + "security.password.ssh": { + "category": "Security", + "required": "pass", + "expected": "Required Pass" + }, + "security.password.telnet": { + "category": "Security", + "required": "pass", + "expected": "Required Pass" + }, + "protocol.bacext.pic": { + "category": "Protocol", + "required": "pass", + "expected": "Required Pass for BACnet Devices" + }, + "protocol.bacext.version": { + "category": "Protocol", + "required": "info", + "expected": "Information" + }, + "poe.switch.power": { + "category": "PoE", + "required": "pass", + "expected": "Required Pass for PoE Devices" + }, + "poe.switch.negotiation": { + "category": "PoE", + "required": "pass", + "expected": "Required Pass for PoE Devices" + }, + "poe.switch.support": { + "category": "PoE", + "required": "info", + "expected": "Information" + }, + "cloud.udmi.pointset": { + "category": "BOS", + "required": "pass", + "expected": "Recommended Pass" + }, + "security.discover.firmware": { + "category": "Security", + "required": "info", + "expected": "Information" } } } diff --git a/testing/test_base.out b/testing/test_base.out index c54fc2d8e7..7cb545df38 100644 --- a/testing/test_base.out +++ b/testing/test_base.out @@ -20,9 +20,10 @@ By default would be in local/site/ rather than resources/test_site/. Overall device result PASS -|Category|Result| -|---|---| -|Other|n/a| +|Category|Total Tests|Result|Other| +|---|---|---|---| +|Other|0|N/A|0/0/0| +Syntax: Pass / Fail / Skip |Expectation|pass|skip| |---|---|---| From 21dcbcbf5171e07689aafe88f183cbd93564ee37 Mon Sep 17 00:00:00 2001 From: Francesco Anselmo Date: Sat, 12 Dec 2020 18:53:36 +0000 Subject: [PATCH 201/212] Setups update (#706) * updated qualification setup files and device_type folder --- .../type_config.json | 152 +++++ .../deltacontrols_o3-din-cpu/aux/pics.csv | 0 .../deltacontrols_o3-din-cpu/type_config.json | 25 +- .../device_type_template/type_config.json | 9 +- .../distech_ecy-s1000/aux/pics.csv | 0 .../distech_ecy-s1000/type_config.json | 27 +- .../device_types/easyio_fw-14/aux/pics.csv | 0 .../easyio_fw-14/type_config.json | 47 +- .../tridium_jace-8000/type_config.json | 167 ++++++ .../setups/qualification/device_config.json | 39 ++ .../qualification/device_module_config.json | 548 ------------------ .../manual_tests_module_config.json | 44 -- .../minimal_device_module_config.json | 13 - .../setups/qualification/report_template.md | 7 +- ..._module_config.json => system_config.json} | 191 +++--- ..._module_config.json => device_config.json} | 0 ..._module_config.json => system_config.json} | 0 17 files changed, 555 insertions(+), 714 deletions(-) create mode 100644 library/device_types/artisticlicence_lightjuice-cv4/type_config.json rename {resources => library}/device_types/deltacontrols_o3-din-cpu/aux/pics.csv (100%) rename resources/device_types/deltacontrols_o3-din-cpu/module_config.json => library/device_types/deltacontrols_o3-din-cpu/type_config.json (93%) rename resources/setups/qualification/device_type_module_config.json => library/device_types/device_type_template/type_config.json (99%) rename {resources => library}/device_types/distech_ecy-s1000/aux/pics.csv (100%) rename resources/device_types/distech_ecy-s1000/module_config.json => library/device_types/distech_ecy-s1000/type_config.json (88%) rename {resources => library}/device_types/easyio_fw-14/aux/pics.csv (100%) rename resources/device_types/easyio_fw-14/module_config.json => library/device_types/easyio_fw-14/type_config.json (73%) create mode 100644 library/device_types/tridium_jace-8000/type_config.json create mode 100644 resources/setups/qualification/device_config.json delete mode 100644 resources/setups/qualification/device_module_config.json delete mode 100644 resources/setups/qualification/manual_tests_module_config.json delete mode 100644 resources/setups/qualification/minimal_device_module_config.json rename resources/setups/qualification/{system_module_config.json => system_config.json} (65%) rename resources/setups/remediation/{device_module_config.json => device_config.json} (100%) rename resources/setups/remediation/{system_module_config.json => system_config.json} (100%) diff --git a/library/device_types/artisticlicence_lightjuice-cv4/type_config.json b/library/device_types/artisticlicence_lightjuice-cv4/type_config.json new file mode 100644 index 0000000000..e0b9829497 --- /dev/null +++ b/library/device_types/artisticlicence_lightjuice-cv4/type_config.json @@ -0,0 +1,152 @@ +{ + "device_datasheets_url": "https://www.artisticlicence.com/WebSiteMaster/Datasheets/lightJuice%20CV4%20datasheet.pdf", + "device_description": "lightJuice CV4 is the first product in a new range of technology based on the latest Power over Ethernet (PoE++) standard. The network cable carries both power and lighting control data, so AC mains wiring is eliminated. lightJuice offers cost savings and uses human-safe DC voltage suitable for LEDs. lightJuice CV4 is a 4-channel constant voltage dimmer configured for common anode drive. It offers high resolution (up to 12-bit) PWM dimming and can drive loads up to 60W in total at 24V. The product supports both Art-Net and sACN, with data and power connected via an Ethercon RJ45. An auxiliary DC input offers an alternative mode of operation if PoE++ is not available.", + "device_image": "https://artisticlicence.com/wp-content/uploads/2017/06/lightJuice-CV4.jpg", + "device_info": { + "make": "Artistic Licence", + "model": "lightJuice CV4", + "category": "Artnet LED constant voltage driver" + }, + "device_manuals_url": "https://www.artisticlicence.com/WebSiteMaster/User%20Guides/lightjuice%20cv4%20user%20guide.pdf", + "modules": { + "bacext": { + "enabled": false + }, + "bacnet": { + "enabled": false + }, + "discover": { + "enabled": true + }, + "ipaddr": { + "enabled": true + }, + "mudgee": { + "enabled": false + }, + "network": { + "enabled": true + }, + "nmap": { + "enabled": true + }, + "password": { + "enabled": true + }, + "switch": { + "enabled": true, + "poe": { + "enabled" : true + } + }, + "tls": { + "enabled": true + }, + "ssh": { + "enabled": true + }, + "udmi": { + "enabled": false + } + }, + "servers": { + "tcp": { + "ports": { + "20": { + "allowed": false, + "description": "File Transfer Protocol (FTP) Server Data Transfer", + "reason": "" + }, + "21": { + "allowed": false, + "description": "File Transfer Protocol (FTP) Server Data Transfer", + "reason": "" + }, + "22": { + "allowed": true, + "description": "Secure Shell (SSH) server", + "reason": "" + }, + "23": { + "allowed": false, + "description": "Telnet Server", + "reason": "" + }, + "25": { + "allowed": false, + "description": "Simple Mail Transfer Protocol (SMTP) Server", + "reason": "" + }, + "80": { + "allowed": false, + "description": "Administrative Insecure Web-Server", + "reason": "" + }, + "110": { + "allowed": false, + "description": "Post Office Protocol v3 (POP3) Server", + "reason": "" + }, + "143": { + "allowed": false, + "description": "Internet Message Access Protocol (IMAP) Server", + "reason": "" + }, + "161": { + "allowed": false, + "description": "Simple Network Management Protocol (SNMP)", + "reason": "" + }, + "162": { + "allowed": false, + "description": "Simple Network Management Protocol (SNMP) Trap", + "reason": "" + }, + "443": { + "allowed": true, + "description": "Administrative Secure Web-Server", + "reason": "" + }, + "5800": { + "allowed": false, + "description": "Virtual Network Computing (VNC) Remote Frame Buffer Protocol Over HTTP", + "reason": "" + }, + "5500": { + "allowed": false, + "description": "Virtual Network Computing (VNC) Remote Frame Buffer Protocol", + "reason": "" + } + } + }, + "udp": { + "ports": { + "69": { + "allowed": false, + "description": "Trivial File Transfer Protocol (TFTP) Server", + "reason": "" + }, + "123": { + "allowed": true, + "description": "Network Time Protocol (NTP) Server", + "reason": "" + }, + "161": { + "allowed": false, + "description": "Simple Network Management Protocol (SNMP)", + "reason": "" + }, + "162": { + "allowed": false, + "description": "Simple Network Management Protocol (SNMP) Trap", + "reason": "" + }, + "47808": { + "allowed": false, + "description": "BACnet protocol", + "reason": "" + } + } + } + } +} diff --git a/resources/device_types/deltacontrols_o3-din-cpu/aux/pics.csv b/library/device_types/deltacontrols_o3-din-cpu/aux/pics.csv similarity index 100% rename from resources/device_types/deltacontrols_o3-din-cpu/aux/pics.csv rename to library/device_types/deltacontrols_o3-din-cpu/aux/pics.csv diff --git a/resources/device_types/deltacontrols_o3-din-cpu/module_config.json b/library/device_types/deltacontrols_o3-din-cpu/type_config.json similarity index 93% rename from resources/device_types/deltacontrols_o3-din-cpu/module_config.json rename to library/device_types/deltacontrols_o3-din-cpu/type_config.json index 6859207787..e02daded32 100644 --- a/resources/device_types/deltacontrols_o3-din-cpu/module_config.json +++ b/library/device_types/deltacontrols_o3-din-cpu/type_config.json @@ -5,8 +5,10 @@ "device_info": { "make": "Delta Controls Inc.", "model": "O3-DIN-CPU", - "type": "BACnet controller" + "category": "BACnet controller" }, + "default_username": "DELTA", + "default_password": "LOGIN", "device_manuals_url": "https://deltacontrols.com/wp-content/uploads/Delta-Controls-Product-Catalog-2019-DIGITAL.pdf", "modules": { "bacext": { @@ -15,12 +17,24 @@ "bacnet": { "enabled": true }, + "discover": { + "enabled": true + }, + "ipaddr": { + "enabled": true + }, "mudgee": { + "enabled": false + }, + "network": { "enabled": true }, "nmap": { "enabled": true }, + "password": { + "enabled": true + }, "switch": { "enabled": true, "poe": { @@ -30,11 +44,11 @@ "tls": { "enabled": true }, - "discover": { + "ssh": { "enabled": true }, - "passwords": { - "enabled": true + "udmi": { + "enabled": false } }, "servers": { @@ -136,8 +150,5 @@ } } } - }, - "process": { - "attempt_number": 1 } } diff --git a/resources/setups/qualification/device_type_module_config.json b/library/device_types/device_type_template/type_config.json similarity index 99% rename from resources/setups/qualification/device_type_module_config.json rename to library/device_types/device_type_template/type_config.json index 0401a128b7..818aa5180c 100644 --- a/resources/setups/qualification/device_type_module_config.json +++ b/library/device_types/device_type_template/type_config.json @@ -5,7 +5,7 @@ "device_info": { "make": "*** Make ***", "model": "*** Model ***", - "type": "*** Type ***" + "category": "*** Category ***" }, "device_manuals_url": "*** Device Manuals URL ***", "modules": { @@ -15,9 +15,6 @@ "bacnet": { "enabled": true }, - "brute": { - "enabled": false - }, "discover": { "enabled": true }, @@ -42,11 +39,11 @@ "tls": { "enabled": true }, - "passwords": { + "password": { "enabled": true }, "udmi": { - "enabled": false + "enabled": true } }, "servers": { diff --git a/resources/device_types/distech_ecy-s1000/aux/pics.csv b/library/device_types/distech_ecy-s1000/aux/pics.csv similarity index 100% rename from resources/device_types/distech_ecy-s1000/aux/pics.csv rename to library/device_types/distech_ecy-s1000/aux/pics.csv diff --git a/resources/device_types/distech_ecy-s1000/module_config.json b/library/device_types/distech_ecy-s1000/type_config.json similarity index 88% rename from resources/device_types/distech_ecy-s1000/module_config.json rename to library/device_types/distech_ecy-s1000/type_config.json index 09e9fd37b9..a9c1570965 100644 --- a/resources/device_types/distech_ecy-s1000/module_config.json +++ b/library/device_types/distech_ecy-s1000/type_config.json @@ -1,12 +1,14 @@ { "device_datasheets_url": "https://docs.distech-controls.com/bundle/ECY-S1000_SP/resource/ECY-S1000_SP.pdf", "device_description": "The ECY-S1000 is a HVAC controller that supports a range of communication protocols such as BACnetIP, BACnet MS/TP, Modbus RTU, Modbus TCP, and M-Bus. With the RESTful API, data can be accessed from different applications, such as energy dashboards, analytics tools, and mobile applications.", - "device_image": "https://img.acuitybrands.com/public-assets/catalog/947830/ECY-RS485_FRONT_30nov2015.png?abl_version=01%2F01%2F0001+00:00:00", + "device_image": "https://shop.controlco.com/SSP%20Applications/NetSuite%20Inc.%20-%20SCA%20Aconcagua/Development/img/Products/CDIYS100000_00.png?resizeid=3&resizeh=205&resizew=308", "device_info": { "make": "Distech Controls, Inc.", "model": "ECY-S1000", - "type": "BACnet controller" + "category": "BACnet controller" }, + "default_username": "admin", + "default_password": "admin", "device_manuals_url": "https://docs.distech-controls.com/bundle/ECY-CSC_IG/resource/ECY-CSC_IG.pdf", "modules": { "bacext": { @@ -15,12 +17,24 @@ "bacnet": { "enabled": true }, + "discover": { + "enabled": true + }, + "ipaddr": { + "enabled": true + }, "mudgee": { + "enabled": false + }, + "network": { "enabled": true }, "nmap": { "enabled": true }, + "password": { + "enabled": true + }, "switch": { "enabled": true, "poe": { @@ -30,11 +44,11 @@ "tls": { "enabled": true }, - "discover": { + "ssh": { "enabled": true }, - "passwords": { - "enabled": true + "udmi": { + "enabled": false } }, "servers": { @@ -136,8 +150,5 @@ } } } - }, - "process": { - "attempt_number": 1 } } diff --git a/resources/device_types/easyio_fw-14/aux/pics.csv b/library/device_types/easyio_fw-14/aux/pics.csv similarity index 100% rename from resources/device_types/easyio_fw-14/aux/pics.csv rename to library/device_types/easyio_fw-14/aux/pics.csv diff --git a/resources/device_types/easyio_fw-14/module_config.json b/library/device_types/easyio_fw-14/type_config.json similarity index 73% rename from resources/device_types/easyio_fw-14/module_config.json rename to library/device_types/easyio_fw-14/type_config.json index cd01cd1a0f..4c863c67c7 100644 --- a/resources/device_types/easyio_fw-14/module_config.json +++ b/library/device_types/easyio_fw-14/type_config.json @@ -5,9 +5,52 @@ "device_info": { "make": "EasyIO", "model": "FW-14", - "type": "BACnet controller" + "category": "BACnet controller" }, + "default_username": "admin", + "default_password": "hellocpt", "device_manuals_url": "https://techcommft.blob.core.windows.net/fluidtopics/integrations/docs/easyio_fw_installation_v2.0.pdf", + "modules": { + "bacext": { + "enabled": true + }, + "bacnet": { + "enabled": true + }, + "discover": { + "enabled": true + }, + "ipaddr": { + "enabled": true + }, + "mudgee": { + "enabled": false + }, + "network": { + "enabled": true + }, + "nmap": { + "enabled": true + }, + "password": { + "enabled": true + }, + "switch": { + "enabled": true, + "poe": { + "enabled" : false + } + }, + "tls": { + "enabled": true + }, + "ssh": { + "enabled": true + }, + "udmi": { + "enabled": false + } + }, "servers": { "tcp": { "ports": { @@ -62,5 +105,5 @@ } } } - }, + } } diff --git a/library/device_types/tridium_jace-8000/type_config.json b/library/device_types/tridium_jace-8000/type_config.json new file mode 100644 index 0000000000..d1beccc1a6 --- /dev/null +++ b/library/device_types/tridium_jace-8000/type_config.json @@ -0,0 +1,167 @@ +{ + "device_datasheets_url": "https://www.tridium.com/~/media/tridium/enterprisesecurity/documents/jace%208000%20ds%20new%20tridium.ashx?la=es-mx", + "device_description": "The JACE 8000 is a compact, embedded IoT (Internet of Things) controller and server platform for connecting multiple and diverse devices and sub-systems. With internet connectivity and web-serving capability, the JACE 8000 controller provides integrated control, supervision, data logging, alarming, scheduling and network management. It streams data and rich graphical displays to a standard web browser via an Ethernet or wireless LAN, or remotely over the internet. Niagara Enterprise Security is a Niagara AX-based application that runs on the JACE 8000. Niagara Analytics 2.0 is a data analytics extension to the Niagara Framework® available on JACE 8000 controllers.", + "device_image": "https://abs-controls.com/wp-content/uploads/2019/07/JACE_8000-316x186.fw_.png", + "device_info": { + "make": "Tridium", + "model": "JACE 8000", + "category": "IoT controller" + }, + "default_username": "tridium", + "default_password": "controls", + "device_manuals_url": "https://community.exchange.se.com/krefy84679/attachments/krefy84679/knowledge-base_public/9611/1/docJace8000Startup.pdf", + "modules": { + "bacext": { + "enabled": false + }, + "bacnet": { + "enabled": false + }, + "discover": { + "enabled": true + }, + "ipaddr": { + "enabled": true + }, + "mudgee": { + "enabled": false + }, + "network": { + "enabled": true + }, + "nmap": { + "enabled": true + }, + "password": { + "enabled": true + }, + "switch": { + "enabled": true, + "poe": { + "enabled" : false + } + }, + "tls": { + "enabled": true + }, + "ssh": { + "enabled": true + }, + "udmi": { + "enabled": false + } + }, + "servers": { + "tcp": { + "ports": { + "20": { + "allowed": false, + "description": "File Transfer Protocol (FTP) Server Data Transfer", + "reason": "" + }, + "21": { + "allowed": false, + "description": "File Transfer Protocol (FTP) Server Data Transfer", + "reason": "" + }, + "22": { + "allowed": true, + "description": "Secure Shell (SSH) server", + "reason": "" + }, + "23": { + "allowed": false, + "description": "Telnet Server", + "reason": "" + }, + "25": { + "allowed": false, + "description": "Simple Mail Transfer Protocol (SMTP) Server", + "reason": "" + }, + "80": { + "allowed": false, + "description": "Administrative Insecure Web-Server", + "reason": "" + }, + "110": { + "allowed": false, + "description": "Post Office Protocol v3 (POP3) Server", + "reason": "" + }, + "143": { + "allowed": false, + "description": "Internet Message Access Protocol (IMAP) Server", + "reason": "" + }, + "161": { + "allowed": false, + "description": "Simple Network Management Protocol (SNMP)", + "reason": "" + }, + "162": { + "allowed": false, + "description": "Simple Network Management Protocol (SNMP) Trap", + "reason": "" + }, + "443": { + "allowed": true, + "description": "Administrative Secure Web-Server", + "reason": "" + }, + "1911": { + "allowed": false, + "description": "Unencrypted FOX", + "reason": "" + }, + "4911": { + "allowed": true, + "description": "Secure FOX", + "reason": "" + }, + "5800": { + "allowed": false, + "description": "Virtual Network Computing (VNC) Remote Frame Buffer Protocol Over HTTP", + "reason": "" + }, + "5500": { + "allowed": false, + "description": "Virtual Network Computing (VNC) Remote Frame Buffer Protocol", + "reason": "" + } + } + }, + "udp": { + "ports": { + "69": { + "allowed": false, + "description": "Trivial File Transfer Protocol (TFTP) Server", + "reason": "" + }, + "123": { + "allowed": true, + "description": "Network Time Protocol (NTP) Server", + "reason": "" + }, + "161": { + "allowed": false, + "description": "Simple Network Management Protocol (SNMP)", + "reason": "" + }, + "162": { + "allowed": false, + "description": "Simple Network Management Protocol (SNMP) Trap", + "reason": "" + }, + "47808": { + "allowed": false, + "description": "BACnet protocol", + "reason": "" + } + } + } + }, + "process": { + "attempt_number": 1 + } +} diff --git a/resources/setups/qualification/device_config.json b/resources/setups/qualification/device_config.json new file mode 100644 index 0000000000..e9a4386390 --- /dev/null +++ b/resources/setups/qualification/device_config.json @@ -0,0 +1,39 @@ +{ + "device_info": { + "guid": "*** GUID ***", + "hostname": "*** Network Hostname ***", + "name": "*** Name ***", + "serial": "*** Serial ***", + "firmware_version": "*** Firmware Version ***" + }, + "device_type": "*** Device Type ***", + "process": { + "attempt_number": 1 + }, + "tests": { + "connection.manual.comms_down": { + "category": "Connection", + "required": "pass", + "expected": "Required Pass", + "description": "Remove the network connection and confirm the device is still operational.", + "enabled": true, + "type": "manual", + "result": "required", + "outcome": "INPUT OUTCOME OF TEST HERE (pass/fail/skip)", + "summary" : "INPUT SUMMARY OF TEST HERE", + "test_log" : "INPUT LOG OF TEST HERE" + }, + "connection.manual.sec_eth_port": { + "category": "Connection", + "required": "pass", + "expected": "Required Pass", + "description": "Connect the second port to the network switch. Check that no connection light is available and the port has been disabled.", + "enabled": true, + "type": "manual", + "result": "required", + "outcome": "INPUT OUTCOME OF TEST HERE (pass/fail/skip)", + "summary" : "INPUT SUMMARY OF TEST HERE", + "test_log" : "INPUT LOG OF TEST HERE" + } + } +} \ No newline at end of file diff --git a/resources/setups/qualification/device_module_config.json b/resources/setups/qualification/device_module_config.json deleted file mode 100644 index 131348b856..0000000000 --- a/resources/setups/qualification/device_module_config.json +++ /dev/null @@ -1,548 +0,0 @@ -{ - "device_datasheets_url": "*** Device Datasheets URL ***", - "device_description": "*** Device Description ***", - "device_image": "*** Device Image URL ***", - "device_info": { - "guid": "*** GUID ***", - "hostname": "*** Network Hostname ***", - "make": "*** Make ***", - "model": "*** Model ***", - "name": "*** Name ***", - "serial": "*** Serial ***", - "type": "*** Type ***", - "firmware_version": "*** Firmware Version ***" - }, - "device_manuals_url": "*** Device Manuals URL ***", - "device_type": "*** Device Type ***", - "modules": { - "bacext": { - "enabled": true - }, - "bacnet": { - "enabled": true - }, - "brute": { - "enabled": false - }, - "discover": { - "enabled": true - }, - "ipaddr": { - "timeout_sec": 120 - }, - "mudgee": { - "enabled": true - }, - "nmap": { - "enabled": true - }, - "switch": { - "enabled": true, - "poe": { - "enabled" : true - } - }, - "tls": { - "enabled": true - }, - "passwords": { - "enabled": true - }, - "udmi": { - "enabled": false - } - }, - "servers": { - "tcp": { - "ports": { - "20": { - "allowed": false, - "description": "File Transfer Protocol (FTP) Server Data Transfer", - "reason": "" - }, - "21": { - "allowed": false, - "description": "File Transfer Protocol (FTP) Server Data Transfer", - "reason": "" - }, - "22": { - "allowed": true, - "description": "Secure Shell (SSH) server", - "reason": "" - }, - "23": { - "allowed": false, - "description": "Telnet Server", - "reason": "" - }, - "25": { - "allowed": false, - "description": "Simple Mail Transfer Protocol (SMTP) Server", - "reason": "" - }, - "37": { - "allowed": false, - "description": "Deprecated Time Protocol", - "reason": "" - }, - "53": { - "allowed": true, - "description": "DNS", - "reason": "" - }, - "80": { - "allowed": false, - "description": "Administrative Insecure Web-Server", - "reason": "" - }, - "110": { - "allowed": false, - "description": "Post Office Protocol v3 (POP3) Server", - "reason": "" - }, - "123": { - "allowed": true, - "description": "Network Time Protocol", - "reason": "" - }, - "135": { - "allowed": false, - "description": "OPC Data Access", - "reason": "" - }, - "143": { - "allowed": false, - "description": "Internet Message Access Protocol (IMAP) Server", - "reason": "" - }, - "161": { - "allowed": false, - "description": "Simple Network Management Protocol (SNMP)", - "reason": "" - }, - "162": { - "allowed": false, - "description": "Simple Network Management Protocol (SNMP) Trap", - "reason": "" - }, - "443": { - "allowed": true, - "description": "Secure Web-Server", - "reason": "" - }, - "465": { - "allowed": false, - "description": "SMTPS", - "reason": "" - }, - "587": { - "allowed": false, - "description": "SMTPS", - "reason": "" - }, - "502": { - "allowed": false, - "description": "Unencrypted Modbus TCP", - "reason": "" - }, - "853": { - "allowed": true, - "description": "Secure DNS", - "reason": "" - }, - "1883": { - "allowed": false, - "description": "Unencrypted MQTT", - "reason": "" - }, - "1911": { - "allowed": false, - "description": "Unencrypted FOX", - "reason": "" - }, - "2221": { - "allowed": false, - "description": "Secure EtherNet/IP", - "reason": "" - }, - "2222": { - "allowed": false, - "description": "EtherNet/IP I/O", - "reason": "" - }, - "2455": { - "allowed": false, - "description": "WAGO-IO-SYSTEM", - "reason": "" - }, - "2540": { - "allowed": false, - "description": "LonWorks", - "reason": "" - }, - "2541": { - "allowed": false, - "description": "LonWorks 2", - "reason": "" - }, - "3011": { - "allowed": false, - "description": "Unencrypted Tridium Platform Protocol", - "reason": "" - }, - "3639": { - "allowed": false, - "description": "XAP Extensible Automation Protocol", - "reason": "" - }, - "3865": { - "allowed": false, - "description": "XPL Automation Protocol", - "reason": "" - }, - "4123": { - "allowed": false, - "description": "Z-Wave Protocol", - "reason": "" - }, - "4843": { - "allowed": true, - "description": "Secure OPC UA Protocol", - "reason": "" - }, - "4911": { - "allowed": false, - "description": "Secure FOX", - "reason": "" - }, - "5011": { - "allowed": false, - "description": "Secure Tridium Platform Protocol", - "reason": "" - }, - "5500": { - "allowed": false, - "description": "Virtual Network Computing (VNC) Remote Frame Buffer Protocol", - "reason": "" - }, - "5671": { - "allowed": false, - "description": "Secure AMQP", - "reason": "" - }, - "5672": { - "allowed": false, - "description": "Unencrypted AMQP", - "reason": "" - }, - "5683": { - "allowed": false, - "description": "Unencrypted CoAP", - "reason": "" - }, - "5684": { - "allowed": false, - "description": "Secure CoAP", - "reason": "" - }, - "5800": { - "allowed": false, - "description": "Virtual Network Computing (VNC) Remote Frame Buffer Protocol Over HTTP", - "reason": "" - }, - "6454": { - "allowed": false, - "description": "ArtNet", - "reason": "" - }, - "6626": { - "allowed": false, - "description": "WAGO-SERVICE", - "reason": "" - }, - "8883": { - "allowed": true, - "description": "Secure MQTT", - "reason": "" - }, - "9000": { - "allowed": false, - "description": "oBIX", - "reason": "" - }, - "9598": { - "allowed": false, - "description": "VSCP ", - "reason": "" - }, - "17755": { - "allowed": false, - "description": "ZigBee IP", - "reason": "" - }, - "17756": { - "allowed": false, - "description": "Secure ZigBee IP", - "reason": "" - }, - "34962": { - "allowed": false, - "description": "PROFInet RT Unicast", - "reason": "" - }, - "34963": { - "allowed": false, - "description": "PROFInet RT Multicast", - "reason": "" - }, - "34964": { - "allowed": false, - "description": "PROFInet Context Manager", - "reason": "" - }, - "34980": { - "allowed": false, - "description": "EtherCAT", - "reason": "" - }, - "41794": { - "allowed": false, - "description": "Crestron Control Port", - "reason": "" - }, - "41795": { - "allowed": false, - "description": "Crestron Terminal Port", - "reason": "" - }, - "41796": { - "allowed": false, - "description": "Crestron Secure Control Port", - "reason": "" - }, - "41797": { - "allowed": false, - "description": "Crestron Secure Terminal Port", - "reason": "" - }, - "44818": { - "allowed": false, - "description": "EtherNet/IP messaging", - "reason": "" - }, - "47806": { - "allowed": false, - "description": "Automated Logic remote access", - "reason": "" - }, - "48400": { - "allowed": false, - "description": "OPC Unified Architecture", - "reason": "" - }, - "48401": { - "allowed": false, - "description": "OPC Unified Architecture", - "reason": "" - } - } - }, - "udp": { - "ports": { - "69": { - "allowed": false, - "description": "Trivial File Transfer Protocol (TFTP) Server", - "reason": "" - }, - "123": { - "allowed": true, - "description": "Network Time Protocol (NTP) Server", - "reason": "" - }, - "135": { - "allowed": false, - "description": "OPC Data Access", - "reason": "" - }, - "161": { - "allowed": false, - "description": "Simple Network Management Protocol (SNMP)", - "reason": "" - }, - "162": { - "allowed": false, - "description": "Simple Network Management Protocol (SNMP) Trap", - "reason": "" - }, - "1876": { - "allowed": false, - "description": "EasyIO/Sedona SOX", - "reason": "" - }, - "2221": { - "allowed": false, - "description": "Secure EtherNet/IP", - "reason": "" - }, - "2222": { - "allowed": false, - "description": "EtherNet/IP I/O", - "reason": "" - }, - "2455": { - "allowed": false, - "description": "WAGO-IO-SYSTEM", - "reason": "" - }, - "2540": { - "allowed": false, - "description": "LonWorks", - "reason": "" - }, - "2541": { - "allowed": false, - "description": "LonWorks 2", - "reason": "" - }, - "3639": { - "allowed": false, - "description": "XAP Extensible Automation Protocol", - "reason": "" - }, - "3671": { - "allowed": false, - "description": "KNX ", - "reason": "" - }, - "3865": { - "allowed": false, - "description": "XPL Automation Protocol", - "reason": "" - }, - "4123": { - "allowed": false, - "description": "Z-Wave Protocol", - "reason": "" - }, - "4843": { - "allowed": true, - "description": "Secure OPC UA Protocol", - "reason": "" - }, - "5671": { - "allowed": false, - "description": "Secure AMQP", - "reason": "" - }, - "5672": { - "allowed": false, - "description": "Unencrypted AMQP", - "reason": "" - }, - "5683": { - "allowed": false, - "description": "Unencrypted CoAP", - "reason": "" - }, - "5684": { - "allowed": false, - "description": "Secure CoAP", - "reason": "" - }, - "6454": { - "allowed": false, - "description": "ArtNet", - "reason": "" - }, - "6626": { - "allowed": false, - "description": "WAGO-SERVICE", - "reason": "" - }, - "9598": { - "allowed": false, - "description": "VSCP ", - "reason": "" - }, - "17755": { - "allowed": false, - "description": "ZigBee IP", - "reason": "" - }, - "17756": { - "allowed": false, - "description": "Secure ZigBee IP", - "reason": "" - }, - "34962": { - "allowed": false, - "description": "PROFInet RT Unicast", - "reason": "" - }, - "34963": { - "allowed": false, - "description": "PROFInet RT Multicast", - "reason": "" - }, - "34964": { - "allowed": false, - "description": "PROFInet Context Manager", - "reason": "" - }, - "34980": { - "allowed": false, - "description": "EtherCAT", - "reason": "" - }, - "41794": { - "allowed": false, - "description": "Crestron Control Port", - "reason": "" - }, - "41795": { - "allowed": false, - "description": "Crestron Terminal Port", - "reason": "" - }, - "41796": { - "allowed": false, - "description": "Crestron Secure Control Port", - "reason": "" - }, - "41797": { - "allowed": false, - "description": "Crestron Secure Terminal Port", - "reason": "" - }, - "44818": { - "allowed": false, - "description": "EtherNet/IP messaging", - "reason": "" - }, - "47806": { - "allowed": false, - "description": "Automated Logic remote access", - "reason": "" - }, - "47808": { - "allowed": false, - "description": "BACnet", - "reason": "" - }, - "47809": { - "allowed": false, - "description": "BACnet", - "reason": "" - }, - "57612": { - "allowed": false, - "description": "Trend Control Systems Protocol", - "reason": "" - } - } - } - }, - "process": { - "attempt_number": 1 - } -} diff --git a/resources/setups/qualification/manual_tests_module_config.json b/resources/setups/qualification/manual_tests_module_config.json deleted file mode 100644 index 57c682a89b..0000000000 --- a/resources/setups/qualification/manual_tests_module_config.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "tests": { - "security.manual.java_interface": { - "outcome": "", - "summary": "", - "test_log": "" - }, - "security.manual.flash_interface": { - "outcome": "", - "summary": "", - "test_log": "" - }, - "security.manual.flash_functionality": { - "outcome": "", - "summary": "", - "test_log": "" - }, - "security.manual.http": { - "outcome": "", - "summary": "", - "test_log": "" - }, - "security.manual.web_passwords": { - "outcome": "", - "summary": "", - "test_log": "" - }, - "connection.manual.comms_down": { - "outcome": "", - "summary": "", - "test_log": "" - }, - "connection.manual.sec_eth_port": { - "outcome": "", - "summary": "", - "test_log": "" - }, - "connection.manual.sec_eth_port_no_ip": { - "outcome": "", - "summary": "", - "test_log": "" - } - } -} diff --git a/resources/setups/qualification/minimal_device_module_config.json b/resources/setups/qualification/minimal_device_module_config.json deleted file mode 100644 index fda18b0c6d..0000000000 --- a/resources/setups/qualification/minimal_device_module_config.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "device_info": { - "guid": "*** GUID ***", - "hostname": "*** Network Hostname ***", - "name": "*** Name ***", - "serial": "*** Serial ***", - "firmware_version": "*** Firmware Version ***" - }, - "device_type": "*** Device Type ***", - "process": { - "attempt_number": 1 - } -} diff --git a/resources/setups/qualification/report_template.md b/resources/setups/qualification/report_template.md index 6ffb6a491a..5644a882b6 100644 --- a/resources/setups/qualification/report_template.md +++ b/resources/setups/qualification/report_template.md @@ -6,8 +6,8 @@ ## Test Roles -Role | Name | Status --------- | ---------------------- | ------ +Role | Name | +-------- | ---------------------- | Operator | {{ process.operator }} | Approver | {{ process.approver }} | @@ -28,7 +28,8 @@ Name | {{ device_info.name }} GUID | {{ device_info.guid }} MAC address | {{ run_info.mac_addr }} Hostname | {{ device_info.hostname }} -Type | {{ device_info.type }} +Type | {{ device_type }} +Category | {{ device_info.category }} Make | {{ device_info.make }} Model | {{ device_info.model }} Serial Number | {{ device_info.serial }} diff --git a/resources/setups/qualification/system_module_config.json b/resources/setups/qualification/system_config.json similarity index 65% rename from resources/setups/qualification/system_module_config.json rename to resources/setups/qualification/system_config.json index c7e941e572..7a7285d605 100644 --- a/resources/setups/qualification/system_module_config.json +++ b/resources/setups/qualification/system_config.json @@ -6,14 +6,18 @@ "bacnet": { "enabled": true }, - "brute": { - "enabled": false - }, "discover": { "enabled": true }, "ipaddr": { - "timeout_sec": 120 + "enabled": true, + "timeout_sec": 0, + "port_flap_timeout_sec": 20, + "dhcp_ranges": [{"start": "10.10.0.1", "end": "10.10.255.254", "prefix_length": 16}, + {"start": "192.168.100.1", "end": "192.168.100.254", "prefix_length": 24}] + }, + "manual": { + "enabled": true }, "mudgee": { "enabled": true @@ -22,21 +26,31 @@ "enabled": true }, "nmap": { + "enabled": true, + "timeout_sec": 0 + }, + "password": { + "enabled": true, + "timeout_sec": 0 + }, + "ssh": { "enabled": true }, "switch": { "enabled": true, + "timeout_sec": 0, "poe": { "enabled" : true } }, "tls": { - "enabled": true + "enabled": true, + "timeout_sec": 0 }, - "passwords": { + "udmi": { "enabled": true }, - "udmi": { + "usi": { "enabled": false } }, @@ -46,10 +60,44 @@ }, "report": { "results": [ "pass", "fail", "skip", "info" ], - "categories": [ "Connection", "Security", "Network Time", "TLS", "Protocol", "PoE", "BOS"], - "expected": [ "Required Pass", "Required Pass for PoE Devices", "Required Pass for BACnet Devices", "Recommended Pass", "Information" ] + "categories": [ "Base", "Connection", "Security", "NTP", "DNS", "Communication", "Protocol", "PoE", "IoT"], + "expected": [ "Required Pass", "Required Pass for PoE Devices", "Required Pass for BACnet Devices", "Required Pass for IoT Devices", "Recommended Pass", "Information" ] }, "tests": { + "connection.manual.comms_down": { + "category": "Connection", + "required": "pass", + "expected": "Required Pass", + "description": "Remove the network connection and confirm the device is still operational.", + "enabled": true, + "type": "manual", + "result": "required", + "outcome": "", + "summary" : "", + "test_log" : "" + }, + "connection.manual.sec_eth_port": { + "category": "Connection", + "required": "pass", + "expected": "Required Pass", + "description": "Connect the second port to the network switch. Check that no connection light is available and the port has been disabled.", + "enabled": true, + "type": "manual", + "result": "required", + "outcome": "", + "summary" : "", + "test_log" : "" + }, + "base.startup.dhcp": { + "category": "Base", + "required": "pass", + "expected": "Required Pass" + }, + "base.switch.ping": { + "category": "Base", + "required": "pass", + "expected": "Required Pass" + }, "connection.switch.port_link": { "category": "Connection", "required": "pass", @@ -65,7 +113,7 @@ "required": "pass", "expected": "Required Pass" }, - "base.switch.ping": { + "connection.ipaddr.private_address": { "category": "Connection", "required": "pass", "expected": "Required Pass" @@ -75,17 +123,22 @@ "required": "pass", "expected": "Required Pass" }, - "connection.ipaddr.private_address": { + "connection.ipaddr.dhcp_disconnect": { "category": "Connection", "required": "pass", "expected": "Required Pass" }, - "connection.ipaddr.dhcp_disconnect": { + "connection.ipaddr.disconnect_ip_change": { "category": "Connection", "required": "pass", "expected": "Required Pass" }, - "connection.network.dhcp_long": { + "connection.ipaddr.ip_change": { + "category": "Connection", + "required": "pass", + "expected": "Required Pass" + }, + "connection.network.mac_address": { "category": "Connection", "required": "pass", "expected": "Required Pass" @@ -96,40 +149,65 @@ "expected": "Required Pass" }, "ntp.network.ntp_support": { - "category": "Network Time", + "category": "NTP", + "required": "pass", + "expected": "Required Pass" + }, + "security.nmap.ports": { + "category": "Security", + "required": "pass", + "expected": "Required Pass" + }, + "security.nmap.http": { + "category": "Security", "required": "pass", "expected": "Required Pass" }, "ntp.network.ntp_update": { - "category": "Network Time", + "category": "NTP", + "required": "pass", + "expected": "Required Pass" + }, + "communication.network.min_send": { + "category": "Communication", "required": "pass", "expected": "Required Pass" }, - "connection.network.communication_type": { + "communication.network.type": { "category": "Communication", "required": "info", "expected": "Information" }, - "connection.network.communication_min_send": { - "category": "Communication", + "dns.network.hostname_resolution": { + "category": "DNS", "required": "pass", "expected": "Required Pass" }, - "security.nmap.ports": { + "security.tls.v1_server": { "category": "Security", "required": "pass", "expected": "Required Pass" }, - "security.tls.v3": { - "category": "TLS", + "security.tls.v1_2_server": { + "category": "Security", "required": "pass", "expected": "Required Pass" }, - "security.tls.x509": { - "category": "Access Control", + "security.tls.v1_2_client": { + "category": "Security", "required": "pass", "expected": "Required Pass" }, + "security.tls.v1_3_server": { + "category": "Security", + "required": "pass", + "expected": "Recommended Pass" + }, + "security.tls.v1_3_client": { + "category": "Security", + "required": "pass", + "expected": "Recommended Pass" + }, "security.password.http": { "category": "Security", "required": "pass", @@ -150,6 +228,11 @@ "required": "pass", "expected": "Required Pass" }, + "security.ssh.version": { + "category": "Security", + "required": "pass", + "expected": "Required Pass" + }, "protocol.bacext.pic": { "category": "Protocol", "required": "pass", @@ -165,73 +248,15 @@ "required": "pass", "expected": "Required Pass for PoE Devices" }, - "poe.switch.negotiation": { - "category": "PoE", - "required": "pass", - "expected": "Required Pass for PoE Devices" - }, - "poe.switch.support": { - "category": "PoE", - "required": "info", - "expected": "Information" - }, "cloud.udmi.pointset": { - "category": "BOS", + "category": "IoT", "required": "pass", - "expected": "Recommended Pass" + "expected": "Required Pass for IoT Devices" }, "security.discover.firmware": { "category": "Security", "required": "info", "expected": "Information" - }, - "security.manual.java_interface": { - "category": "Security", - "required": "pass", - "expected": "Required Pass", - "type": "manual" - }, - "security.manual.flash_interface": { - "category": "Security", - "required": "pass", - "expected": "Required Pass", - "type": "manual" - }, - "security.manual.flash_functionality": { - "category": "Security", - "required": "pass", - "expected": "Required Pass", - "type": "manual" - }, - "security.manual.http": { - "category": "Security", - "required": "pass", - "expected": "Required Pass", - "type": "manual" - }, - "security.manual.web_passwords": { - "category": "Security", - "required": "pass", - "expected": "Required Pass", - "type": "manual" - }, - "connection.manual.comms_down": { - "category": "Connection", - "required": "pass", - "expected": "Recommended Pass", - "type": "manual" - }, - "connection.manual.sec_eth_port": { - "category": "Connection", - "required": "pass", - "expected": "Recommended Pass", - "type": "manual" - }, - "connection.manual.sec_eth_port_no_ip": { - "category": "Connection", - "required": "pass", - "expected": "Recommended Pass", - "type": "manual" } } } diff --git a/resources/setups/remediation/device_module_config.json b/resources/setups/remediation/device_config.json similarity index 100% rename from resources/setups/remediation/device_module_config.json rename to resources/setups/remediation/device_config.json diff --git a/resources/setups/remediation/system_module_config.json b/resources/setups/remediation/system_config.json similarity index 100% rename from resources/setups/remediation/system_module_config.json rename to resources/setups/remediation/system_config.json From 01156d874f18d0e7f962aeaebc349ba967c236d2 Mon Sep 17 00:00:00 2001 From: Trevor Date: Sun, 13 Dec 2020 08:36:59 -0800 Subject: [PATCH 202/212] Fix setuptools install (#721) --- .github/workflows/tests.yml | 6 +++--- bin/setup_dev | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 91126daaf1..e63d3179c1 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -11,7 +11,7 @@ on: jobs: integration_tests: - runs-on: ubuntu-latest + runs-on: ubuntu-18.04 strategy: fail-fast: false matrix: @@ -46,7 +46,7 @@ jobs: cat inst/test_${{ matrix.test }}.out unit_tests: - runs-on: ubuntu-latest + runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 - name: Set up Python 3.8 @@ -64,7 +64,7 @@ jobs: testing/run_unit_tests.sh usi_tests: - runs-on: ubuntu-latest + runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v2 - name: Set up JDK 1.11 diff --git a/bin/setup_dev b/bin/setup_dev index c7f68ad604..a352f2a19a 100755 --- a/bin/setup_dev +++ b/bin/setup_dev @@ -134,8 +134,9 @@ $PIP -V echo Installing python dependencies... $PIP install wheel +$PIP install --upgrade --index-url=https://pypi.python.org/simple setuptools $PIP install --upgrade --index-url=https://pypi.python.org/simple Jinja2 \ - pylint==2.4.2 cryptography requests netifaces codecov coverage setuptools \ + pylint==2.4.2 cryptography requests netifaces codecov coverage \ pyyaml cairocffi==1.0.2 WeasyPrint==50 pypandoc==1.4 \ firebase-admin==2.16.0 \ google-api-core==1.16.0 \ From edc6e74c030d67bccd8fddc833e130def36e3380 Mon Sep 17 00:00:00 2001 From: Trevor Pering Date: Mon, 14 Dec 2020 20:02:25 -0800 Subject: [PATCH 203/212] Lower codecov target --- codecov.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/codecov.yml b/codecov.yml index 58e59b885d..8f7a1cc8a0 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,5 +1,8 @@ coverage: status: + project: + default: + target: 80% patch: default: threshold: .5% From a3f781dcf9c2840112f68e08d1edb7ddb04cac25 Mon Sep 17 00:00:00 2001 From: Yufeng Duan <55268016+didovesei@users.noreply.github.com> Date: Thu, 31 Dec 2020 09:24:10 -1000 Subject: [PATCH 204/212] Update MUD tests (#726) --- testing/test_base.out | 22 ++++++++-------------- testing/test_base.sh | 41 +++++++++++++++++++++++------------------ 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/testing/test_base.out b/testing/test_base.out index 7cb545df38..4bcf7134fe 100644 --- a/testing/test_base.out +++ b/testing/test_base.out @@ -169,21 +169,15 @@ RESULT fail base.startup.dns Invalid DNS server address %% DNS server 10.20.99.2 9a02571e8f02: ['9a02571e8f02:acquire:TimeoutError'] %%%%%%%%%%%%%%%%%%%%%% Mud profile tests result open 9a02571e8f01: [] 9a02571e8f02: [] 9a02571e8f03: [] -device open 1 1 1 -cntrlr open 1 1 1 -result base 9a02571e8f01: [] 9a02571e8f02: [] 9a02571e8f03: [] -device base 1 1 0 -cntrlr base 1 1 0 +device-1 open 1 1 1 1 +device-2 open 1 1 1 1 result todev 9a02571e8f01: ['9a02571e8f01:ping:1'] 9a02571e8f02: ['9a02571e8f02:ping:1'] 9a02571e8f03: [] -device todev 0 0 0 -cntrlr todev 0 0 0 -result frdev 9a02571e8f01: [] 9a02571e8f02: ['9a02571e8f02:ping:1'] 9a02571e8f03: [] -device frdev 1 0 0 -cntrlr frdev 1 0 0 +device-1 todev 0 0 0 0 +device-2 todev 0 0 0 0 result none 9a02571e8f01: ['9a02571e8f01:ping:1'] 9a02571e8f02: ['9a02571e8f02:ping:1'] 9a02571e8f03: [] -device none 0 0 0 -cntrlr none 0 0 0 +device-1 none 0 0 0 0 +device-2 none 0 0 0 0 result star 9a02571e8f01: [] 9a02571e8f02: [] 9a02571e8f03: [] -device star 1 1 1 -cntrlr star 1 1 0 +device-1 star 1 1 1 1 +device-2 star 1 1 1 0 %%%%%%%%%%%%%%%%%%%%%% Done with tests diff --git a/testing/test_base.sh b/testing/test_base.sh index 51d24891fd..907b9524c4 100755 --- a/testing/test_base.sh +++ b/testing/test_base.sh @@ -76,35 +76,40 @@ if [ -z `which tcpdump` ]; then export PATH=/usr/sbin:$PATH fi -device_traffic="tcpdump -en -r inst/run-9a02571e8f01/scans/monitor.pcap port 47808" -device_bcast="$device_traffic and ether broadcast" -device_ucast="$device_traffic and ether dst 9a:02:57:1e:8f:02" -device_xcast="$device_traffic and ether dst 9a:02:57:1e:8f:03" -cntrlr_traffic="tcpdump -en -r inst/run-9a02571e8f02/scans/monitor.pcap port 47808" -cntrlr_bcast="$cntrlr_traffic and ether broadcast" -cntrlr_ucast="$cntrlr_traffic and ether dst 9a:02:57:1e:8f:01" -cntrlr_xcast="$cntrlr_traffic and ether dst 9a:02:57:1e:8f:03" +function test_device_traffic { + device_num=$1 + peer_num=$((3-device_num)) + device_mac=9a:02:57:1e:8f:0$device_num + peer_mac=9a:02:57:1e:8f:0$peer_num + neighbor_mac=9a:02:57:1e:8f:03 + + device_traffic="tcpdump -en -r inst/run-9a02571e8f0$device_num/scans/monitor.pcap port 47808" + device_bfr_peer="$device_traffic and ether src $peer_mac and ether broadcast" + device_bfr_ngbr="$device_traffic and ether src $neighbor_mac and ether broadcast" + device_ufr_peer="$device_traffic and ether src $peer_mac and ether dst $device_mac" + device_ufr_ngbr="$device_traffic and ether src $neighbor_mac and ether dst $device_mac" + bfr_peer=$($device_bfr_peer | wc -l) + bfr_ngbr=$($device_bfr_ngbr | wc -l) + ufr_peer=$($device_ufr_peer | wc -l) + ufr_ngbr=$($device_ufr_ngbr | wc -l) + echo device-$device_num $type $((bfr_peer > 2)) $((bfr_ngbr > 0)) $((ufr_peer > 2)) $((ufr_ngbr > 0)) | tee -a $TEST_RESULTS +} function test_mud { type=$1 echo %%%%%%%%%%%%%%%%% test mud profile $type cmd/run -s device_specs=resources/device_specs/bacnet_$type.json + echo result $type $(sort inst/result.log) | tee -a $TEST_RESULTS - bcast=$($device_bcast | wc -l) - ucast=$($device_ucast | wc -l) - xcast=$($device_xcast | wc -l) - echo device $type $(($bcast > 2)) $(($ucast > 2)) $(($xcast > 0)) | tee -a $TEST_RESULTS - bcast=$($cntrlr_bcast | wc -l) - ucast=$($cntrlr_ucast | wc -l) - xcast=$($cntrlr_xcast | wc -l) - echo cntrlr $type $(($bcast > 2)) $(($ucast > 2)) $(($xcast > 0)) | tee -a $TEST_RESULTS + + test_device_traffic 1 + test_device_traffic 2 + more inst/run-*/nodes/*/activate.log | cat } test_mud open -test_mud base test_mud todev -test_mud frdev test_mud none test_mud star From 24b8f9a78aa905e471311f7dd94127e37a040b9c Mon Sep 17 00:00:00 2001 From: noursaidi Date: Fri, 1 Jan 2021 15:15:16 +0000 Subject: [PATCH 205/212] remove information tests --- daq/testpy | 39 +++++++++++++++++++ docs/device_report.md | 10 ++--- .../setups/qualification/system_config.json | 12 +++--- .../setups/remediation/system_config.json | 16 ++------ .../src/main/java/VersionTest.java | 4 +- subset/network/network_tests.py | 7 +++- subset/network/run_macoui_test | 4 +- testing/test_aux.out | 16 ++++---- 8 files changed, 72 insertions(+), 36 deletions(-) create mode 100644 daq/testpy diff --git a/daq/testpy b/daq/testpy new file mode 100644 index 0000000000..6a8478f522 --- /dev/null +++ b/daq/testpy @@ -0,0 +1,39 @@ +arr1 = [[1,2,3],[4,5,6],[7,8,9]] +print(arr1) + +def jj(tt): + return '/'.join(str(v) for v in tt) + +#newlist=list(map(jj,arr1)) +newlist=list(map(lambda results:'/'.join(str(v) for v in results), arr1)) +print(newlist) + +colheader=["one","two","three","four"] +print(["a", "b"] + colheader) + +#PREPOPULATE OUTPU +blank= [[0,0,0] for _ in range(len(colheader))] +print(blank) +blank[2][2] = 7 +print(blank) +print(list(map(jj,blank))) + +result="skipa" + +if result in ["pass", "skip"]: + print("yes") + +result = "n/a" +for i in range(1,5): + cur = "pass" if i == 1 else cur + cur = "pass" if i == 2 else cur + cur = "pass" if i == 3 else cur + cur = "pass" if i == 4 else cur + cur = "pass" if i == 5 else cur + + if result not in ("n/a", cur, 'info'): + result = "fail" + else: + result = cur + +print(result) \ No newline at end of file diff --git a/docs/device_report.md b/docs/device_report.md index e12958aaa4..02f90f0790 100644 --- a/docs/device_report.md +++ b/docs/device_report.md @@ -65,10 +65,10 @@ Syntax: Pass / Fail / Skip |---|---|---|---|---|---| |Required Pass|4|1|8|0|4| |Required Pass for PoE Devices|0|0|1|0|1| -|Required Pass for BACnet Devices|0|1|0|0|0| +|Required Pass for BACnet Devices|0|1|1|0|0| |Recommended Pass|1|0|1|0|1| -|Information|0|0|2|0|2| -|Other|3|0|9|2|2| +|Information|0|0|0|0|2| +|Other|4|0|9|2|2| |Result|Test|Category|Expectation|Notes| |---|---|---|---|---| @@ -86,7 +86,7 @@ Syntax: Pass / Fail / Skip |gone|connection.network.communication_min_send|Communication|Required Pass|| |gone|connection.network.communication_type|Communication|Information|| |gone|connection.network.dhcp_long|Connection|Required Pass|| -|info|connection.network.mac_address|Other|Other|Device MAC address is 9a:02:57:1e:8f:01| +|pass|connection.network.mac_address|Other|Other|Device MAC address is 9a:02:57:1e:8f:01| |fail|connection.network.mac_oui|Connection|Required Pass|Manufacturer prefix not found!| |skip|connection.switch.port_duplex|Connection|Required Pass|No local IP has been set, check system config| |skip|connection.switch.port_link|Connection|Required Pass|No local IP has been set, check system config| @@ -626,7 +626,7 @@ Reports device MAC address -------------------- Device MAC address is 9a:02:57:1e:8f:01 -------------------- -RESULT info connection.network.mac_address Device MAC address is 9a:02:57:1e:8f:01 +RESULT pass connection.network.mac_address Device MAC address is 9a:02:57:1e:8f:01 -------------------- dns.network.hostname_resolution diff --git a/resources/setups/qualification/system_config.json b/resources/setups/qualification/system_config.json index 7a7285d605..dbad48e655 100644 --- a/resources/setups/qualification/system_config.json +++ b/resources/setups/qualification/system_config.json @@ -175,8 +175,8 @@ }, "communication.network.type": { "category": "Communication", - "required": "info", - "expected": "Information" + "required": "pass", + "expected": "Required Pass" }, "dns.network.hostname_resolution": { "category": "DNS", @@ -240,8 +240,8 @@ }, "protocol.bacext.version": { "category": "Protocol", - "required": "info", - "expected": "Information" + "required": "pass", + "expected": "Required Pass for BACnet Devices" }, "poe.switch.power": { "category": "PoE", @@ -255,8 +255,8 @@ }, "security.discover.firmware": { "category": "Security", - "required": "info", - "expected": "Information" + "required": "pass", + "expected": "Required Pass for BACnet Devices" } } } diff --git a/resources/setups/remediation/system_config.json b/resources/setups/remediation/system_config.json index e821c16ee2..d618b37636 100644 --- a/resources/setups/remediation/system_config.json +++ b/resources/setups/remediation/system_config.json @@ -149,28 +149,18 @@ "protocol.bacext.pic": { "category": "Protocol", "required": "pass", - "expected": "Required Pass for BACnet devices" + "expected": "Required Pass for BACnet Devices" }, "protocol.bacext.version": { "category": "Protocol", - "required": "info", - "expected": "Information" - }, - "poe.switch.power": { - "category": "PoE", "required": "pass", - "expected": "Required Pass for PoE Devices" + "expected": "Required Pass for BACnet Devices" }, - "poe.switch.negotiation": { + "poe.switch.power": { "category": "PoE", "required": "pass", "expected": "Required Pass for PoE Devices" }, - "poe.switch.support": { - "category": "PoE", - "required": "info", - "expected": "Information" - }, "cloud.udmi.pointset": { "category": "BOS", "required": "pass", diff --git a/subset/bacnet/bacnetTests/src/main/java/VersionTest.java b/subset/bacnet/bacnetTests/src/main/java/VersionTest.java index 0bcb16d274..217e2dfdd5 100644 --- a/subset/bacnet/bacnetTests/src/main/java/VersionTest.java +++ b/subset/bacnet/bacnetTests/src/main/java/VersionTest.java @@ -22,7 +22,7 @@ public class VersionTest { private boolean testPassed = false; boolean bacnetSupported = false; private String testName = "protocol.bacext.version"; - private String infoReportText = String.format("RESULT info %s", testName); + private String passReportText = String.format("RESULT pass %s", testName); private String skippedReportText = String.format("RESULT skip %s Bacnet device not found.", testName); private String errorPropertyMessage = "errorClass=Property, errorCode=Unknown property"; private String protocolVersionText = ""; @@ -136,7 +136,7 @@ private void generateReport(String deviceMacAddress) { Report report = new Report("tmp/BacnetVersionTestReport.txt"); Report appendices = new Report("tmp/BacnetVersionTest_APPENDIX.txt"); if (bacnetSupported && testPassed) { - report.writeReport(infoReportText + protocolVersionText); + report.writeReport(passReportText + protocolVersionText); } else { report.writeReport(skippedReportText); } diff --git a/subset/network/network_tests.py b/subset/network/network_tests.py index 5ef25bc182..8249b01a03 100644 --- a/subset/network/network_tests.py +++ b/subset/network/network_tests.py @@ -187,26 +187,31 @@ def test_communication_type_broadcast(): """ Runs the communication.network.type DAQ test. Counts the number of unicast, broadcast and multicast packets sent. """ + test_result = 'fail' broadcast_result = shell_command_with_result(tcpdump_display_broadcast_packets, 0, False) broadcast_packets = packets_received_count(broadcast_result) if broadcast_packets > 0: + test_result = 'pass' add_summary("Broadcast packets received.") add_packet_count_to_report("Broadcast", broadcast_packets) multicast_result = shell_command_with_result(tcpdump_display_multicast_packets, 0, False) multicast_packets = packets_received_count(multicast_result) if multicast_packets > 0: + test_result = 'pass' add_summary("Multicast packets received.") add_packet_count_to_report("Multicast", multicast_packets) unicast_result = shell_command_with_result(tcpdump_display_all_packets, 0, False) unicast_packets = packets_received_count(unicast_result) - broadcast_packets - multicast_packets if unicast_packets > 0: + test_result = 'pass' add_summary("Unicast packets received.") add_packet_count_to_report("Unicast", unicast_packets) - return 'info' + + return test_result write_report("{b}{t}\n{b}".format(b=dash_break_line, t=test_request)) diff --git a/subset/network/run_macoui_test b/subset/network/run_macoui_test index 39a5d2880d..e410fd2072 100755 --- a/subset/network/run_macoui_test +++ b/subset/network/run_macoui_test @@ -33,7 +33,9 @@ write_out_result $REPORT \ TEST_NAME="connection.network.mac_address" TEST_DESCRIPTION="Reports device MAC address" TEST_RESULT="Device MAC address is ${TARGET_MAC}" -RESULT_AND_SUMMARY="RESULT info ${TEST_NAME} ${TEST_RESULT}" + +# Test result is a pass because there will always be a MAC address +RESULT_AND_SUMMARY="RESULT pass ${TEST_NAME} ${TEST_RESULT}" write_out_result $REPORT \ "$TEST_NAME" \ diff --git a/testing/test_aux.out b/testing/test_aux.out index a34f90be51..7b73e43e3f 100644 --- a/testing/test_aux.out +++ b/testing/test_aux.out @@ -17,9 +17,9 @@ RESULT skip base.startup.ntp No NTP traffic detected RESULT pass base.startup.dns Correct DNS server address RESULT skip protocol.bacext.version Bacnet device not found. RESULT fail protocol.bacext.pic PICS file defined however a BACnet device was not found. -RESULT info protocol.bacext.version Protocol version: 1 +RESULT pass protocol.bacext.version Protocol version: 1 RESULT skip protocol.bacext.pic BACnet device found, but pics.csv not found in device type directory. -RESULT info protocol.bacext.version Protocol version: 1 +RESULT pass protocol.bacext.version Protocol version: 1 RESULT pass protocol.bacext.pic The devices matches the PICS RESULT skip security.tls.v1_2_client No client initiated TLS communication detected RESULT skip security.tls.v1_2_server IOException unable to connect to server. @@ -51,25 +51,25 @@ RESULT pass security.password.telnet Was not able to brute force using dictionar RESULT skip security.discover.firmware Could not retrieve a firmware version with nmap. Check bacnet port. RESULT pass security.discover.firmware version found: ?\xFF\xFF\x19,>u\x08\x00no RESULT pass communication.network.min_send ARP packets received. Data packets were sent at a frequency of less than 5 minutes -RESULT info communication.network.type Broadcast packets received. Unicast packets received. +RESULT pass communication.network.type Broadcast packets received. Unicast packets received. RESULT pass ntp.network.ntp_support Using NTPv4. RESULT pass ntp.network.ntp_update Device clock synchronized. RESULT fail connection.network.mac_oui Manufacturer prefix not found! -RESULT info connection.network.mac_address Device MAC address is 9a:02:57:1e:8f:01 +RESULT pass connection.network.mac_address Device MAC address is 9a:02:57:1e:8f:01 RESULT skip dns.network.hostname_resolution Device did not send any DNS requests RESULT pass communication.network.min_send ARP packets received. Data packets were sent at a frequency of less than 5 minutes -RESULT info communication.network.type Broadcast packets received. Unicast packets received. +RESULT pass communication.network.type Broadcast packets received. Unicast packets received. RESULT fail ntp.network.ntp_support Not using NTPv4. RESULT fail ntp.network.ntp_update Device clock not synchronized with local NTP server. RESULT pass connection.network.mac_oui Manufacturer: Google found for address 3c:5a:b4:1e:8f:0b -RESULT info connection.network.mac_address Device MAC address is 3c:5a:b4:1e:8f:0b +RESULT pass connection.network.mac_address Device MAC address is 3c:5a:b4:1e:8f:0b RESULT fail dns.network.hostname_resolution Device sent DNS requests to servers other than the DHCP provided server RESULT pass communication.network.min_send ARP packets received. Data packets were sent at a frequency of less than 5 minutes -RESULT info communication.network.type Broadcast packets received. Unicast packets received. +RESULT pass communication.network.type Broadcast packets received. Unicast packets received. RESULT skip ntp.network.ntp_support No NTP packets received. RESULT skip ntp.network.ntp_update Not enough NTP packets received. RESULT pass connection.network.mac_oui Manufacturer: Google found for address 3c:5a:b4:1e:8f:0a -RESULT info connection.network.mac_address Device MAC address is 3c:5a:b4:1e:8f:0a +RESULT pass connection.network.mac_address Device MAC address is 3c:5a:b4:1e:8f:0a RESULT pass dns.network.hostname_resolution Device sends DNS requests and resolves host names dhcp requests 1 1 1 1 3c5ab41e8f0a: [] From 9cf75083908072203da41f3960842f2653969333 Mon Sep 17 00:00:00 2001 From: noursaidi Date: Fri, 1 Jan 2021 18:59:34 +0000 Subject: [PATCH 206/212] remove "information category", ci fix for previous commit --- docs/device_report.md | 20 ++++++++++---------- resources/test_site/module_config.json | 18 ++++-------------- 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/docs/device_report.md b/docs/device_report.md index 02f90f0790..a9a57dd9ad 100644 --- a/docs/device_report.md +++ b/docs/device_report.md @@ -61,14 +61,14 @@ Overall device result FAIL |Communication|2|GONE|0/1/0|0/0/0|0/0/0|0/0/0|0/1/0|0/0/0| Syntax: Pass / Fail / Skip -|Expectation|pass|fail|skip|info|gone| -|---|---|---|---|---|---| -|Required Pass|4|1|8|0|4| -|Required Pass for PoE Devices|0|0|1|0|1| -|Required Pass for BACnet Devices|0|1|1|0|0| -|Recommended Pass|1|0|1|0|1| -|Information|0|0|0|0|2| -|Other|4|0|9|2|2| +|Expectation|pass|fail|skip|gone| +|---|---|---|---|---| +|Required Pass|4|1|8|4| +|Required Pass for PoE Devices|0|0|1|1| +|Required Pass for BACnet Devices|0|1|0|0| +|Recommended Pass|1|0|1|1| +|Information|0|0|2|2| +|Other|5|0|9|2|$ |Result|Test|Category|Expectation|Notes| |---|---|---|---|---| @@ -79,7 +79,7 @@ Syntax: Pass / Fail / Skip |skip|cloud.udmi.state|Other|Other|No device id| |skip|cloud.udmi.system|Other|Other|No device id| |pass|communication.network.min_send|Other|Other|ARP packets received. Data packets were sent at a frequency of less than 5 minutes| -|info|communication.network.type|Other|Other|Broadcast packets received. Unicast packets received.| +|pass|communication.network.type|Other|Other|Broadcast packets received. Unicast packets received.| |pass|connection.base.target_ping|Connection|Required Pass|target reached| |gone|connection.ipaddr.dhcp_disconnect|Connection|Required Pass|| |gone|connection.ipaddr.private_address|Connection|Required Pass|| @@ -596,7 +596,7 @@ Device sends unicast or broadcast packets. -------------------- -RESULT info communication.network.type Broadcast packets received. Unicast packets received. +RESULT pass communication.network.type Broadcast packets received. Unicast packets received. -------------------- ntp.network.ntp_support -------------------- diff --git a/resources/test_site/module_config.json b/resources/test_site/module_config.json index 4ecbbd036f..47c3c246dc 100644 --- a/resources/test_site/module_config.json +++ b/resources/test_site/module_config.json @@ -148,24 +148,14 @@ }, "protocol.bacext.version": { "category": "Protocol", - "required": "info", - "expected": "Information" - }, - "poe.switch.power": { - "category": "PoE", "required": "pass", - "expected": "Required Pass for PoE Devices" + "expected": "Required Pass for BACnet Devices" }, - "poe.switch.negotiation": { + "poe.switch.power": { "category": "PoE", "required": "pass", "expected": "Required Pass for PoE Devices" }, - "poe.switch.support": { - "category": "PoE", - "required": "info", - "expected": "Information" - }, "cloud.udmi.pointset": { "category": "BOS", "required": "pass", @@ -173,8 +163,8 @@ }, "security.discover.firmware": { "category": "Security", - "required": "info", - "expected": "Information" + "required": "pass", + "expected": "Required Pass for BACnet Devices" } } } From db58712e18543cff83852ecffda1ad76e1375abb Mon Sep 17 00:00:00 2001 From: noursaidi Date: Fri, 1 Jan 2021 20:05:11 +0000 Subject: [PATCH 207/212] ci fix previous commit, remove information category --- docs/device_report.md | 37 ++++++++++++-------------- resources/test_site/module_config.json | 2 +- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/docs/device_report.md b/docs/device_report.md index a9a57dd9ad..fbf9e78b50 100644 --- a/docs/device_report.md +++ b/docs/device_report.md @@ -48,27 +48,26 @@ Overall device result FAIL **Some tests report as GONE. Please check for possible misconfiguration** -|Category|Total Tests|Result|Required Pass|Required Pass for PoE Devices|Required Pass for BACnet Devices|Recommended Pass|Information|Other| +|Category|Total Tests|Result|Required Pass|Required Pass for PoE Devices|Required Pass for BACnet Devices|Recommended Pass|Other| |---|---|---|---|---|---|---|---|---| -|Connection|9|FAIL|1/4/4|0/0/0|0/0/0|0/0/0|0/0/0|0/0/0| -|Security|8|FAIL|1/0/4|0/0/0|0/0/0|1/1/0|0/0/1|0/0/0| -|Network Time|2|PASS|2/0/0|0/0/0|0/0/0|0/0/0|0/0/0|0/0/0| -|TLS|0|N/A|0/0/0|0/0/0|0/0/0|0/0/0|0/0/0|0/0/0| -|Protocol|2|FAIL|0/0/0|0/0/0|0/1/0|0/0/0|0/0/1|0/0/0| -|PoE|3|FAIL|0/0/0|0/1/1|0/0/0|0/0/0|0/1/0|0/0/0| -|BOS|1|SKIP|0/0/0|0/0/0|0/0/0|0/0/1|0/0/0|0/0/0| -|Other|2|GONE|0/0/0|0/0/0|0/0/0|0/0/0|0/0/0|0/2/0| -|Communication|2|GONE|0/1/0|0/0/0|0/0/0|0/0/0|0/1/0|0/0/0| +|Connection|9|FAIL|1/4/4|0/0/0|0/0/0|0/0/0|0/0/0| +|Security|8|FAIL|1/0/4|0/0/0|0/0/1|1/1/00/0/0| +|Network Time|2|PASS|2/0/0|0/0/0|0/0/0|0/0/0|0/0/0| +|TLS|0|N/A|0/0/0|0/0/0|0/0/0|0/0/0|0/0/0| +|Protocol|2|FAIL|0/0/0|0/0/0|0/1/1|0/0/0|0/0/0| +|PoE|1|SKIP|0/0/0|0/0/1|0/0/0|0/0/0|0/0/0| +|BOS|1|SKIP|0/0/0|0/0/0|0/0/0|0/0/1|0/0/0| +|Other|2|GONE|0/0/0|0/0/0|0/0/0|0/0/0|0/2/0| +|Communication|2|GONE|0/1/0|0/0/0|0/0/0|0/0/0|0/0/0| Syntax: Pass / Fail / Skip |Expectation|pass|fail|skip|gone| |---|---|---|---|---| -|Required Pass|4|1|8|4| -|Required Pass for PoE Devices|0|0|1|1| -|Required Pass for BACnet Devices|0|1|0|0| +|Required Pass|4|1|8|5| +|Required Pass for PoE Devices|0|0|1|0| +|Required Pass for BACnet Devices|0|1|2|0| |Recommended Pass|1|0|1|1| -|Information|0|0|2|2| -|Other|5|0|9|2|$ +|Other|5|0|9|2| |Result|Test|Category|Expectation|Notes| |---|---|---|---|---| @@ -84,7 +83,7 @@ Syntax: Pass / Fail / Skip |gone|connection.ipaddr.dhcp_disconnect|Connection|Required Pass|| |gone|connection.ipaddr.private_address|Connection|Required Pass|| |gone|connection.network.communication_min_send|Communication|Required Pass|| -|gone|connection.network.communication_type|Communication|Information|| +|gone|connection.network.communication_type|Communication|Required Pass|| |gone|connection.network.dhcp_long|Connection|Required Pass|| |pass|connection.network.mac_address|Other|Other|Device MAC address is 9a:02:57:1e:8f:01| |fail|connection.network.mac_oui|Connection|Required Pass|Manufacturer prefix not found!| @@ -95,12 +94,10 @@ Syntax: Pass / Fail / Skip |pass|manual.test.name|Security|Recommended Pass|Manual test - for testing| |pass|ntp.network.ntp_support|Network Time|Required Pass|Using NTPv4.| |pass|ntp.network.ntp_update|Network Time|Required Pass|Device clock synchronized.| -|gone|poe.switch.negotiation|PoE|Required Pass for PoE Devices|| |skip|poe.switch.power|PoE|Required Pass for PoE Devices|No local IP has been set, check system config| -|gone|poe.switch.support|PoE|Information|| |fail|protocol.bacext.pic|Protocol|Required Pass for BACnet Devices|PICS file defined however a BACnet device was not found.| -|skip|protocol.bacext.version|Protocol|Information|Bacnet device not found.| -|skip|security.discover.firmware|Security|Information|Could not retrieve a firmware version with nmap. Check bacnet port.| +|skip|protocol.bacext.version|Protocol|Required Pass for BACnet Devices|Bacnet device not found.| +|skip|security.discover.firmware|Security|Required Pass for BACnet Devices|Could not retrieve a firmware version with nmap. Check bacnet port.| |pass|security.nmap.http|Other|Other|No running http servers have been found.| |pass|security.nmap.ports|Security|Required Pass|Only allowed ports found open.| |skip|security.password.http|Security|Required Pass|Port 80 not open on target device.| diff --git a/resources/test_site/module_config.json b/resources/test_site/module_config.json index 47c3c246dc..719dc06987 100644 --- a/resources/test_site/module_config.json +++ b/resources/test_site/module_config.json @@ -109,7 +109,7 @@ "connection.network.communication_type": { "category": "Communication", "required": "info", - "expected": "Information" + "expected": "Required Pass" }, "connection.network.communication_min_send": { "category": "Communication", From 4a0540b7ecff08db70c1552ba9b8ae124351a6e1 Mon Sep 17 00:00:00 2001 From: noursaidi Date: Fri, 1 Jan 2021 21:15:28 +0000 Subject: [PATCH 208/212] update test_site/module_config --- resources/test_site/module_config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/test_site/module_config.json b/resources/test_site/module_config.json index 719dc06987..7d1a7cbcc2 100644 --- a/resources/test_site/module_config.json +++ b/resources/test_site/module_config.json @@ -29,7 +29,7 @@ "report": { "results": [ "pass", "fail", "skip" ], "categories": [ "Connection", "Security", "Network Time", "TLS", "Protocol", "PoE", "BOS"], - "expected": [ "Required Pass", "Required Pass for PoE Devices", "Required Pass for BACnet Devices", "Recommended Pass", "Information" ] + "expected": [ "Required Pass", "Required Pass for PoE Devices", "Required Pass for BACnet Devices", "Recommended Pass"] }, "tests": { "unknown.fake.llama": { From 82a62fe626a14495bdf33b726114d6d312623159 Mon Sep 17 00:00:00 2001 From: noursaidi Date: Fri, 1 Jan 2021 22:13:07 +0000 Subject: [PATCH 209/212] fix device_report --- docs/device_report.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/device_report.md b/docs/device_report.md index fbf9e78b50..7521dc5f40 100644 --- a/docs/device_report.md +++ b/docs/device_report.md @@ -49,16 +49,16 @@ Overall device result FAIL **Some tests report as GONE. Please check for possible misconfiguration** |Category|Total Tests|Result|Required Pass|Required Pass for PoE Devices|Required Pass for BACnet Devices|Recommended Pass|Other| -|---|---|---|---|---|---|---|---|---| +|---|---|---|---|---|---|---|---| |Connection|9|FAIL|1/4/4|0/0/0|0/0/0|0/0/0|0/0/0| -|Security|8|FAIL|1/0/4|0/0/0|0/0/1|1/1/00/0/0| +|Security|8|FAIL|1/0/4|0/0/0|0/0/1|1/1/0|0/0/0| |Network Time|2|PASS|2/0/0|0/0/0|0/0/0|0/0/0|0/0/0| |TLS|0|N/A|0/0/0|0/0/0|0/0/0|0/0/0|0/0/0| |Protocol|2|FAIL|0/0/0|0/0/0|0/1/1|0/0/0|0/0/0| |PoE|1|SKIP|0/0/0|0/0/1|0/0/0|0/0/0|0/0/0| |BOS|1|SKIP|0/0/0|0/0/0|0/0/0|0/0/1|0/0/0| |Other|2|GONE|0/0/0|0/0/0|0/0/0|0/0/0|0/2/0| -|Communication|2|GONE|0/1/0|0/0/0|0/0/0|0/0/0|0/0/0| +|Communication|2|GONE|0/2/0|0/0/0|0/0/0|0/0/0|0/0/0| Syntax: Pass / Fail / Skip |Expectation|pass|fail|skip|gone| From 088da45bb90964d96a9b4a2631904c4a4465c795 Mon Sep 17 00:00:00 2001 From: noursaidi Date: Sun, 3 Jan 2021 22:25:25 +0000 Subject: [PATCH 210/212] align changes for info in all module_configs --- resources/setups/qualification/system_config.json | 4 ++-- resources/setups/remediation/system_config.json | 12 ++++++------ resources/test_site/module_config.json | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/resources/setups/qualification/system_config.json b/resources/setups/qualification/system_config.json index dbad48e655..b5d5c29fc8 100644 --- a/resources/setups/qualification/system_config.json +++ b/resources/setups/qualification/system_config.json @@ -59,9 +59,9 @@ "operator": "*** Operator ***" }, "report": { - "results": [ "pass", "fail", "skip", "info" ], + "results": [ "pass", "fail", "skip" ], "categories": [ "Base", "Connection", "Security", "NTP", "DNS", "Communication", "Protocol", "PoE", "IoT"], - "expected": [ "Required Pass", "Required Pass for PoE Devices", "Required Pass for BACnet Devices", "Required Pass for IoT Devices", "Recommended Pass", "Information" ] + "expected": [ "Required Pass", "Required Pass for PoE Devices", "Required Pass for BACnet Devices", "Required Pass for IoT Devices", "Recommended Pass" ] }, "tests": { "connection.manual.comms_down": { diff --git a/resources/setups/remediation/system_config.json b/resources/setups/remediation/system_config.json index d618b37636..1cfd19d6df 100644 --- a/resources/setups/remediation/system_config.json +++ b/resources/setups/remediation/system_config.json @@ -41,9 +41,9 @@ } }, "report": { - "results": [ "pass", "fail", "skip", "info" ], + "results": [ "pass", "fail", "skip"], "categories": [ "Connection", "Security", "Network Time", "TLS", "Protocol", "PoE", "BOS"], - "expected": [ "Required Pass", "Required Pass for PoE Devices", "Required Pass for BACnet Devices", "Recommended Pass", "Information" ] + "expected": [ "Required Pass", "Required Pass for PoE Devices", "Required Pass for BACnet Devices", "Recommended Pass" ] }, "tests": { "connection.switch.port_link": { @@ -103,8 +103,8 @@ }, "connection.network.communication_type": { "category": "Communication", - "required": "info", - "expected": "information" + "required": "pass", + "expected": "Required Pass" }, "connection.network.communication_min_send": { "category": "Communication", @@ -168,8 +168,8 @@ }, "security.discover.firmware": { "category": "Security", - "required": "info", - "expected": "Information" + "required": "pass", + "expected": "Required Pass for BACnet Devices" } } } diff --git a/resources/test_site/module_config.json b/resources/test_site/module_config.json index 7d1a7cbcc2..53056b7400 100644 --- a/resources/test_site/module_config.json +++ b/resources/test_site/module_config.json @@ -108,7 +108,7 @@ }, "connection.network.communication_type": { "category": "Communication", - "required": "info", + "required": "pass", "expected": "Required Pass" }, "connection.network.communication_min_send": { From 6df102590610bbd3d91beec16b66a874e7fb1b36 Mon Sep 17 00:00:00 2001 From: Noureddine Date: Mon, 4 Jan 2021 08:50:11 +0000 Subject: [PATCH 211/212] Remove accidentally included files --- daq/testpy | 39 --------------------------------------- 1 file changed, 39 deletions(-) delete mode 100644 daq/testpy diff --git a/daq/testpy b/daq/testpy deleted file mode 100644 index 6a8478f522..0000000000 --- a/daq/testpy +++ /dev/null @@ -1,39 +0,0 @@ -arr1 = [[1,2,3],[4,5,6],[7,8,9]] -print(arr1) - -def jj(tt): - return '/'.join(str(v) for v in tt) - -#newlist=list(map(jj,arr1)) -newlist=list(map(lambda results:'/'.join(str(v) for v in results), arr1)) -print(newlist) - -colheader=["one","two","three","four"] -print(["a", "b"] + colheader) - -#PREPOPULATE OUTPU -blank= [[0,0,0] for _ in range(len(colheader))] -print(blank) -blank[2][2] = 7 -print(blank) -print(list(map(jj,blank))) - -result="skipa" - -if result in ["pass", "skip"]: - print("yes") - -result = "n/a" -for i in range(1,5): - cur = "pass" if i == 1 else cur - cur = "pass" if i == 2 else cur - cur = "pass" if i == 3 else cur - cur = "pass" if i == 4 else cur - cur = "pass" if i == 5 else cur - - if result not in ("n/a", cur, 'info'): - result = "fail" - else: - result = cur - -print(result) \ No newline at end of file From bd039bc8ee73cd31d0fe491571f15cf14d29e0bb Mon Sep 17 00:00:00 2001 From: noursaidi Date: Mon, 4 Jan 2021 10:40:41 +0000 Subject: [PATCH 212/212] sticklr fix --- subset/bacnet/bacnetTests/src/main/java/VersionTest.java | 2 +- subset/network/network_tests.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/subset/bacnet/bacnetTests/src/main/java/VersionTest.java b/subset/bacnet/bacnetTests/src/main/java/VersionTest.java index 217e2dfdd5..b21a234450 100644 --- a/subset/bacnet/bacnetTests/src/main/java/VersionTest.java +++ b/subset/bacnet/bacnetTests/src/main/java/VersionTest.java @@ -136,7 +136,7 @@ private void generateReport(String deviceMacAddress) { Report report = new Report("tmp/BacnetVersionTestReport.txt"); Report appendices = new Report("tmp/BacnetVersionTest_APPENDIX.txt"); if (bacnetSupported && testPassed) { - report.writeReport(passReportText + protocolVersionText); + report.writeReport(passReportText + protocolVersionText); } else { report.writeReport(skippedReportText); } diff --git a/subset/network/network_tests.py b/subset/network/network_tests.py index 8249b01a03..b2dcf530c6 100644 --- a/subset/network/network_tests.py +++ b/subset/network/network_tests.py @@ -210,7 +210,6 @@ def test_communication_type_broadcast(): add_summary("Unicast packets received.") add_packet_count_to_report("Unicast", unicast_packets) - return test_result