diff --git a/netops_demo/Makefile b/netops_demo/Makefile index e2b5e9d..c639653 100644 --- a/netops_demo/Makefile +++ b/netops_demo/Makefile @@ -1,12 +1,18 @@ NETOPS_TAG := $(if $(NETOPS_TAG),$(NETOPS_TAG),latest) NETOPS_REGISTRY_URL := $(if $(NETOPS_REGISTRY_URL),$(NETOPS_REGISTRY_URL),iguaziodocker) +MODEL_FILE := $(if $(MODEL_FILE), $(MODEL_FILE),/tmp/model/netops.model) +MODEL_LOCATION_URL := $(if $(MODEL_LOCATION_URL), $(MODEL_LOCATION_URL),http://192.168.224.49:8081/1/netops.model) .PHONY: default default: golang py .PHONY: py py: - cd py && docker build . -t netops-demo-py:$(NETOPS_TAG) + cd py && docker build \ + --tag netops-demo-py:$(NETOPS_TAG) \ + --build-arg MODEL_FILE=$(MODEL_FILE) \ + --build-arg MODEL_LOCATION_URL=$(MODEL_LOCATION_URL) \ + . .PHONY: golang golang: diff --git a/netops_demo/README.md b/netops_demo/README.md index 510cfa4..b8486e3 100644 --- a/netops_demo/README.md +++ b/netops_demo/README.md @@ -6,7 +6,7 @@ This demo generates network data and detects, predicts and visualizes anomalies. 3. Nuclio functions that generate and ingest historical and real-time metric samples into the Iguazio TSDB and Anodot 4. Grafana for visualization of metrics -Setting up an Iguazio system including Grafana and Nuclio is out of the scope of this document. +Setting up an Iguazio system including Grafana and Nuclio is out of the scope of this document. ## Deploying and running the demo @@ -20,7 +20,7 @@ helm install v3io-demo/netops \ --set ingest.tsdb.path ``` -> Note: To ingest into Anodot, add `--set ingest.anodot.token ` to the above. +> Note: To ingest into Anodot, add `--set ingest.anodot.token ` to the above. The demo is configured with defaults, as can be found in the values.yaml (#REF). You can download and modify these settings and pass `--values ` rather than the `--set` arguments above. The generator is configured through a Kubernetes configmap, so it comes up configured. All we need to do is start the generation, including a day of historical data: @@ -75,6 +75,15 @@ nuctl deploy --run-image iguaziodocker/netops-demo-py:0.0.5 \ --triggers '{"periodic": {"kind": "cron", "workerAllocatorName": "defaultHTTPWorkerAllocator", "attributes": {"interval": "1s"}}}' \ --platform-config '{"attributes": {"network":"netops"}}' \ netops-demo-generate + +nuctl deploy --run-image iguaziodocker/netops-demo-py:0.0.5 \ + --runtime python:3.6 \ + --handler functions.predict.predict:predict \ + --readiness-timeout 10 \ + --platform local \ + --triggers '{"periodic": {"kind": "cron", "workerAllocatorName": "defaultHTTPWorkerAllocator", "attributes": {"interval": "1m"}}}' \ + --platform-config '{"attributes": {"network":"netops"}}' \ + netops-demo-predict ``` You can choose to follow the logs by running `docker logs -f default-`, for example: @@ -157,6 +166,22 @@ We can now start the generation: http localhost:/start ``` +By default, the predict function is idling - waiting for configuration. Let's configure it by POSTing the following configuration to `/configure`: +``` +echo ' +{ + 'metrics': , + 'tsdb': , + 'state': 'predicting', + 'target': "function:netops-demo-ingest" +} +' | http localhost:/configure +``` +We can now start predicting: + +```sh +http localhost:/start +``` ## Developing ### Python (Pycharm) @@ -184,11 +209,10 @@ Modify the source code and build the images: NETOPS_TAG=latest make ``` -This will output `netops-demo-golang:latest` and `netops-demo-py:latest` using Nuclio's ability to [build function images from Dockerfiles](https://github.com/nuclio/nuclio/blob/master/docs/tasks/deploy-functions-from-dockerfile.md). -> The `golang` image contains the `ingest` and `query` functions. The `py` image contains the `generate` and `train` functions. By bunching together a few functions inside a single image we allow for easily sharing code without worrying about versioning, reducing the number of moving parts, etc. +This will output `netops-demo-golang:latest` and `netops-demo-py:latest` using Nuclio's ability to [build function images from Dockerfiles](https://github.com/nuclio/nuclio/blob/master/docs/tasks/deploy-functions-from-dockerfile.md). +> The `golang` image contains the `ingest` and `query` functions. The `py` image contains the `generate` and `train` functions. By bunching together a few functions inside a single image we allow for easily sharing code without worrying about versioning, reducing the number of moving parts, etc. Push the images to your favorite Docker registry: ``` NETOPS_TAG=latest NETOPS_REGISTRY_URL=mydockerhubaccount make push ``` - diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/nuclio/logger.a b/netops_demo/golang/pkg/darwin_amd64/github.com/nuclio/logger.a new file mode 100644 index 0000000..66fb789 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/nuclio/logger.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/nuclio/nuclio-sdk-go.a b/netops_demo/golang/pkg/darwin_amd64/github.com/nuclio/nuclio-sdk-go.a new file mode 100644 index 0000000..8e8e1d9 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/nuclio/nuclio-sdk-go.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/functions/ingest.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/functions/ingest.a new file mode 100644 index 0000000..f0f8ad8 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/functions/ingest.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/functions/ingest/anodot.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/functions/ingest/anodot.a new file mode 100644 index 0000000..bbd7db5 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/functions/ingest/anodot.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/cespare/xxhash.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/cespare/xxhash.a new file mode 100644 index 0000000..9c04677 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/cespare/xxhash.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/ghodss/yaml.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/ghodss/yaml.a new file mode 100644 index 0000000..3b9e16b Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/ghodss/yaml.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/nuclio-test-go.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/nuclio-test-go.a new file mode 100644 index 0000000..d9dc97d Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/nuclio-test-go.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap.a new file mode 100644 index 0000000..8bb6ac6 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/github.com/mgutz/ansi.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/github.com/mgutz/ansi.a new file mode 100644 index 0000000..69d5313 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/github.com/mgutz/ansi.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/github.com/pavius/zap.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/github.com/pavius/zap.a new file mode 100644 index 0000000..e113690 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/github.com/pavius/zap.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/github.com/pavius/zap/buffer.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/github.com/pavius/zap/buffer.a new file mode 100644 index 0000000..7d05c3c Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/github.com/pavius/zap/buffer.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/github.com/pavius/zap/internal/bufferpool.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/github.com/pavius/zap/internal/bufferpool.a new file mode 100644 index 0000000..87af6a5 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/github.com/pavius/zap/internal/bufferpool.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/github.com/pavius/zap/internal/color.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/github.com/pavius/zap/internal/color.a new file mode 100644 index 0000000..6390494 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/github.com/pavius/zap/internal/color.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/github.com/pavius/zap/internal/exit.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/github.com/pavius/zap/internal/exit.a new file mode 100644 index 0000000..d78e6b2 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/github.com/pavius/zap/internal/exit.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/github.com/pavius/zap/zapcore.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/github.com/pavius/zap/zapcore.a new file mode 100644 index 0000000..3c36dbf Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/github.com/pavius/zap/zapcore.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/github.com/pkg/errors.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/github.com/pkg/errors.a new file mode 100644 index 0000000..de3ce2b Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/github.com/pkg/errors.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/go.uber.org/atomic.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/go.uber.org/atomic.a new file mode 100644 index 0000000..d00425e Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/go.uber.org/atomic.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/go.uber.org/multierr.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/go.uber.org/multierr.a new file mode 100644 index 0000000..05580c3 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/nuclio/zap/vendor/go.uber.org/multierr.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/pkg/errors.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/pkg/errors.a new file mode 100644 index 0000000..9eea69c Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/pkg/errors.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/stretchr/testify/assert.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/stretchr/testify/assert.a new file mode 100644 index 0000000..6515f0a Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/stretchr/testify/assert.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/stretchr/testify/require.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/stretchr/testify/require.a new file mode 100644 index 0000000..f659ce2 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/stretchr/testify/require.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/stretchr/testify/suite.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/stretchr/testify/suite.a new file mode 100644 index 0000000..c85b9b4 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/stretchr/testify/suite.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew.a new file mode 100644 index 0000000..25e4216 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/difflib.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/difflib.a new file mode 100644 index 0000000..ff38259 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/difflib.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/v3io/v3io-tsdb/pkg/aggregate.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/v3io/v3io-tsdb/pkg/aggregate.a new file mode 100644 index 0000000..df5cb5c Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/v3io/v3io-tsdb/pkg/aggregate.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/v3io/v3io-tsdb/pkg/appender.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/v3io/v3io-tsdb/pkg/appender.a new file mode 100644 index 0000000..064e528 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/v3io/v3io-tsdb/pkg/appender.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/v3io/v3io-tsdb/pkg/chunkenc.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/v3io/v3io-tsdb/pkg/chunkenc.a new file mode 100644 index 0000000..20c8ae6 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/v3io/v3io-tsdb/pkg/chunkenc.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/v3io/v3io-tsdb/pkg/config.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/v3io/v3io-tsdb/pkg/config.a new file mode 100644 index 0000000..6235830 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/v3io/v3io-tsdb/pkg/config.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/v3io/v3io-tsdb/pkg/partmgr.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/v3io/v3io-tsdb/pkg/partmgr.a new file mode 100644 index 0000000..522a322 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/v3io/v3io-tsdb/pkg/partmgr.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/v3io/v3io-tsdb/pkg/querier.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/v3io/v3io-tsdb/pkg/querier.a new file mode 100644 index 0000000..861ec42 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/v3io/v3io-tsdb/pkg/querier.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/v3io/v3io-tsdb/pkg/tsdb.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/v3io/v3io-tsdb/pkg/tsdb.a new file mode 100644 index 0000000..0cd021e Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/v3io/v3io-tsdb/pkg/tsdb.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/v3io/v3io-tsdb/pkg/utils.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/v3io/v3io-tsdb/pkg/utils.a new file mode 100644 index 0000000..4061f51 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/github.com/v3io/v3io-tsdb/pkg/utils.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/golang.org/x/net/context.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/golang.org/x/net/context.a new file mode 100644 index 0000000..5be1e7e Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/golang.org/x/net/context.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/golang.org/x/sync/errgroup.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/golang.org/x/sync/errgroup.a new file mode 100644 index 0000000..eff6306 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/golang.org/x/sync/errgroup.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/gopkg.in/yaml.v2.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/gopkg.in/yaml.v2.a new file mode 100644 index 0000000..3f4da25 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/demos/vendor/gopkg.in/yaml.v2.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http.a new file mode 100644 index 0000000..40103e7 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http/vendor/github.com/klauspost/compress/flate.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http/vendor/github.com/klauspost/compress/flate.a new file mode 100644 index 0000000..a9e5006 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http/vendor/github.com/klauspost/compress/flate.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http/vendor/github.com/klauspost/compress/gzip.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http/vendor/github.com/klauspost/compress/gzip.a new file mode 100644 index 0000000..7872cbf Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http/vendor/github.com/klauspost/compress/gzip.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http/vendor/github.com/klauspost/compress/zlib.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http/vendor/github.com/klauspost/compress/zlib.a new file mode 100644 index 0000000..3096348 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http/vendor/github.com/klauspost/compress/zlib.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http/vendor/github.com/klauspost/cpuid.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http/vendor/github.com/klauspost/cpuid.a new file mode 100644 index 0000000..2cea920 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http/vendor/github.com/klauspost/cpuid.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http/vendor/github.com/pkg/errors.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http/vendor/github.com/pkg/errors.a new file mode 100644 index 0000000..933a163 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http/vendor/github.com/pkg/errors.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http/vendor/github.com/valyala/bytebufferpool.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http/vendor/github.com/valyala/bytebufferpool.a new file mode 100644 index 0000000..7d45083 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http/vendor/github.com/valyala/bytebufferpool.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http/vendor/github.com/valyala/fasthttp.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http/vendor/github.com/valyala/fasthttp.a new file mode 100644 index 0000000..d32f528 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http/vendor/github.com/valyala/fasthttp.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http/vendor/github.com/valyala/fasthttp/fasthttputil.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http/vendor/github.com/valyala/fasthttp/fasthttputil.a new file mode 100644 index 0000000..1425464 Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http/vendor/github.com/valyala/fasthttp/fasthttputil.a differ diff --git a/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http/vendor/github.com/valyala/fasthttp/stackless.a b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http/vendor/github.com/valyala/fasthttp/stackless.a new file mode 100644 index 0000000..e272cee Binary files /dev/null and b/netops_demo/golang/pkg/darwin_amd64/github.com/v3io/v3io-go-http/vendor/github.com/valyala/fasthttp/stackless.a differ diff --git a/netops_demo/golang/src/github.com/nuclio/logger b/netops_demo/golang/src/github.com/nuclio/logger new file mode 160000 index 0000000..ccc5ab9 --- /dev/null +++ b/netops_demo/golang/src/github.com/nuclio/logger @@ -0,0 +1 @@ +Subproject commit ccc5ab971395c6eae9a743a678d7b1bcb8e70414 diff --git a/netops_demo/golang/src/github.com/nuclio/nuclio-sdk-go b/netops_demo/golang/src/github.com/nuclio/nuclio-sdk-go new file mode 160000 index 0000000..f750b95 --- /dev/null +++ b/netops_demo/golang/src/github.com/nuclio/nuclio-sdk-go @@ -0,0 +1 @@ +Subproject commit f750b959d2f7ebec6ebd4bc6b5638307406a5888 diff --git a/netops_demo/golang/src/github.com/v3io/demos/Dockerfile b/netops_demo/golang/src/github.com/v3io/demos/Dockerfile index 0da7224..7d20fda 100644 --- a/netops_demo/golang/src/github.com/v3io/demos/Dockerfile +++ b/netops_demo/golang/src/github.com/v3io/demos/Dockerfile @@ -25,3 +25,4 @@ HEALTHCHECK --interval=1s --timeout=3s CMD /usr/local/bin/uhttpc --url http://12 # Run processor with configuration and platform configuration CMD [ "processor", "--config", "/etc/nuclio/config/processor/processor.yaml", "--platform-config", "/etc/nuclio/config/platform/platform.yaml" ] + diff --git a/netops_demo/golang/src/github.com/v3io/demos/functions/ingest/anodot/appender.go b/netops_demo/golang/src/github.com/v3io/demos/functions/ingest/anodot/appender.go index 98e669f..88add28 100644 --- a/netops_demo/golang/src/github.com/v3io/demos/functions/ingest/anodot/appender.go +++ b/netops_demo/golang/src/github.com/v3io/demos/functions/ingest/anodot/appender.go @@ -1,26 +1,26 @@ package anodot import ( - "net/http" - "time" - "fmt" - "encoding/json" "bytes" + "encoding/json" + "fmt" "io/ioutil" + "net/http" + "time" "github.com/nuclio/logger" ) type Metric struct { Properties map[string]interface{} `json:"properties,omitempty"` - Tags map[string]interface{} `json:"tags,omitempty"` - Timestamp uint64 `json:"timestamp,omitempty"` - Value float64 `json:"value,omitempty"` + Tags map[string]interface{} `json:"tags,omitempty"` + Timestamp uint64 `json:"timestamp,omitempty"` + Value float64 `json:"value,omitempty"` } type Appender struct { - logger logger.Logger - httpClient *http.Client + logger logger.Logger + httpClient *http.Client appendEndpoint string } diff --git a/netops_demo/golang/src/github.com/v3io/demos/functions/ingest/ingest.go b/netops_demo/golang/src/github.com/v3io/demos/functions/ingest/ingest.go index 0be906c..062a832 100644 --- a/netops_demo/golang/src/github.com/v3io/demos/functions/ingest/ingest.go +++ b/netops_demo/golang/src/github.com/v3io/demos/functions/ingest/ingest.go @@ -2,11 +2,12 @@ package ingest import ( "encoding/json" - "os" - "sync" "fmt" - "sort" "golang.org/x/sync/errgroup" + "os" + "sort" + "strconv" + "sync" "github.com/v3io/demos/functions/ingest/anodot" @@ -29,13 +30,14 @@ type metricSamples struct { } type emitter struct { - Labels map[string]interface{} `json:"labels,omitempty"` + Labels map[string]interface{} `json:"labels,omitempty"` Metrics map[string]*metricSamples `json:"metrics,omitempty"` } type userData struct { tsdbAppender tsdb.Appender anodotAppender *anodot.Appender + kvAppender *v3io.Container } func Ingest(context *nuclio.Context, event nuclio.Event) (interface{}, error) { @@ -63,7 +65,6 @@ func Ingest(context *nuclio.Context, event nuclio.Event) (interface{}, error) { } } - return nil, nil } @@ -74,11 +75,13 @@ func InitContext(context *nuclio.Context) error { // get configuration from env tsdbAppenderPath := os.Getenv("INGEST_V3IO_TSDB_PATH") + kvAppenderPath := os.Getenv("INGEST_V3IO_KV_PATH") anodotAppenderURL := os.Getenv("INGEST_ANODOT_URL") anodotAppenderToken := os.Getenv("INGEST_ANODOT_TOKEN") context.Logger.InfoWith("Initializing", "tsdbAppenderPath", tsdbAppenderPath, + "kvAppenderPath", kvAppenderPath, "anodotAppenderURL", anodotAppenderURL, "anodotAppenderToken", anodotAppenderToken) @@ -100,6 +103,10 @@ func InitContext(context *nuclio.Context) error { } } + if kvAppenderPath != "" { + userData.kvAppender = context.DataBinding["db0"].(*v3io.Container) + } + // set user data into the context context.UserData = &userData @@ -176,6 +183,13 @@ func ingestMetricSamples(context *nuclio.Context, }) } + // TODO: Ingest into KV + if userData.kvAppender != nil { + ingestErrGroup.Go(func() error { + return ingestMetricSamplesToKV(context, userData.kvAppender, emitterLabels, metricName, samples) + }) + } + // wait and return composite error return ingestErrGroup.Wait() } @@ -196,7 +210,7 @@ func ingestMetricSamplesToTSDB(context *nuclio.Context, // iterate over label source and copy over for labelKey, labelValue := range labelSource { labels = append(labels, utils.Label{ - Name: labelKey, + Name: labelKey, Value: fmt.Sprintf("%v", labelValue), }) } @@ -227,6 +241,55 @@ func ingestMetricSamplesToTSDB(context *nuclio.Context, return nil } +func ingestMetricSamplesToKV(context *nuclio.Context, + kvContainer *v3io.Container, + emitterLabels map[string]interface{}, + metricName string, + samples *metricSamples) error { + + baseKVPath := os.Getenv("INGEST_V3IO_KV_PATH") + metricPath := baseKVPath + "/" + metricName + responseChannel := make(chan *v3io.Response, 1) // Only one response per PutItems + + items := make(map[string]map[string]interface{}, len(samples.Timestamps)) + for index, timestamp := range samples.Timestamps { + key := strconv.FormatInt(timestamp, 10) + "_" + emitterLabels["device"].(string) + items [key] = map[string]interface{}{ + string("timestamp"): string(timestamp), + string("alert"): string(samples.Alerts[index]), + string("IsError"): int(samples.IsError[index]), + } + for k, v := range emitterLabels { + items [key][k] = v + } + } + + // TODO: Why Emitter Labels doesn't hold device ID? Only company name / site + _, PutItemErr := kvContainer.PutItems(&v3io.PutItemsInput{ + Path: metricPath, + Items: items}, + context, + responseChannel) + + if PutItemErr != nil { + context.Logger.ErrorWith("Failed to put kv alert", "err", PutItemErr) + } + + resp := <-responseChannel + if resp.Error != nil { + context.Logger.ErrorWith("Failed to put kv alert", "err", resp.Error) + } + + output := resp.Output.(*v3io.PutItemsOutput) + if !output.Success { + for key, error := range output.Errors { + context.Logger.ErrorWith("Failed to put kv alert: Key:", key, "Error:", error) + } + } + + return nil +} + func ingestMetricSamplesToAnodot(context *nuclio.Context, anodotAppender *anodot.Appender, emitterLabels map[string]interface{}, @@ -241,8 +304,8 @@ func ingestMetricSamplesToAnodot(context *nuclio.Context, for sampleIndex := 0; sampleIndex < len(samples.Timestamps); sampleIndex++ { metrics = append(metrics, &anodot.Metric{ Properties: samples.Labels, - Timestamp: uint64(samples.Timestamps[sampleIndex]), - Value: samples.Values[sampleIndex], + Timestamp: uint64(samples.Timestamps[sampleIndex]), + Value: samples.Values[sampleIndex], }) } diff --git a/netops_demo/golang/src/github.com/v3io/demos/functions/ingest/ingest_test.go b/netops_demo/golang/src/github.com/v3io/demos/functions/ingest/ingest_test.go index 7e7b824..45e491e 100644 --- a/netops_demo/golang/src/github.com/v3io/demos/functions/ingest/ingest_test.go +++ b/netops_demo/golang/src/github.com/v3io/demos/functions/ingest/ingest_test.go @@ -39,7 +39,8 @@ func (suite *ingestSuite) TestIngestValid() { "longitude": 51.4990232516124, "latitute": -0.16853921733979035, "company_name": "Wong Ltd", - "site_name": "Wong Ltd/0" + "site_name": "Wong Ltd/0", + "device": "Wong Ltd/0/0" }, "metrics": { "cpu_utilization": { @@ -87,7 +88,8 @@ func (suite *ingestSuite) TestIngestValid() { "longitude": 51.4990232516124, "latitute": -0.16853921733979035, "company_name": "Wong Ltd", - "site_name": "Wong Ltd/0" + "site_name": "Wong Ltd/0", + "device": "Wong Ltd/0/1" }, "metrics": { "cpu_utilization": { @@ -135,7 +137,8 @@ func (suite *ingestSuite) TestIngestValid() { "longitude": 51.4990232516124, "latitute": -0.16853921733979035, "company_name": "Wong Ltd", - "site_name": "Wong Ltd/0" + "site_name": "Wong Ltd/0", + "device": "Wong Ltd/0/2" }, "metrics": { "cpu_utilization": { @@ -183,7 +186,8 @@ func (suite *ingestSuite) TestIngestValid() { "longitude": 51.4990232516124, "latitute": -0.16853921733979035, "company_name": "Wong Ltd", - "site_name": "Wong Ltd/0" + "site_name": "Wong Ltd/0", + "device": "Wong Ltd/0/3" }, "metrics": { "cpu_utilization": { @@ -231,7 +235,8 @@ func (suite *ingestSuite) TestIngestValid() { "longitude": 51.4990232516124, "latitute": -0.16853921733979035, "company_name": "Wong Ltd", - "site_name": "Wong Ltd/0" + "site_name": "Wong Ltd/0", + "device": "Wong Ltd/0/4" }, "metrics": { "cpu_utilization": { @@ -279,7 +284,8 @@ func (suite *ingestSuite) TestIngestValid() { "longitude": 51.518019501496426, "latitute": -0.09269391832986805, "company_name": "Wong Ltd", - "site_name": "Wong Ltd/1" + "site_name": "Wong Ltd/1", + "device": "Wong Ltd/1/0" }, "metrics": { "cpu_utilization": { @@ -327,7 +333,8 @@ func (suite *ingestSuite) TestIngestValid() { "longitude": 51.518019501496426, "latitute": -0.09269391832986805, "company_name": "Wong Ltd", - "site_name": "Wong Ltd/1" + "site_name": "Wong Ltd/1", + "device": "Wong Ltd/1/1" }, "metrics": { "cpu_utilization": { @@ -375,7 +382,8 @@ func (suite *ingestSuite) TestIngestValid() { "longitude": 51.518019501496426, "latitute": -0.09269391832986805, "company_name": "Wong Ltd", - "site_name": "Wong Ltd/1" + "site_name": "Wong Ltd/1", + "device": "Wong Ltd/1/2" }, "metrics": { "cpu_utilization": { @@ -423,7 +431,8 @@ func (suite *ingestSuite) TestIngestValid() { "longitude": 51.518019501496426, "latitute": -0.09269391832986805, "company_name": "Wong Ltd", - "site_name": "Wong Ltd/1" + "site_name": "Wong Ltd/1", + "device": "Wong Ltd/1/3" }, "metrics": { "cpu_utilization": { @@ -471,7 +480,8 @@ func (suite *ingestSuite) TestIngestValid() { "longitude": 51.518019501496426, "latitute": -0.09269391832986805, "company_name": "Wong Ltd", - "site_name": "Wong Ltd/1" + "site_name": "Wong Ltd/1", + "device": "Wong Ltd/1/4" }, "metrics": { "cpu_utilization": { diff --git a/netops_demo/golang/src/github.com/v3io/demos/functions/query/query.go b/netops_demo/golang/src/github.com/v3io/demos/functions/query/query.go new file mode 100644 index 0000000..d6db405 --- /dev/null +++ b/netops_demo/golang/src/github.com/v3io/demos/functions/query/query.go @@ -0,0 +1,93 @@ +package query + +import ( + "bytes" + "encoding/json" + "github.com/nuclio/nuclio-sdk-go" + "github.com/pkg/errors" + "github.com/v3io/v3io-go-http" + "github.com/v3io/v3io-tsdb/pkg/config" + "github.com/v3io/v3io-tsdb/pkg/formatter" + "github.com/v3io/v3io-tsdb/pkg/tsdb" + "github.com/v3io/v3io-tsdb/pkg/utils" + "strings" +) + +// Configuration +var tsdbConfig = ` +path: "pmetric" +` + +type tsdbQuery struct { + Name string + Aggregators []string + Step string + Filter string + From string + To string + Last string +} + +// example query event +const queryEvent = ` +{ + "Name": "cpu", + "Last":"2h" +} +` + +// Note: the user must define the v3io data binding in the nuclio function with path, username, password and name it db0 + +func Handler(context *nuclio.Context, event nuclio.Event) (interface{}, error) { + + query := tsdbQuery{} + err := json.Unmarshal(event.GetBody(), &query) + if err != nil { + return nil, err + } + + // convert string times (unix or RFC3339 or relative like now-2h) to unix milisec times + from, to, step, err := utils.GetTimeFromRange(query.From, query.To, query.Last, query.Step) + if err != nil { + return nil, errors.Wrap(err, "Error parsing query time range") + } + + // Create TSDB Querier + context.Logger.DebugWith("Query", "params", query) + adapter := context.UserData.(*tsdb.V3ioAdapter) + qry, err := adapter.Querier(nil, from, to) + if err != nil { + return nil, errors.Wrap(err, "Failed to initialize Querier") + } + + // Select Query to get back a series set iterator + set, err := qry.Select(query.Name, strings.Join(query.Aggregators, ","), step, query.Filter) + if err != nil { + return nil, errors.Wrap(err, "Select Failed") + } + + // convert SeriesSet to Json (Grafana simpleJson format) + f, err := formatter.NewFormatter("json", nil) + if err != nil { + return nil, errors.Wrap(err, "failed to start json formatter") + } + + var b bytes.Buffer + err = f.Write(&b, set) + + return b.String(), err +} + +// InitContext runs only once when the function runtime starts +func InitContext(context *nuclio.Context) error { + cfg, _ := config.LoadFromData([]byte(tsdbConfig)) + data := context.DataBinding["db0"].(*v3io.Container) + adapter, err := tsdb.NewV3ioAdapter(cfg, data, context.Logger) + if err != nil { + return err + } + + // Store adapter in user cache + context.UserData = adapter + return nil +} diff --git a/netops_demo/golang/src/github.com/v3io/v3io-go-http b/netops_demo/golang/src/github.com/v3io/v3io-go-http new file mode 160000 index 0000000..3c8ba0c --- /dev/null +++ b/netops_demo/golang/src/github.com/v3io/v3io-go-http @@ -0,0 +1 @@ +Subproject commit 3c8ba0ce5ac8a9ffa869b3c835cb695590e62c5c diff --git a/netops_demo/netops.ipynb b/netops_demo/netops.ipynb new file mode 100644 index 0000000..db698ab --- /dev/null +++ b/netops_demo/netops.ipynb @@ -0,0 +1,2204 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Intelligent Management\n", + "\n", + "## Table of content\n", + "\n", + "1.[Introduction](#Introduction) \n", + "2.[Generator](#Generator) \n", + " 2.1.[Metric baseline](#Metric-baseline) \n", + " 2.2.[Location (Deployment-site)](#Location-\\(Deployment-site\\)) \n", + " 2.3.[Company](#Company) \n", + " 2.4.[Deployment](#Deployment) \n", + " 2.5.[Deployment Configuration](#Deployment-Configuration) \n", + " 2.6.[Deployment Example](#Deployment-Example) \n", + "3.[Model Training](#Model-Training) \n", + " 3.1.[Get The Data](#Get-The-Data) \n", + " 3.2.[Transform raw data to Feature Vectors](#Transform-raw-data-to-Feature-Vectors) \n", + " 3.3.[Prepare traning and test datasets](#Prepare-traning-and-test-datasets) \n", + " 3.4.[Train Model](#Train-Model) \n", + " 3.5.[Save Model](#Save-Model) \n", + "4.[Predict](#Predict)\n", + "\n", + "The goal of this demo is to showcase a machine learning based usecase around Fault Prediction for Network Infrastructure.\n", + "\n", + "This use case follows the next steps:\n", + "* Data generation for Hardware Performance metrics\n", + "* Netcool Alarms sent through SMOD when appropriate\n", + "* Join with generated EOS data\n", + "\n", + "* Fault Identification from data Using XGBoost ( Machine Learning )" + ] + }, + { + "cell_type": "code", + "execution_count": 121, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: pandas in /Users/orz/anaconda3/lib/python3.6/site-packages (0.20.3)\n", + "Requirement already satisfied: python-dateutil>=2 in /Users/orz/anaconda3/lib/python3.6/site-packages (from pandas) (2.6.1)\n", + "Requirement already satisfied: pytz>=2011k in /Users/orz/anaconda3/lib/python3.6/site-packages (from pandas) (2017.2)\n", + "Requirement already satisfied: numpy>=1.7.0 in /Users/orz/anaconda3/lib/python3.6/site-packages (from pandas) (1.14.5)\n", + "Requirement already satisfied: six>=1.5 in /Users/orz/anaconda3/lib/python3.6/site-packages (from python-dateutil>=2->pandas) (1.11.0)\n", + "\u001b[33mYou are using pip version 10.0.1, however version 18.1 is available.\n", + "You should consider upgrading via the 'pip install --upgrade pip' command.\u001b[0m\n", + "Requirement already satisfied: xgboost in /Users/orz/anaconda3/lib/python3.6/site-packages (0.81)\n", + "Requirement already satisfied: numpy in /Users/orz/anaconda3/lib/python3.6/site-packages (from xgboost) (1.14.5)\n", + "Requirement already satisfied: scipy in /Users/orz/anaconda3/lib/python3.6/site-packages (from xgboost) (0.19.1)\n", + "\u001b[33mYou are using pip version 10.0.1, however version 18.1 is available.\n", + "You should consider upgrading via the 'pip install --upgrade pip' command.\u001b[0m\n", + "Requirement already satisfied: bokeh in /Users/orz/anaconda3/lib/python3.6/site-packages (0.12.10)\n", + "Requirement already satisfied: six>=1.5.2 in /Users/orz/anaconda3/lib/python3.6/site-packages (from bokeh) (1.11.0)\n", + "Requirement already satisfied: PyYAML>=3.10 in /Users/orz/anaconda3/lib/python3.6/site-packages (from bokeh) (3.12)\n", + "Requirement already satisfied: python-dateutil>=2.1 in /Users/orz/anaconda3/lib/python3.6/site-packages (from bokeh) (2.6.1)\n", + "Requirement already satisfied: Jinja2>=2.7 in /Users/orz/anaconda3/lib/python3.6/site-packages (from bokeh) (2.9.6)\n", + "Requirement already satisfied: numpy>=1.7.1 in /Users/orz/anaconda3/lib/python3.6/site-packages (from bokeh) (1.14.5)\n", + "Requirement already satisfied: tornado>=4.3 in /Users/orz/anaconda3/lib/python3.6/site-packages (from bokeh) (4.5.2)\n", + "Requirement already satisfied: MarkupSafe>=0.23 in /Users/orz/anaconda3/lib/python3.6/site-packages (from Jinja2>=2.7->bokeh) (1.0)\n", + "\u001b[33mYou are using pip version 10.0.1, however version 18.1 is available.\n", + "You should consider upgrading via the 'pip install --upgrade pip' command.\u001b[0m\n", + "Requirement already satisfied: sklearn in /Users/orz/anaconda3/lib/python3.6/site-packages (0.0)\n", + "Requirement already satisfied: scikit-learn in /Users/orz/anaconda3/lib/python3.6/site-packages (from sklearn) (0.20.2)\n", + "Requirement already satisfied: numpy>=1.8.2 in /Users/orz/anaconda3/lib/python3.6/site-packages (from scikit-learn->sklearn) (1.14.5)\n", + "Requirement already satisfied: scipy>=0.13.3 in /Users/orz/anaconda3/lib/python3.6/site-packages (from scikit-learn->sklearn) (0.19.1)\n", + "\u001b[33mYou are using pip version 10.0.1, however version 18.1 is available.\n", + "You should consider upgrading via the 'pip install --upgrade pip' command.\u001b[0m\n", + "Requirement already satisfied: bkzep in /Users/orz/anaconda3/lib/python3.6/site-packages (0.5.0)\n", + "Requirement already satisfied: bokeh>=0.12.7 in /Users/orz/anaconda3/lib/python3.6/site-packages (from bkzep) (0.12.10)\n", + "Requirement already satisfied: six>=1.5.2 in /Users/orz/anaconda3/lib/python3.6/site-packages (from bokeh>=0.12.7->bkzep) (1.11.0)\n", + "Requirement already satisfied: PyYAML>=3.10 in /Users/orz/anaconda3/lib/python3.6/site-packages (from bokeh>=0.12.7->bkzep) (3.12)\n", + "Requirement already satisfied: python-dateutil>=2.1 in /Users/orz/anaconda3/lib/python3.6/site-packages (from bokeh>=0.12.7->bkzep) (2.6.1)\n", + "Requirement already satisfied: Jinja2>=2.7 in /Users/orz/anaconda3/lib/python3.6/site-packages (from bokeh>=0.12.7->bkzep) (2.9.6)\n", + "Requirement already satisfied: numpy>=1.7.1 in /Users/orz/anaconda3/lib/python3.6/site-packages (from bokeh>=0.12.7->bkzep) (1.14.5)\n", + "Requirement already satisfied: tornado>=4.3 in /Users/orz/anaconda3/lib/python3.6/site-packages (from bokeh>=0.12.7->bkzep) (4.5.2)\n", + "Requirement already satisfied: MarkupSafe>=0.23 in /Users/orz/anaconda3/lib/python3.6/site-packages (from Jinja2>=2.7->bokeh>=0.12.7->bkzep) (1.0)\n", + "\u001b[33mYou are using pip version 10.0.1, however version 18.1 is available.\n", + "You should consider upgrading via the 'pip install --upgrade pip' command.\u001b[0m\n" + ] + }, + { + "data": { + "text/html": [ + "\n", + "
\n", + " \n", + " Loading BokehJS ...\n", + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": [ + "\n", + "(function(root) {\n", + " function now() {\n", + " return new Date();\n", + " }\n", + "\n", + " var force = true;\n", + "\n", + " if (typeof (root._bokeh_onload_callbacks) === \"undefined\" || force === true) {\n", + " root._bokeh_onload_callbacks = [];\n", + " root._bokeh_is_loading = undefined;\n", + " }\n", + "\n", + " var JS_MIME_TYPE = 'application/javascript';\n", + " var HTML_MIME_TYPE = 'text/html';\n", + " var EXEC_MIME_TYPE = 'application/vnd.bokehjs_exec.v0+json';\n", + " var CLASS_NAME = 'output_bokeh rendered_html';\n", + "\n", + " /**\n", + " * Render data to the DOM node\n", + " */\n", + " function render(props, node) {\n", + " var script = document.createElement(\"script\");\n", + " node.appendChild(script);\n", + " }\n", + "\n", + " /**\n", + " * Handle when an output is cleared or removed\n", + " */\n", + " function handleClearOutput(event, handle) {\n", + " var cell = handle.cell;\n", + "\n", + " var id = cell.output_area._bokeh_element_id;\n", + " var server_id = cell.output_area._bokeh_server_id;\n", + " // Clean up Bokeh references\n", + " if (id !== undefined) {\n", + " Bokeh.index[id].model.document.clear();\n", + " delete Bokeh.index[id];\n", + " }\n", + "\n", + " if (server_id !== undefined) {\n", + " // Clean up Bokeh references\n", + " var cmd = \"from bokeh.io.state import curstate; print(curstate().uuid_to_server['\" + server_id + \"'].get_sessions()[0].document.roots[0]._id)\";\n", + " cell.notebook.kernel.execute(cmd, {\n", + " iopub: {\n", + " output: function(msg) {\n", + " var element_id = msg.content.text.trim();\n", + " Bokeh.index[element_id].model.document.clear();\n", + " delete Bokeh.index[element_id];\n", + " }\n", + " }\n", + " });\n", + " // Destroy server and session\n", + " var cmd = \"import bokeh.io.notebook as ion; ion.destroy_server('\" + server_id + \"')\";\n", + " cell.notebook.kernel.execute(cmd);\n", + " }\n", + " }\n", + "\n", + " /**\n", + " * Handle when a new output is added\n", + " */\n", + " function handleAddOutput(event, handle) {\n", + " var output_area = handle.output_area;\n", + " var output = handle.output;\n", + "\n", + " // limit handleAddOutput to display_data with EXEC_MIME_TYPE content only\n", + " if ((output.output_type != \"display_data\") || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n", + " return\n", + " }\n", + "\n", + " var toinsert = output_area.element.find(`.${CLASS_NAME.split(' ')[0]}`);\n", + "\n", + " if (output.metadata[EXEC_MIME_TYPE][\"id\"] !== undefined) {\n", + " toinsert[0].firstChild.textContent = output.data[JS_MIME_TYPE];\n", + " // store reference to embed id on output_area\n", + " output_area._bokeh_element_id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n", + " }\n", + " if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n", + " var bk_div = document.createElement(\"div\");\n", + " bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n", + " var script_attrs = bk_div.children[0].attributes;\n", + " for (var i = 0; i < script_attrs.length; i++) {\n", + " toinsert[0].firstChild.setAttribute(script_attrs[i].name, script_attrs[i].value);\n", + " }\n", + " // store reference to server id on output_area\n", + " output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n", + " }\n", + " }\n", + "\n", + " function register_renderer(events, OutputArea) {\n", + "\n", + " function append_mime(data, metadata, element) {\n", + " // create a DOM node to render to\n", + " var toinsert = this.create_output_subarea(\n", + " metadata,\n", + " CLASS_NAME,\n", + " EXEC_MIME_TYPE\n", + " );\n", + " this.keyboard_manager.register_events(toinsert);\n", + " // Render to node\n", + " var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n", + " render(props, toinsert[0]);\n", + " element.append(toinsert);\n", + " return toinsert\n", + " }\n", + "\n", + " /* Handle when an output is cleared or removed */\n", + " events.on('clear_output.CodeCell', handleClearOutput);\n", + " events.on('delete.Cell', handleClearOutput);\n", + "\n", + " /* Handle when a new output is added */\n", + " events.on('output_added.OutputArea', handleAddOutput);\n", + "\n", + " /**\n", + " * Register the mime type and append_mime function with output_area\n", + " */\n", + " OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n", + " /* Is output safe? */\n", + " safe: true,\n", + " /* Index of renderer in `output_area.display_order` */\n", + " index: 0\n", + " });\n", + " }\n", + "\n", + " // register the mime type if in Jupyter Notebook environment and previously unregistered\n", + " if (root.Jupyter !== undefined) {\n", + " var events = require('base/js/events');\n", + " var OutputArea = require('notebook/js/outputarea').OutputArea;\n", + "\n", + " if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n", + " register_renderer(events, OutputArea);\n", + " }\n", + " }\n", + "\n", + " \n", + " if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n", + " root._bokeh_timeout = Date.now() + 5000;\n", + " root._bokeh_failed_load = false;\n", + " }\n", + "\n", + " var NB_LOAD_WARNING = {'data': {'text/html':\n", + " \"
\\n\"+\n", + " \"

\\n\"+\n", + " \"BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \\n\"+\n", + " \"may be due to a slow or bad network connection. Possible fixes:\\n\"+\n", + " \"

\\n\"+\n", + " \"
    \\n\"+\n", + " \"
  • re-rerun `output_notebook()` to attempt to load from CDN again, or
  • \\n\"+\n", + " \"
  • use INLINE resources instead, as so:
  • \\n\"+\n", + " \"
\\n\"+\n", + " \"\\n\"+\n", + " \"from bokeh.resources import INLINE\\n\"+\n", + " \"output_notebook(resources=INLINE)\\n\"+\n", + " \"\\n\"+\n", + " \"
\"}};\n", + "\n", + " function display_loaded() {\n", + " var el = document.getElementById(\"273d85d2-896e-4761-bd9a-e399837c6aa4\");\n", + " if (el != null) {\n", + " el.textContent = \"BokehJS is loading...\";\n", + " }\n", + " if (root.Bokeh !== undefined) {\n", + " if (el != null) {\n", + " el.textContent = \"BokehJS \" + root.Bokeh.version + \" successfully loaded.\";\n", + " }\n", + " } else if (Date.now() < root._bokeh_timeout) {\n", + " setTimeout(display_loaded, 100)\n", + " }\n", + " }\n", + "\n", + "\n", + " function run_callbacks() {\n", + " try {\n", + " root._bokeh_onload_callbacks.forEach(function(callback) { callback() });\n", + " }\n", + " finally {\n", + " delete root._bokeh_onload_callbacks\n", + " }\n", + " console.info(\"Bokeh: all callbacks have finished\");\n", + " }\n", + "\n", + " function load_libs(js_urls, callback) {\n", + " root._bokeh_onload_callbacks.push(callback);\n", + " if (root._bokeh_is_loading > 0) {\n", + " console.log(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n", + " return null;\n", + " }\n", + " if (js_urls == null || js_urls.length === 0) {\n", + " run_callbacks();\n", + " return null;\n", + " }\n", + " console.log(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n", + " root._bokeh_is_loading = js_urls.length;\n", + " for (var i = 0; i < js_urls.length; i++) {\n", + " var url = js_urls[i];\n", + " var s = document.createElement('script');\n", + " s.src = url;\n", + " s.async = false;\n", + " s.onreadystatechange = s.onload = function() {\n", + " root._bokeh_is_loading--;\n", + " if (root._bokeh_is_loading === 0) {\n", + " console.log(\"Bokeh: all BokehJS libraries loaded\");\n", + " run_callbacks()\n", + " }\n", + " };\n", + " s.onerror = function() {\n", + " console.warn(\"failed to load library \" + url);\n", + " };\n", + " console.log(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " document.getElementsByTagName(\"head\")[0].appendChild(s);\n", + " }\n", + " };var element = document.getElementById(\"273d85d2-896e-4761-bd9a-e399837c6aa4\");\n", + " if (element == null) {\n", + " console.log(\"Bokeh: ERROR: autoload.js configured with elementid '273d85d2-896e-4761-bd9a-e399837c6aa4' but no matching script tag was found. \")\n", + " return false;\n", + " }\n", + "\n", + " var js_urls = [\"https://cdn.pydata.org/bokeh/release/bokeh-0.12.10.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.10.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-tables-0.12.10.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-gl-0.12.10.min.js\"];\n", + "\n", + " var inline_js = [\n", + " function(Bokeh) {\n", + " Bokeh.set_log_level(\"info\");\n", + " },\n", + " \n", + " function(Bokeh) {\n", + " \n", + " },\n", + " function(Bokeh) {\n", + " console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-0.12.10.min.css\");\n", + " Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-0.12.10.min.css\");\n", + " console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.10.min.css\");\n", + " Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.10.min.css\");\n", + " console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-tables-0.12.10.min.css\");\n", + " Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-tables-0.12.10.min.css\");\n", + " }\n", + " ];\n", + "\n", + " function run_inline_js() {\n", + " \n", + " if ((root.Bokeh !== undefined) || (force === true)) {\n", + " for (var i = 0; i < inline_js.length; i++) {\n", + " inline_js[i].call(root, root.Bokeh);\n", + " }if (force === true) {\n", + " display_loaded();\n", + " }} else if (Date.now() < root._bokeh_timeout) {\n", + " setTimeout(run_inline_js, 100);\n", + " } else if (!root._bokeh_failed_load) {\n", + " console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n", + " root._bokeh_failed_load = true;\n", + " } else if (force !== true) {\n", + " var cell = $(document.getElementById(\"273d85d2-896e-4761-bd9a-e399837c6aa4\")).parents('.cell').data().cell;\n", + " cell.output_area.append_execute_result(NB_LOAD_WARNING)\n", + " }\n", + "\n", + " }\n", + "\n", + " if (root._bokeh_is_loading === 0) {\n", + " console.log(\"Bokeh: BokehJS loaded, going straight to plotting\");\n", + " run_inline_js();\n", + " } else {\n", + " load_libs(js_urls, function() {\n", + " console.log(\"Bokeh: BokehJS plotting callback run at\", now());\n", + " run_inline_js();\n", + " });\n", + " }\n", + "}(window));" + ], + "application/vnd.bokehjs_load.v0+json": "\n(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n\n if (typeof (root._bokeh_onload_callbacks) === \"undefined\" || force === true) {\n root._bokeh_onload_callbacks = [];\n root._bokeh_is_loading = undefined;\n }\n\n \n\n \n if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n var NB_LOAD_WARNING = {'data': {'text/html':\n \"
\\n\"+\n \"

\\n\"+\n \"BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \\n\"+\n \"may be due to a slow or bad network connection. Possible fixes:\\n\"+\n \"

\\n\"+\n \"
    \\n\"+\n \"
  • re-rerun `output_notebook()` to attempt to load from CDN again, or
  • \\n\"+\n \"
  • use INLINE resources instead, as so:
  • \\n\"+\n \"
\\n\"+\n \"\\n\"+\n \"from bokeh.resources import INLINE\\n\"+\n \"output_notebook(resources=INLINE)\\n\"+\n \"\\n\"+\n \"
\"}};\n\n function display_loaded() {\n var el = document.getElementById(\"273d85d2-896e-4761-bd9a-e399837c6aa4\");\n if (el != null) {\n el.textContent = \"BokehJS is loading...\";\n }\n if (root.Bokeh !== undefined) {\n if (el != null) {\n el.textContent = \"BokehJS \" + root.Bokeh.version + \" successfully loaded.\";\n }\n } else if (Date.now() < root._bokeh_timeout) {\n setTimeout(display_loaded, 100)\n }\n }\n\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) { callback() });\n }\n finally {\n delete root._bokeh_onload_callbacks\n }\n console.info(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(js_urls, callback) {\n root._bokeh_onload_callbacks.push(callback);\n if (root._bokeh_is_loading > 0) {\n console.log(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls == null || js_urls.length === 0) {\n run_callbacks();\n return null;\n }\n console.log(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n root._bokeh_is_loading = js_urls.length;\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n var s = document.createElement('script');\n s.src = url;\n s.async = false;\n s.onreadystatechange = s.onload = function() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.log(\"Bokeh: all BokehJS libraries loaded\");\n run_callbacks()\n }\n };\n s.onerror = function() {\n console.warn(\"failed to load library \" + url);\n };\n console.log(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.getElementsByTagName(\"head\")[0].appendChild(s);\n }\n };var element = document.getElementById(\"273d85d2-896e-4761-bd9a-e399837c6aa4\");\n if (element == null) {\n console.log(\"Bokeh: ERROR: autoload.js configured with elementid '273d85d2-896e-4761-bd9a-e399837c6aa4' but no matching script tag was found. \")\n return false;\n }\n\n var js_urls = [\"https://cdn.pydata.org/bokeh/release/bokeh-0.12.10.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.10.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-tables-0.12.10.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-gl-0.12.10.min.js\"];\n\n var inline_js = [\n function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\n \n function(Bokeh) {\n \n },\n function(Bokeh) {\n console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-0.12.10.min.css\");\n Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-0.12.10.min.css\");\n console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.10.min.css\");\n Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.10.min.css\");\n console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-tables-0.12.10.min.css\");\n Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-tables-0.12.10.min.css\");\n }\n ];\n\n function run_inline_js() {\n \n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }if (force === true) {\n display_loaded();\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n } else if (force !== true) {\n var cell = $(document.getElementById(\"273d85d2-896e-4761-bd9a-e399837c6aa4\")).parents('.cell').data().cell;\n cell.output_area.append_execute_result(NB_LOAD_WARNING)\n }\n\n }\n\n if (root._bokeh_is_loading === 0) {\n console.log(\"Bokeh: BokehJS loaded, going straight to plotting\");\n run_inline_js();\n } else {\n load_libs(js_urls, function() {\n console.log(\"Bokeh: BokehJS plotting callback run at\", now());\n run_inline_js();\n });\n }\n}(window));" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "!pip install pandas\n", + "!pip install xgboost\n", + "!pip install bokeh\n", + "!pip install sklearn\n", + "!pip install bkzep\n", + "\n", + "import scipy as sp\n", + "import numpy as np\n", + "import pandas as pd\n", + "import pickle\n", + "import matplotlib.pyplot as plt; plt.rcdefaults()\n", + "from bokeh.plotting import figure, show\n", + "from bokeh.io import output_notebook\n", + "from bokeh.layouts import column, row, gridplot\n", + "from bokeh.models import ColumnDataSource\n", + "from sklearn.model_selection import train_test_split\n", + "from sklearn.metrics import classification_report\n", + "from sklearn.ensemble import GradientBoostingClassifier\n", + "from sklearn.pipeline import Pipeline\n", + "import os\n", + "import re\n", + "import itertools\n", + "import random\n", + "import bkzep\n", + "import pprint\n", + "import xgboost as xgb\n", + "from xgboost import plot_importance\n", + "output_notebook()\n", + "pp = pprint.PrettyPrinter(indent=4)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Introduction\n", + "\n", + "The goal of this demo is to showcase a machine learning based usecase around Fault Prediction for Network Infrastructure.\n", + "\n", + "This use case follows the next steps:\n", + "\n", + "Data generation for Hardware Performance metrics\n", + "Netcool Alarms sent through SMOD when appropriate\n", + "Join with generated EOS data\n", + "\n", + "Fault Identification from data Using XGBoost ( Machine Learning )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Generator \n", + "### Metric baseline\n", + "[top](#Table-of-content)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "def Normal(mu=0, sigma=0.5, noise=0):\n", + " '''\n", + " The function used to create the actual device performance data\n", + "\n", + " :param mu: Mean of the normal distribution to draw the metric from\n", + " :param sigma: Deviation from the mean of the distribution\n", + " :param noise: Sigma for the noise, (Drawn from distribution of Normal(0, noise)\n", + " :return: Metric\n", + " '''\n", + " # while True:\n", + " added_noise = 0 \n", + " if noise is not 0:\n", + " added_noise = np.random.normal(loc=0, scale=noise, size=1)\n", + " tick = np.random.normal(loc=mu, scale=sigma, size=1) + added_noise\n", + " return tick" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "A sample output from Normal(noise=1): [-0.72290584]\n" + ] + }, + { + "data": { + "text/html": [ + "\n", + "
\n", + "
\n", + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": [ + "(function(root) {\n", + " function embed_document(root) {\n", + " var docs_json = {\"2c6126f8-46fb-43d5-910d-bb1089a7f5fa\":{\"roots\":{\"references\":[{\"attributes\":{\"callback\":null},\"id\":\"94364da2-bb54-4be1-bcd6-28a028f08781\",\"type\":\"DataRange1d\"},{\"attributes\":{},\"id\":\"e77d0b50-7157-419c-a8f2-27a68319f9cc\",\"type\":\"PanTool\"},{\"attributes\":{\"axis_label\":\"ticks\",\"formatter\":{\"id\":\"b72cd2e3-e81e-4b97-ba73-4ac78aa3b11d\",\"type\":\"BasicTickFormatter\"},\"plot\":{\"id\":\"35c221ad-c263-405d-89f1-6c3c7968540e\",\"subtype\":\"Figure\",\"type\":\"Plot\"},\"ticker\":{\"id\":\"63273d3f-275c-417b-97f4-5bdf861e96e2\",\"type\":\"BasicTicker\"}},\"id\":\"e7c6b8e8-b752-484e-a6f0-a0e229c97720\",\"type\":\"LinearAxis\"},{\"attributes\":{},\"id\":\"63273d3f-275c-417b-97f4-5bdf861e96e2\",\"type\":\"BasicTicker\"},{\"attributes\":{\"active_drag\":\"auto\",\"active_inspect\":\"auto\",\"active_scroll\":\"auto\",\"active_tap\":\"auto\",\"tools\":[{\"id\":\"e77d0b50-7157-419c-a8f2-27a68319f9cc\",\"type\":\"PanTool\"},{\"id\":\"d0f5d2e2-1ba6-4567-8310-81241225ac61\",\"type\":\"WheelZoomTool\"},{\"id\":\"71ab4a4a-dea1-40e8-bc6b-4abc79d6d1ff\",\"type\":\"BoxZoomTool\"},{\"id\":\"f14127f5-14e8-4bd1-b1e2-f5675b870046\",\"type\":\"SaveTool\"},{\"id\":\"aedf5de4-2141-464c-acc8-8ab87d2d1c3f\",\"type\":\"ResetTool\"},{\"id\":\"b323dede-650f-4d1b-b19c-bf50471914ef\",\"type\":\"HelpTool\"}]},\"id\":\"2a4a10d0-36da-4730-80f4-b7870aba002b\",\"type\":\"Toolbar\"},{\"attributes\":{},\"id\":\"d0f5d2e2-1ba6-4567-8310-81241225ac61\",\"type\":\"WheelZoomTool\"},{\"attributes\":{\"axis_label\":\"Metric\",\"formatter\":{\"id\":\"c096ca5a-91ba-444c-b998-73af153c43df\",\"type\":\"BasicTickFormatter\"},\"plot\":{\"id\":\"35c221ad-c263-405d-89f1-6c3c7968540e\",\"subtype\":\"Figure\",\"type\":\"Plot\"},\"ticker\":{\"id\":\"25c2c1fc-e148-4bbe-a1d4-a2215ccb4239\",\"type\":\"BasicTicker\"}},\"id\":\"71223f13-e188-4b0b-a3d7-2132380f35c6\",\"type\":\"LinearAxis\"},{\"attributes\":{},\"id\":\"c096ca5a-91ba-444c-b998-73af153c43df\",\"type\":\"BasicTickFormatter\"},{\"attributes\":{\"overlay\":{\"id\":\"c915f18a-b201-4a14-bc16-50c7bda6b6d3\",\"type\":\"BoxAnnotation\"}},\"id\":\"71ab4a4a-dea1-40e8-bc6b-4abc79d6d1ff\",\"type\":\"BoxZoomTool\"},{\"attributes\":{},\"id\":\"25c2c1fc-e148-4bbe-a1d4-a2215ccb4239\",\"type\":\"BasicTicker\"},{\"attributes\":{\"source\":{\"id\":\"b4a7b246-b401-4752-8e20-8de9371694ac\",\"type\":\"ColumnDataSource\"}},\"id\":\"2acddea8-ed9a-4157-b3d5-c7e74f424189\",\"type\":\"CDSView\"},{\"attributes\":{},\"id\":\"f14127f5-14e8-4bd1-b1e2-f5675b870046\",\"type\":\"SaveTool\"},{\"attributes\":{\"dimension\":1,\"plot\":{\"id\":\"35c221ad-c263-405d-89f1-6c3c7968540e\",\"subtype\":\"Figure\",\"type\":\"Plot\"},\"ticker\":{\"id\":\"25c2c1fc-e148-4bbe-a1d4-a2215ccb4239\",\"type\":\"BasicTicker\"}},\"id\":\"f326c8b6-0462-4920-bd27-458bdb91214e\",\"type\":\"Grid\"},{\"attributes\":{\"line_alpha\":{\"value\":0.1},\"line_color\":{\"value\":\"#1f77b4\"},\"x\":{\"field\":\"x\"},\"y\":{\"field\":\"y\"}},\"id\":\"83f1f888-534d-4267-8e59-8e50c24abc3b\",\"type\":\"Line\"},{\"attributes\":{},\"id\":\"aedf5de4-2141-464c-acc8-8ab87d2d1c3f\",\"type\":\"ResetTool\"},{\"attributes\":{\"data_source\":{\"id\":\"b4a7b246-b401-4752-8e20-8de9371694ac\",\"type\":\"ColumnDataSource\"},\"glyph\":{\"id\":\"fdaa133a-aed5-4985-89a5-88c1fb5d9e21\",\"type\":\"Line\"},\"hover_glyph\":null,\"muted_glyph\":null,\"nonselection_glyph\":{\"id\":\"83f1f888-534d-4267-8e59-8e50c24abc3b\",\"type\":\"Line\"},\"selection_glyph\":null,\"view\":{\"id\":\"2acddea8-ed9a-4157-b3d5-c7e74f424189\",\"type\":\"CDSView\"}},\"id\":\"0cc7c841-c62f-42d7-81a5-9b01464212d8\",\"type\":\"GlyphRenderer\"},{\"attributes\":{},\"id\":\"87f69884-20a2-4fc9-8a46-02ef6b19023f\",\"type\":\"LinearScale\"},{\"attributes\":{\"callback\":null,\"column_names\":[\"x\",\"y\"],\"data\":{\"x\":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483,484,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499],\"y\":[{\"__ndarray__\":\"qmAk0l+sMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"JEye2OnjNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"p0SEUFgBM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"3+FZpKnyM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"hoWx9PHrM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"3PX4nzP0MkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"f91/1svbMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"vRgB+/vPNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"HsX4jBx3LkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Tr6pdtLJMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"r9K+MOwpM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"attWxuJHM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"PM4L/J6cKEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"x7XuRhosNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"zh/8BxtROEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"QxiPvlLRMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"zDgmCltuN0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"ydGLNwqVMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"viJ0VV0ZNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"rCa5qAEEM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"LWTtowC+NEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"tXM8jkC6NkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"ZnCtwRpRLkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"VLrSwmQ6NkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"5dQjAPIZNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"yLDkswF9M0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"mkqSj62rNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"z3fm+jUJM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"iA0qcN12MEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"bHLhPtEvM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"WkmIMimFM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"u8V2KanpOEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"HL0coBUMLkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"hijGbEoLNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"y6WEKIbAL0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"A9bFdfLmOEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"gm0NjMsBL0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"XqMENiJoNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"laK/2iziMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"ZQ81EsD9MkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"vQrWEpT0NEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"pNtnpZp8O0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"US6r1oEMMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"5DMfSjj9K0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"cSt3W+qZN0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Pz0SLcKgMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"6uapySNoMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Quqn/kKSNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"G4vZkJqrMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"08bsULJXNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"cEYLrcQdOEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"CtkmytHiK0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"ndHMQRiaM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"5fDmsRcAOUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"bjWzaZ9FMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"vwAf/qccM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"wuOAf3+PMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"/ZUPwAINN0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"CSd4zuRjNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"6LCvWAzDOEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"A0Xo36bwMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"jLwuOziNMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"I5ZG7D/EMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"TsdoKLYfM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Mo5MRiO6OUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"TQ2RR/iuNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"YioJcPbWNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"cavhThM3NkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"izt5FVNdMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"xqw8ZWp0MkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"SmeUkW8hN0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"LEOSLnV8L0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"55b3byMuNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"naCodzKXNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"hti9YthENEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"enchVBKBMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"QPlvksNSNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"eMAOEWxVMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"9CXbHv4zNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"9Mp88R+9MUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"C2WaZ/58M0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"kXiqnexSMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"DMiazed4MkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"oFUo07xkMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"rBGnVwNiMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"5T4y3XxbM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"2jPxt7RRK0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"vTC0pp6oM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"C/mEo3FuMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"AG+cl7R9NUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"rHjBQzikK0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"xnS7JnAXOUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"tGqIXfPMMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"8Yqmdv4COEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"OrZeap9rMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"rjH0zex/NUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"0ikshRwLMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"8ad8siJsNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"CdITd/h6M0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"PDyimGtfNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"jnM+CF63M0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"6LHpBUWxNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"uHWgDimMM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"JRweOuhSMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"f2kVhUEVMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"qpoCo2uGLEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"sLv5zCrrMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"R3LBzcAkNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"xp6hspgVNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"54w4MkIyMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"WispUdp3MEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"WVzH/I3IM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"lqrdymDiNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"kk5hEDHeNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"zvKSNi07MEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Y5GuUao5M0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"mA+MO6JDMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"3XovUcLbN0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"HNkCBEPrM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"2v/zHwsQNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"nH2FhwpqLUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"KkhJIJb+LUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"llxojRloNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"SKN3yxZUMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"siODCJu6MEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"ube+N5OzMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"9bKH30QmNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"7cCDBVAxM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Jgi36IIFNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"y1gy0lrRNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"4+fDqTLUM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Y6O2ToctNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"neeyGrL9LUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"jumYpq5JMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Wnro6cxmM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"v7NDRHSbOEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"mVaiglMZN0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"TJlY7dGKMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"pBZKx1xONUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"2Gv8Bw4vMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"ShJtvk8aOEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"ia7K0UsDNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"IafO39oSM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"q7/YAsfoLkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"e6PRFQBSLkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"LcK4bk6gN0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"5M1xYVxrNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"KZS+y4O3N0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"gzTdwp2YNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"fdGSZXozNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"gykGprvnNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"kpYY6yBgLkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"vuVSBOqnNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Or2JbtvuMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"AoO1XefVNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"QDXBFej+NEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"rohwEnn9MUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"LFkLQPkSNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"RGgA59nbNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"PuC27S3XLkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"KPGDg/DdMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"MV/h0IYvM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"7PXntTgGM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"mFwtZQocNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"SiSU2uR6N0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"n+iwbufUM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"yn+U1soAM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"KZYNmEhvNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"NBkPpbIqMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"h/G/ZQPbNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"ELdji3SROEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"OFxTWMWzMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"t1LS6ZdSOUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"SUWjKptbM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"t+xf01OoNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"FknORCrtNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"XzEDa0EcNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"hjn9sNy9MEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"l8TXmit9M0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"l99nOampM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"hPoIlqhsM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"VU8UdHAOOEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"DmCcXMfxMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"sJsQfzZiNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Jm/AJYwdMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Qp4OnKADNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"hGS1S8bNMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"mvY93tUSMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"kAUmLL7qL0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"l/0l4H5QN0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"NQiKSzZdNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"jmLXfG04MEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"BuTpcGjWNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"JIyOZK1cNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"J7KVnVjJL0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"4ykecGg4NEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"X7/qMCrpNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"1vXiYRMEOUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"eh3PJRZFMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"iVGSPJFhMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"TVLK9o9fM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"MMKdQUhDNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"GvxQplSbMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"RbsOkyrCNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"USVXM++1M0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"cYw8gTtbM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"YpwnZa+jNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"wHxzWkqBNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"oeWNvasyM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"bnBN9zkaMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"93eO+JEQM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"+IQJHCzUMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"lKvVkVfQMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"WOqkPxO2NkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"iwWgM8PIOEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"pZs435JPMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"oJKcEopLNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Ht/+clC2M0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"5Nbf0EPAL0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"V2yJT+fHNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"z9tVwlRKNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"LsA966toMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"OUb4boL+NEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"q4UGaWccNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"SSGM8l8ONEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"kDcQDpvqM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"am9PzRSINUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"UjDAgq0tNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"p9blWDjmOEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"LvV+W4OXMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"ZKKeqrgkNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"T+5XPQokNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"RT4Yy1t5N0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Gzb31E00NEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"9KldcvNSM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"LWYElk8dNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"RaGJI/C6MEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"KXO8H6LDMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Jbk2DwC1MkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"9VNAN5pONEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"/JqrDN/4L0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"YD0bk2FeMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"EzJ/g+ThMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"dxsBVcouMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"KVmYnnA4NUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"+lpfNE//N0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"x3c5ySmfMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"AiGBR87rM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"9h6Y0yE1LEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"f79c0ZChMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"9HxPHTu5M0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"fEZ4E5BvMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"NhER01MVOEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"ELW9vXXFMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"22yC9M8UNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"zq9wtTwhN0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"WjvieUF7L0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Xf50WjZpOEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"oCEb0AeDNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Q+cXaDb7MUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"/4r4bHLMMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"16xGHHXhL0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"meLUC+2RN0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"RYgy3pPtOEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"njlVcfA7L0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"3GXY4kVaNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"tHHqwFdSMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"BTxEZES5NUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"H9KJv45tNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"DzkaYdHINEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Lm6nCHMhMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"2da5KUbiL0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"T0uDo3P8MUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"MsedEwHfNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"02cR/kLKM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"45UmPTl4MUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"jfNIs/aFMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"CuuHf+1+M0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"/a7JBtBEMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"7dPwjLcLNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"dn1lu9d7MkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"QB533k8XN0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"dz3b8mIiMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"dh7ka9NwMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"uyXZq5HDNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"vCe+pBTtOEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"wcdrngJQMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"zlqEkgyiMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"lPH/9bnaNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"qzUwvlKqM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"+nsqgIgNMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"MlKbZg+3MEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"7iZP+H24N0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"aSZYZX0QNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"5cwxEn0XNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"IR2iWGQEMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"AGbbNcf6L0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"hPbyVaCqNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"FlHm7NkZNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"WEXUDRqwO0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"jtybey9CNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"IIyKnfeKNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"ogh1BhByMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"8GV6BiAFMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"q/sbcbIBNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Hy6OfNINNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"BCOsrvk3NUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"0P77PfKGMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"0rBPqtgiOUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"wj1dJZZIO0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"I9jRJbWYMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"vM4QSZ33L0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"+JE1sqohNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"KZthKAt1NUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"91y8YcGbLkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"bGO6wkAmMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"jGmyzGzZNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"VLyblsWbMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"ub4SqRF8MUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"pdInXp/1M0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"E4xHRdINNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"OHI/HWg1OEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"UoabuxQrMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"8Auh51fHNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Vakoun3tNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Xw21C8wmM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"0y9ViXlRMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"u353fT6XNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"uMGC6i0NM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"xIntpCTUNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"x7KBPdo0M0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"SvafjwN9M0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"uLLAroBOL0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"RTRnSNrsMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"nq9N3shOOUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"DrpHNS8KM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Z6BL0tHeM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"+GOY1rZoOEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"v5dAfw75MkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"QTfVHt2sNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"tWaNHL4KOEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"LyVmUH6sMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"G92lhBn9M0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"2aTF9rQrOEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"uo9ow3rnMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"3VAj5HWLNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"wxxJl4euNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"oJ37tIPPNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"abSKk/+ZMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"T9fNs0sZM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"fGGqsKZ1MUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"0HyC4jZdMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"8Fy8Q07fNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"XWJF0qQwMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"hGW2W30KOUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"XJKLqKS0NEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"gL1dcaPWM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"kH50XmC7LUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"9AAFE54hM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"9/9WttiuM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"dOYEEPsgMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"6UGT1kLbNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"rwGf1aU5MkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"0vtE0u4CLkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"KiDpaePYNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"x+zHF4OaM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"XpLrvke5MEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"lKicWn0aM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"F7RigeJ/NUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"jD4rlRfgOEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"UuorITEpMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"HmfvsTgYNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"dytbh/erLkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"BGb2KvlRMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"ERv+M3PmMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"QGeUeKu+MUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"5mDoFMcrOUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"ffmNGTPSNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Xg83ry7JNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"+zsye00fMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"9qxZNG7UMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"PXYSymtmM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"GZHMm71FN0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"KuU38gENNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"fNZWcbTDLkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"KZ/gCwdwOkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"U2kw8s5nK0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"YLi+Mqw7L0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"yY84xZS6M0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"SFg+TAlFNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"VfX3Gn8eMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"mi23P3geMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"ZGRv2s7NN0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"3GJdse1SMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Rxv5oPdlN0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"RKli+IlyO0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"/l9kONx7NUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"HD2JuathOEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"wrw/e+nENUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"duWP+B+bLkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"ehBDMcpuMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"hMgAf71CNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"gSiaZiKlMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"vTXDpD+INkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"ei4WBkl5OEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Kf5gMW88NkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"6u/aKMMSNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"DrzVi9lANEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"WWEqfCArKUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"e0eLJJBCLkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"wKXsJW58MEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"+11R/WXUNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Ea+Wa5NXNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"VkhMvNFxM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"tEwnqzB8MUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Nu/CcZQKNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"zlJSjmnsM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"B93ToDmVM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"mnZKSxHnMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"rs91YNwIMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"hrVwG1PJNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"zOkm84/GNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"nCyhxQ0rNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"pwjnYyiFNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Cod4s4MRM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"BNWTbOFYN0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"hPaj+5nJN0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"NYgw3TJDOUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"F0K+WlMqLkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"9OuqtEB4OEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"TP9bO+RLNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"bRAJchq1LkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"/Sruhyo9M0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"FiQynaXWM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"+9TZDUzCMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"DNDW6gigLUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"/YzMpSzNN0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"UVn/p83vNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"IQGvvkUlM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Sq06ZNdPNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"jbivWyWMN0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Q/rugDdVMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"PtBoCFdxMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"qa+5aKztMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"AKmiVqj0NkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"UIAVMmq0NkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"cJ1Bb9FXM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Rb3ZVE6AN0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"+nKWh3ehMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"CNzr4/AKNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"RhGcL8oWLUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"3bHf2XefOEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"7Ly1XfxONUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"hrVF/PxaMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"XAIBPcIaOUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Qyt9FbH5M0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"T+gmO3dwN0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"7iQaJPfcOEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"0xxb0OmMN0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"O9CGYneeNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"MjSD70bsMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"kBk54BknLEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"C385jbNXM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"OcQb6wsKOkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"2SC+udWlMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"j5c2ZckdNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"iiglkKsNOkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"oGzK1F1nMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"VdgcnWBbMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Nk7pbFzeNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"bLlfiVWYNUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"A9l9LE+VNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"RfJm0R04OUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"hw/PVHYNNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"8r6oFgXDM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"olL8LHBwNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"P9xQig8MNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"THDw5bj1NUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Rgb8gtedN0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"GDFBmAhvMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"oBywj1m5MkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"fjYZzGpkM0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"kzYt/ETiMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"YrZPGvsbNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"tmcjSNCLNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"Tkjg6+cJMUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"NLV0+5EaL0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"NOnYw3aGMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"BJQOhd5hMEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"whxYrPO0M0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"KCkZ7MC9OEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"/E9MKjeTMkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"mj8yzqHFL0A=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"AeIV7k9QNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"SANw9R4/LkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"XDX+Fr0jNkA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"I32Bc7vwNEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"yMppl7oQOEA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"sx749Cv7MUA=\",\"dtype\":\"float64\",\"shape\":[1]},{\"__ndarray__\":\"oLVkuzwuOUA=\",\"dtype\":\"float64\",\"shape\":[1]}]}},\"id\":\"b4a7b246-b401-4752-8e20-8de9371694ac\",\"type\":\"ColumnDataSource\"},{\"attributes\":{\"below\":[{\"id\":\"e7c6b8e8-b752-484e-a6f0-a0e229c97720\",\"type\":\"LinearAxis\"}],\"left\":[{\"id\":\"71223f13-e188-4b0b-a3d7-2132380f35c6\",\"type\":\"LinearAxis\"}],\"plot_width\":1200,\"renderers\":[{\"id\":\"e7c6b8e8-b752-484e-a6f0-a0e229c97720\",\"type\":\"LinearAxis\"},{\"id\":\"5dbbd85e-5fb0-4e09-b053-f1c0a5cf16a5\",\"type\":\"Grid\"},{\"id\":\"71223f13-e188-4b0b-a3d7-2132380f35c6\",\"type\":\"LinearAxis\"},{\"id\":\"f326c8b6-0462-4920-bd27-458bdb91214e\",\"type\":\"Grid\"},{\"id\":\"c915f18a-b201-4a14-bc16-50c7bda6b6d3\",\"type\":\"BoxAnnotation\"},{\"id\":\"80c28318-2e3a-4185-b449-b7a896185e9e\",\"type\":\"Legend\"},{\"id\":\"0cc7c841-c62f-42d7-81a5-9b01464212d8\",\"type\":\"GlyphRenderer\"}],\"title\":{\"id\":\"34174e91-20eb-471d-9c9f-2c666becf69a\",\"type\":\"Title\"},\"toolbar\":{\"id\":\"2a4a10d0-36da-4730-80f4-b7870aba002b\",\"type\":\"Toolbar\"},\"x_range\":{\"id\":\"94364da2-bb54-4be1-bcd6-28a028f08781\",\"type\":\"DataRange1d\"},\"x_scale\":{\"id\":\"87f69884-20a2-4fc9-8a46-02ef6b19023f\",\"type\":\"LinearScale\"},\"y_range\":{\"id\":\"a5d9ef87-2ac0-4ae3-9519-f8c1d4163271\",\"type\":\"DataRange1d\"},\"y_scale\":{\"id\":\"5d67c1d6-bf82-4e6e-a1bd-c4f1366186c4\",\"type\":\"LinearScale\"}},\"id\":\"35c221ad-c263-405d-89f1-6c3c7968540e\",\"subtype\":\"Figure\",\"type\":\"Plot\"},{\"attributes\":{\"line_color\":{\"value\":\"#1f77b4\"},\"x\":{\"field\":\"x\"},\"y\":{\"field\":\"y\"}},\"id\":\"fdaa133a-aed5-4985-89a5-88c1fb5d9e21\",\"type\":\"Line\"},{\"attributes\":{},\"id\":\"b323dede-650f-4d1b-b19c-bf50471914ef\",\"type\":\"HelpTool\"},{\"attributes\":{\"plot\":null,\"text\":\"Sample Performance Generation\"},\"id\":\"34174e91-20eb-471d-9c9f-2c666becf69a\",\"type\":\"Title\"},{\"attributes\":{\"callback\":null},\"id\":\"a5d9ef87-2ac0-4ae3-9519-f8c1d4163271\",\"type\":\"DataRange1d\"},{\"attributes\":{\"items\":[{\"id\":\"7886a05f-2b55-451d-9b78-27a98430bcb0\",\"type\":\"LegendItem\"}],\"plot\":{\"id\":\"35c221ad-c263-405d-89f1-6c3c7968540e\",\"subtype\":\"Figure\",\"type\":\"Plot\"}},\"id\":\"80c28318-2e3a-4185-b449-b7a896185e9e\",\"type\":\"Legend\"},{\"attributes\":{},\"id\":\"5d67c1d6-bf82-4e6e-a1bd-c4f1366186c4\",\"type\":\"LinearScale\"},{\"attributes\":{\"label\":{\"value\":\"Utilization (%)\"},\"renderers\":[{\"id\":\"0cc7c841-c62f-42d7-81a5-9b01464212d8\",\"type\":\"GlyphRenderer\"}]},\"id\":\"7886a05f-2b55-451d-9b78-27a98430bcb0\",\"type\":\"LegendItem\"},{\"attributes\":{},\"id\":\"b72cd2e3-e81e-4b97-ba73-4ac78aa3b11d\",\"type\":\"BasicTickFormatter\"},{\"attributes\":{\"bottom_units\":\"screen\",\"fill_alpha\":{\"value\":0.5},\"fill_color\":{\"value\":\"lightgrey\"},\"left_units\":\"screen\",\"level\":\"overlay\",\"line_alpha\":{\"value\":1.0},\"line_color\":{\"value\":\"black\"},\"line_dash\":[4,4],\"line_width\":{\"value\":2},\"plot\":null,\"render_mode\":\"css\",\"right_units\":\"screen\",\"top_units\":\"screen\"},\"id\":\"c915f18a-b201-4a14-bc16-50c7bda6b6d3\",\"type\":\"BoxAnnotation\"},{\"attributes\":{\"plot\":{\"id\":\"35c221ad-c263-405d-89f1-6c3c7968540e\",\"subtype\":\"Figure\",\"type\":\"Plot\"},\"ticker\":{\"id\":\"63273d3f-275c-417b-97f4-5bdf861e96e2\",\"type\":\"BasicTicker\"}},\"id\":\"5dbbd85e-5fb0-4e09-b053-f1c0a5cf16a5\",\"type\":\"Grid\"}],\"root_ids\":[\"35c221ad-c263-405d-89f1-6c3c7968540e\"]},\"title\":\"Bokeh Application\",\"version\":\"0.12.10\"}};\n", + " var render_items = [{\"docid\":\"2c6126f8-46fb-43d5-910d-bb1089a7f5fa\",\"elementid\":\"1aded3e0-c709-495b-a651-d0570e043576\",\"modelid\":\"35c221ad-c263-405d-89f1-6c3c7968540e\"}];\n", + "\n", + " root.Bokeh.embed.embed_items(docs_json, render_items);\n", + " }\n", + "\n", + " if (root.Bokeh !== undefined) {\n", + " embed_document(root);\n", + " } else {\n", + " var attempts = 0;\n", + " var timer = setInterval(function(root) {\n", + " if (root.Bokeh !== undefined) {\n", + " embed_document(root);\n", + " clearInterval(timer);\n", + " }\n", + " attempts++;\n", + " if (attempts > 100) {\n", + " console.log(\"Bokeh: ERROR: Unable to embed document because BokehJS library is missing\")\n", + " clearInterval(timer);\n", + " }\n", + " }, 10, root)\n", + " }\n", + "})(window);" + ], + "application/vnd.bokehjs_exec.v0+json": "" + }, + "metadata": { + "application/vnd.bokehjs_exec.v0+json": { + "id": "35c221ad-c263-405d-89f1-6c3c7968540e" + } + }, + "output_type": "display_data" + } + ], + "source": [ + "print(f'A sample output from Normal(noise=1): {Normal(noise=1)}')\n", + "\n", + "\n", + "# Showcase a sample of performance generation with Normal base function\n", + "sample_component_performance = list(map(lambda x: Normal(mu=20, sigma=0, noise=3), np.arange(0, 100, 0.2)))\n", + "p = figure(title=\"Sample Performance Generation\",\n", + " x_axis_label=\"ticks\",\n", + " y_axis_label=\"Metric\",\n", + " width=1200)\n", + "p.line(x=range(len(sample_component_performance)), \n", + " y=sample_component_performance, \n", + " legend=\"Utilization (%)\")\n", + "show(p)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "class Metric:\n", + "\n", + " def __init__(self,\n", + " name: str,\n", + " threshold_alerts_dict: dict,\n", + " mu: float,\n", + " sigma: float,\n", + " noise: float,\n", + " max: float,\n", + " min: float):\n", + " '''\n", + "\n", + " :param name: Metric name\n", + " :param threshold_alerts_dict:\n", + " Dictionary of: (Threshold -> Alert)\n", + "\n", + " Note: StatReplace is the Stub to replace for the current generated metric to the log line\n", + " Example:\n", + " - CPU Utilization metric\n", + " - Threshold: 80%\n", + " - Alert: \"Operation - Chassis CPU Utilization (StatReplace) exceed Critical threshold (80.0)\"\n", + " :param mu: Mean of the metric distribution\n", + " :param sigma: Deviation of the metric distribution\n", + " :param noise: Noise added to the metric distribution (As Normal(mu=0, sigma=noise))\n", + " :return:\n", + " '''\n", + "\n", + " self.name = name\n", + " self.mu = mu\n", + " self.sigma = sigma\n", + " self.noise = noise\n", + " self.max = max\n", + " self.min = min\n", + "\n", + " self.alert_threshold = threshold_alerts_dict.get('threshold') if len(threshold_alerts_dict) > 0 else -1\n", + " self.threshold_alerts_dict = threshold_alerts_dict\n", + " self.is_threshold_below = threshold_alerts_dict.get('type') if 'type' in threshold_alerts_dict.keys() else True\n", + "\n", + " self.is_error = False\n", + " self.is_in_peak_error = False\n", + " self.steps = 0\n", + " self.error_length = 80\n", + "\n", + " self.peaks = 0\n", + " self.error_peak_length = 0\n", + " self.peak_chance = 0\n", + " self.r = Random()\n", + " self.r.seed(42)\n", + "\n", + " self.generator_metric = Normal\n", + " self.error_metric = self.Peak_error()\n", + " self.current_metric = self.generator_metric\n", + "\n", + " def Peak_error(self, target_peaks: int = 4, error_peak_ratio: float = 0.5):\n", + " def return_peak():\n", + " return self.max if self.is_threshold_below else self.min\n", + "\n", + " while True:\n", + " # Are we in Pre-Error?\n", + " if self.steps <= self.error_length - self.error_peak_length:\n", + " # Will it peak?\n", + " is_peak = True if self.r.uniform(0, 1) <= self.peak_chance else False\n", + " yield return_peak() if is_peak else self.generator_metric(mu=self.mu,\n", + " sigma=self.sigma,\n", + " noise=self.noise)[0]\n", + "\n", + " # Are we in Peak-Error?\n", + " else:\n", + " self.is_in_peak_error = True\n", + " yield return_peak()\n", + "\n", + " def generator(self):\n", + " '''\n", + " Produces the metric from normal distribution as defined by the user\n", + " :return: One metric sample\n", + " '''\n", + " if self.is_error:\n", + " self.steps += 1\n", + " return next(self.error_metric)\n", + " else:\n", + " return self.generator_metric(mu=self.mu,\n", + " sigma=self.sigma,\n", + " noise=self.noise)[0]\n", + "\n", + " def get_alert(self, metric):\n", + " '''\n", + " Checks weather an alert should be made\n", + " :param metric: Current sample\n", + " :return: A Metric Alert if needed\n", + " '''\n", + " return self.threshold_alerts_dict.get('alert').replace('StatReplace', str(\n", + " metric)) if ((self.is_threshold_below and metric >= self.alert_threshold) or\n", + " (not self.is_threshold_below and metric <= self.alert_threshold)) and \\\n", + " self.alert_threshold is not -1 else ''\n", + "\n", + " def validate_value(self, metric):\n", + " '''\n", + " Validates the metric values are within valid range as defined by min / max\n", + " '''\n", + " # Need to switch to by parameters\n", + " metric = metric if metric > self.min else self.min\n", + " metric = metric if metric < self.max else self.max\n", + " return metric\n", + "\n", + " def start_error(self, error_length: int, target_peaks: int = 4, error_peak_ratio: float = 0.5):\n", + " r = Random()\n", + " r.seed(42)\n", + "\n", + " # Pick one error scenario\n", + " self.error_length = error_length\n", + " self.is_error = True\n", + " self.error_metric = self.Peak_error()\n", + " self.peaks = int(r.gauss(mu=target_peaks, sigma=0.5 * target_peaks))\n", + " self.error_peak_length = int(\n", + " r.gauss(mu=self.error_length * error_peak_ratio, sigma=self.error_length * 0.1))\n", + " self.peak_chance = self.peaks / (self.error_length - self.error_peak_length)\n", + " return 0\n", + "\n", + " def stop_error(self):\n", + " # Return generator to Normal\n", + " self.current_metric = self.generator_metric\n", + " self.is_error = False\n", + " self.is_in_peak_error = False\n", + " self.steps = 0\n", + " self.error_length = 0\n", + " return 0\n", + "\n", + " def get_metric(self):\n", + " while True:\n", + " metric = self.validate_value(self.generator())\n", + " yield {\n", + " 'value': metric,\n", + " 'alert': self.get_alert(metric=metric),\n", + " 'is_error': 1 if self.is_in_peak_error else 0\n", + " }\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "class Device:\n", + "\n", + " def __init__(self, metrics: dict, error_scenarios: [], error_rate: float):\n", + " '''\n", + " Component Manager:\n", + " Receives configuration dictionary and -\n", + " - Creates metrics\n", + " - Runs scenarios\n", + " :param metrics: Configuration dictionary\n", + " '''\n", + " self.metrics = [Metric(name=metric,\n", + " mu=metrics[metric]['metric']['mu'],\n", + " sigma=metrics[metric]['metric']['sigma'],\n", + " noise=metrics[metric]['metric']['noise'],\n", + " max=metrics[metric]['metric']['max'],\n", + " min=metrics[metric]['metric']['min'],\n", + " threshold_alerts_dict=metrics[metric]['alerts']) for metric in metrics.keys()]\n", + "\n", + " self.error_rate = error_rate\n", + " self.error_scenarios = error_scenarios\n", + "\n", + " self.is_error = False\n", + " self.steps = 0\n", + " self.error_length = -1\n", + " self.scenario = []\n", + "\n", + " self.r = Random()\n", + " self.r.seed(42)\n", + "\n", + " def select_error(self):\n", + " '''\n", + " Chooses randomly an error scenario from\n", + " the given scenarios\n", + " :return: an error scenario dict\n", + " '''\n", + " return self.r.choice(self.error_scenarios)\n", + "\n", + " def notify_metric_of_error(self):\n", + " [component.start_error(self.error_length-self.steps) for component in self.metrics\n", + " if self.steps == self.scenario[component.name]]\n", + "\n", + " def notify_metrics_of_normalization(self):\n", + " [component.stop_error() for component in self.metrics]\n", + "\n", + " def generate(self):\n", + " # Initialize state\n", + "\n", + " # Main generator loop\n", + " while True:\n", + " # Check if we are in an error state (Prev or New)\n", + " self.is_error = True if (\n", + " (self.is_error is False) and self.r.uniform(0, 1) <= self.error_rate) else self.is_error\n", + "\n", + " # If we are in error\n", + " if self.is_error:\n", + "\n", + " # If this is the first error step\n", + " if self.steps == 0:\n", + " # Initialize error\n", + " self.scenario = self.select_error()\n", + " self.error_length = int(\n", + " self.r.gauss(mu=self.scenario['length'], sigma=0.1 * self.scenario['length']))\n", + "\n", + " # Do we need to notify a metric to start an error state?\n", + " self.notify_metric_of_error()\n", + "\n", + " # Advance steps\n", + " self.steps += 1\n", + "\n", + " # If we are already in an error state, do we need to stop?\n", + " elif self.steps == self.error_length:\n", + " # Change internal state\n", + " self.is_error = False\n", + " self.steps = 0\n", + " # Notify metrics\n", + " self.notify_metrics_of_normalization()\n", + "\n", + " # Normal in-error step\n", + " else:\n", + " self.notify_metric_of_error()\n", + " self.steps += 1\n", + "\n", + " # If we are not in an error state\n", + " # else:\n", + " yield {component.name: next(component.get_metric()) for component in self.metrics}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Location (Deployment site)\n", + "[top](#Table-of-content)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "from faker.providers import BaseProvider\n", + "from random import Random\n", + "from ast import literal_eval as make_tuple\n", + "\n", + "class LocationProvider(BaseProvider):\n", + " '''\n", + " Creates locations for company deployments within given GPS Coordinates rectangle\n", + " '''\n", + " def location(self, within: dict = {}):\n", + " '''\n", + "\n", + " :param within: GPS rectangle Coordinates containing:\n", + " nw: ()\n", + " se: ()\n", + " :return: GPS Coordinate within the given rectangle\n", + " '''\n", + " nw = make_tuple(within['nw'])\n", + " se = make_tuple(within['se'])\n", + "\n", + " width = abs(nw[1] - se[1])\n", + " height = abs(nw[0] - se[0])\n", + "\n", + " r = Random()\n", + "\n", + " location = (se[0] + r.uniform(0, height), se[1] + r.uniform(0, width))\n", + "\n", + " return location" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Company\n", + "[top](#Table-of-content)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "class Company:\n", + " '''\n", + " Creates a company with locations\n", + " '''\n", + "\n", + " def __init__(self, num_devices: int, num_locations: int, within: dict, metrics: dict, error_scenarios: [],\n", + " error_rate: float):\n", + " # Init\n", + " self.f = Faker('en_US')\n", + " self.f.add_provider(LocationProvider)\n", + "\n", + " # Set parameters\n", + " self.name = self.f.company()\n", + " self.locations = {i:self.f.location(within) for i in range(num_locations)}\n", + " self.devices = [Device(metrics=metrics,\n", + " error_scenarios=error_scenarios,\n", + " error_rate=error_rate) for l in self.locations for d in range(num_devices)]\n", + " self.components = {l: {'location': self.locations[l],\n", + " 'devices': [Device(metrics=metrics,\n", + " error_scenarios=error_scenarios,\n", + " error_rate=error_rate) for d in range(num_devices)]}\n", + " for l in range(num_locations)}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Deployment\n", + "[top](#Table-of-content)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "class Deployment:\n", + "\n", + " def __init__(self, configuration: dict):\n", + " '''\n", + "\n", + " :param locations:\n", + " :param companies:\n", + " :param metrics:\n", + " :param error_scenarios:\n", + " :param error_rate:\n", + " '''\n", + "\n", + " # Init\n", + " deployment_configuration = configuration['deployment']\n", + " self.configuration = configuration\n", + "\n", + " self.companies = [Company(num_devices=deployment_configuration['num_devices_per_site'],\n", + " num_locations=deployment_configuration['num_sites_per_company'],\n", + " within=deployment_configuration['site_locations_bounding_box'],\n", + " metrics=configuration['metrics'],\n", + " error_scenarios=configuration['error_scenarios'],\n", + " error_rate=configuration['error_rate']) for _ in\n", + " range(deployment_configuration['num_companies'])]\n", + "\n", + " def generate(self):\n", + "\n", + " while True:\n", + " tick = {}\n", + "\n", + " for company in self.companies:\n", + " tick[company.name] = {}\n", + " for l, location in enumerate(company.components.values()):\n", + " tick[company.name][l] = {\n", + " 'location': location['location'],\n", + " 'devices': {}\n", + " }\n", + " for d, device in enumerate(location['devices']):\n", + " tick[company.name][l]['devices'][d] = next(device.generate())\n", + "\n", + " yield tick" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Deployment Configuration \n", + "[top](#Table-of-content)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "deplyoment_configuration = {\n", + " \"metrics\": {\n", + " \"cpu_utilization\": {\n", + " \"labels\": {\n", + " \"ver\": 1,\n", + " \"unit\": \"percent\",\n", + " \"target_type\": \"gauge\"\n", + " },\n", + " \"metric\": {\n", + " \"mu\": 75,\n", + " \"sigma\": 4,\n", + " \"noise\": 1,\n", + " \"max\": 100,\n", + " \"min\": 0\n", + " },\n", + " \"alerts\": {\n", + " \"threshold\": 80,\n", + " \"alert\": \"Operation - Chassis CPU Utilization (StatReplace) exceed Critical threshold (80.0)\"\n", + " }\n", + " },\n", + " \"throughput\": {\n", + " \"labels\": {\n", + " \"ver\": 1,\n", + " \"unit\": \"mbyte_sec\",\n", + " \"target_type\": \"gauge\"\n", + " },\n", + " \"metric\": {\n", + " \"mu\": 200,\n", + " \"sigma\": 50,\n", + " \"noise\": 50,\n", + " \"max\": 300,\n", + " \"min\": 0\n", + " },\n", + " \"alerts\": {\n", + " \"threshold\": 30,\n", + " \"alert\": \"Low Throughput (StatReplace) below threshold (3.0)\",\n", + " \"type\": False\n", + " }\n", + " },\n", + " \"latency\": {\n", + " \"labels\": {\n", + " \"ver\": 1,\n", + " \"unit\": \"ms\",\n", + " \"target_type\": \"gauge\"\n", + " },\n", + " \"metric\": {\n", + " \"mu\": 3,\n", + " \"sigma\": 2,\n", + " \"noise\": 1,\n", + " \"max\": 20,\n", + " \"min\": 0\n", + " },\n", + " \"alerts\": {\n", + " \"threshold\": 5,\n", + " \"alert\": \"Latency (StatReplace) above threshold (5.0)\",\n", + " \"type\": True\n", + " }\n", + " },\n", + " \"packet_loss\": {\n", + " \"labels\": {\n", + " \"ver\": 1,\n", + " \"unit\": \"percent\",\n", + " \"target_type\": \"gauge\"\n", + " },\n", + " \"metric\": {\n", + " \"mu\": 3,\n", + " \"sigma\": 2,\n", + " \"noise\": 1,\n", + " \"max\": 100,\n", + " \"min\": 0\n", + " },\n", + " \"alerts\": {\n", + " \"threshold\": 5,\n", + " \"alert\": \"Packet Loss (StatReplace) above threshold (5.0)\",\n", + " \"type\": True\n", + " }\n", + " }\n", + " },\n", + " \"error_scenarios\": [{\n", + " \"cpu_utilization\": 0,\n", + " \"throughput\": 30,\n", + " \"latency\": 50,\n", + " \"packet_loss\": 20,\n", + " \"length\": 80\n", + " }],\n", + " \"errors\": [],\n", + " \"error_rate\": 0.05,\n", + " \"deployment\": {\n", + " \"num_companies\": 3,\n", + " \"num_sites_per_company\": 2,\n", + " \"num_devices_per_site\": 2,\n", + " \"site_locations_bounding_box\": {\n", + " \"nw\": \"(51.520249, -0.071591)\",\n", + " \"se\": \"(51.490988, -0.188702)\"\n", + " }\n", + " }\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Deployment Example\n", + "[top](#Table-of-content)" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[ ( 'Sample 0:',\n", + " { 'Brown Ltd': { 0: { 'devices': { 0: { 'cpu_utilization': { 'alert': 'Operation '\n", + " '- '\n", + " 'Chassis '\n", + " 'CPU '\n", + " 'Utilization '\n", + " '(81.18646858816678) '\n", + " 'exceed '\n", + " 'Critical '\n", + " 'threshold '\n", + " '(80.0)',\n", + " 'is_error': 0,\n", + " 'value': 81.18646858816678},\n", + " 'latency': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 0},\n", + " 'packet_loss': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 3.1348521001937177},\n", + " 'throughput': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 163.5959516897998}},\n", + " 1: { 'cpu_utilization': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 77.18155461707538},\n", + " 'latency': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 3.493042046187642},\n", + " 'packet_loss': { 'alert': 'Packet '\n", + " 'Loss '\n", + " '(5.381050744200107) '\n", + " 'above '\n", + " 'threshold '\n", + " '(5.0)',\n", + " 'is_error': 0,\n", + " 'value': 5.381050744200107},\n", + " 'throughput': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 225.72034009842002}}},\n", + " 'location': ( 51.51462563504477,\n", + " -0.1557846123865522)},\n", + " 1: { 'devices': { 0: { 'cpu_utilization': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 70.31164874809181},\n", + " 'latency': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 1.0283880035247606},\n", + " 'packet_loss': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 2.525384225894885},\n", + " 'throughput': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 221.47783071655547}},\n", + " 1: { 'cpu_utilization': { 'alert': 'Operation '\n", + " '- '\n", + " 'Chassis '\n", + " 'CPU '\n", + " 'Utilization '\n", + " '(80.60192900335751) '\n", + " 'exceed '\n", + " 'Critical '\n", + " 'threshold '\n", + " '(80.0)',\n", + " 'is_error': 0,\n", + " 'value': 80.60192900335751},\n", + " 'latency': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 0.5264821641584111},\n", + " 'packet_loss': { 'alert': 'Packet '\n", + " 'Loss '\n", + " '(7.160328306411617) '\n", + " 'above '\n", + " 'threshold '\n", + " '(5.0)',\n", + " 'is_error': 0,\n", + " 'value': 7.160328306411617},\n", + " 'throughput': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 300}}},\n", + " 'location': ( 51.50481942953137,\n", + " -0.12480785082663902)}},\n", + " 'Cook-Garcia': { 0: { 'devices': { 0: { 'cpu_utilization': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 74.19894267104786},\n", + " 'latency': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 2.960506181930309},\n", + " 'packet_loss': { 'alert': 'Packet '\n", + " 'Loss '\n", + " '(5.362717434454413) '\n", + " 'above '\n", + " 'threshold '\n", + " '(5.0)',\n", + " 'is_error': 0,\n", + " 'value': 5.362717434454413},\n", + " 'throughput': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 243.4494107445954}},\n", + " 1: { 'cpu_utilization': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 79.10598942894484},\n", + " 'latency': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 3.8433041952745395},\n", + " 'packet_loss': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 0.6502623759241918},\n", + " 'throughput': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 207.36008499571855}}},\n", + " 'location': ( 51.493543967071595,\n", + " -0.16590678894892827)},\n", + " 1: { 'devices': { 0: { 'cpu_utilization': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 73.8201153899665},\n", + " 'latency': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 4.887414858921548},\n", + " 'packet_loss': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 3.085674812791428},\n", + " 'throughput': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 187.22506610606098}},\n", + " 1: { 'cpu_utilization': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 73.67785713782037},\n", + " 'latency': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 1.2323381173298915},\n", + " 'packet_loss': { 'alert': 'Packet '\n", + " 'Loss '\n", + " '(5.480753401658468) '\n", + " 'above '\n", + " 'threshold '\n", + " '(5.0)',\n", + " 'is_error': 0,\n", + " 'value': 5.480753401658468},\n", + " 'throughput': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 300}}},\n", + " 'location': ( 51.50773284997823,\n", + " -0.15441384502163097)}},\n", + " 'Ortiz Group': { 0: { 'devices': { 0: { 'cpu_utilization': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 72.49954821111541},\n", + " 'latency': { 'alert': 'Latency '\n", + " '(5.884737320994838) '\n", + " 'above '\n", + " 'threshold '\n", + " '(5.0)',\n", + " 'is_error': 0,\n", + " 'value': 5.884737320994838},\n", + " 'packet_loss': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 1.4726118101226522},\n", + " 'throughput': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 296.8462698235178}},\n", + " 1: { 'cpu_utilization': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 77.79508267867517},\n", + " 'latency': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 3.2493899705660514},\n", + " 'packet_loss': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 0.5957746828911601},\n", + " 'throughput': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 155.45685936694815}}},\n", + " 'location': ( 51.518566280796634,\n", + " -0.08512722951384004)},\n", + " 1: { 'devices': { 0: { 'cpu_utilization': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 69.68611731053089},\n", + " 'latency': { 'alert': 'Latency '\n", + " '(6.953106991036155) '\n", + " 'above '\n", + " 'threshold '\n", + " '(5.0)',\n", + " 'is_error': 0,\n", + " 'value': 6.953106991036155},\n", + " 'packet_loss': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 3.200894783159529},\n", + " 'throughput': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 196.33027185867974}},\n", + " 1: { 'cpu_utilization': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 73.79713551564922},\n", + " 'latency': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 1.1940253694213234},\n", + " 'packet_loss': { 'alert': 'Packet '\n", + " 'Loss '\n", + " '(7.0339900707296845) '\n", + " 'above '\n", + " 'threshold '\n", + " '(5.0)',\n", + " 'is_error': 0,\n", + " 'value': 7.0339900707296845},\n", + " 'throughput': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 263.6815105856207}}},\n", + " 'location': ( 51.49843940953085,\n", + " -0.07216006822476903)}}}),\n", + " ( 'Sample 1:',\n", + " { 'Brown Ltd': { 0: { 'devices': { 0: { 'cpu_utilization': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 71.36943073018143},\n", + " 'latency': { 'alert': 'Latency '\n", + " '(5.368800822544379) '\n", + " 'above '\n", + " 'threshold '\n", + " '(5.0)',\n", + " 'is_error': 0,\n", + " 'value': 5.368800822544379},\n", + " 'packet_loss': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 3.7482555902923917},\n", + " 'throughput': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 102.93675756238903}},\n", + " 1: { 'cpu_utilization': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 70.11167841487266},\n", + " 'latency': { 'alert': 'Latency '\n", + " '(5.138727582428533) '\n", + " 'above '\n", + " 'threshold '\n", + " '(5.0)',\n", + " 'is_error': 0,\n", + " 'value': 5.138727582428533},\n", + " 'packet_loss': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 0.706764064971068},\n", + " 'throughput': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 226.3062193502681}}},\n", + " 'location': ( 51.51462563504477,\n", + " -0.1557846123865522)},\n", + " 1: { 'devices': { 0: { 'cpu_utilization': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 79.05047713915975},\n", + " 'latency': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 4.081261402917731},\n", + " 'packet_loss': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 3.303623935664029},\n", + " 'throughput': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 170.80479689682238}},\n", + " 1: { 'cpu_utilization': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 74.75133492091697},\n", + " 'latency': { 'alert': 'Latency '\n", + " '(5.69398127113165) '\n", + " 'above '\n", + " 'threshold '\n", + " '(5.0)',\n", + " 'is_error': 0,\n", + " 'value': 5.69398127113165},\n", + " 'packet_loss': { 'alert': 'Packet '\n", + " 'Loss '\n", + " '(9.411960644473137) '\n", + " 'above '\n", + " 'threshold '\n", + " '(5.0)',\n", + " 'is_error': 0,\n", + " 'value': 9.411960644473137},\n", + " 'throughput': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 223.09358352197313}}},\n", + " 'location': ( 51.50481942953137,\n", + " -0.12480785082663902)}},\n", + " 'Cook-Garcia': { 0: { 'devices': { 0: { 'cpu_utilization': { 'alert': 'Operation '\n", + " '- '\n", + " 'Chassis '\n", + " 'CPU '\n", + " 'Utilization '\n", + " '(80.13286280293262) '\n", + " 'exceed '\n", + " 'Critical '\n", + " 'threshold '\n", + " '(80.0)',\n", + " 'is_error': 0,\n", + " 'value': 80.13286280293262},\n", + " 'latency': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 1.0693360012600555},\n", + " 'packet_loss': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 3.8795603855485457},\n", + " 'throughput': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 208.63655889153728}},\n", + " 1: { 'cpu_utilization': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 70.91413469122692},\n", + " 'latency': { 'alert': 'Latency '\n", + " '(5.554423655722503) '\n", + " 'above '\n", + " 'threshold '\n", + " '(5.0)',\n", + " 'is_error': 0,\n", + " 'value': 5.554423655722503},\n", + " 'packet_loss': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 4.269603416151698},\n", + " 'throughput': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 300}}},\n", + " 'location': ( 51.493543967071595,\n", + " -0.16590678894892827)},\n", + " 1: { 'devices': { 0: { 'cpu_utilization': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 78.3268502857455},\n", + " 'latency': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 1.6017809809702843},\n", + " 'packet_loss': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 1.756836589092155},\n", + " 'throughput': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 169.35187410052393}},\n", + " 1: { 'cpu_utilization': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 67.21769139867197},\n", + " 'latency': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 0},\n", + " 'packet_loss': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 3.0954553588899025},\n", + " 'throughput': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 188.21502785701614}}},\n", + " 'location': ( 51.50773284997823,\n", + " -0.15441384502163097)}},\n", + " 'Ortiz Group': { 0: { 'devices': { 0: { 'cpu_utilization': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 77.59281900138168},\n", + " 'latency': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 1.6748668545428416},\n", + " 'packet_loss': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 0},\n", + " 'throughput': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 273.3914890361344}},\n", + " 1: { 'cpu_utilization': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 78.72389709264276},\n", + " 'latency': { 'alert': 'Latency '\n", + " '(5.2916532700684185) '\n", + " 'above '\n", + " 'threshold '\n", + " '(5.0)',\n", + " 'is_error': 0,\n", + " 'value': 5.2916532700684185},\n", + " 'packet_loss': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 2.972407320453359},\n", + " 'throughput': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 300}}},\n", + " 'location': ( 51.518566280796634,\n", + " -0.08512722951384004)},\n", + " 1: { 'devices': { 0: { 'cpu_utilization': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 73.80112576247484},\n", + " 'latency': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 4.415371965874538},\n", + " 'packet_loss': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 1.8746184287681646},\n", + " 'throughput': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 133.54978078499573}},\n", + " 1: { 'cpu_utilization': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 78.3237916430692},\n", + " 'latency': { 'alert': 'Latency '\n", + " '(10.70861064051489) '\n", + " 'above '\n", + " 'threshold '\n", + " '(5.0)',\n", + " 'is_error': 0,\n", + " 'value': 10.70861064051489},\n", + " 'packet_loss': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 3.479758244606926},\n", + " 'throughput': { 'alert': '',\n", + " 'is_error': 0,\n", + " 'value': 200.13876301743494}}},\n", + " 'location': ( 51.49843940953085,\n", + " -0.07216006822476903)}}})]\n" + ] + } + ], + "source": [ + "ex_dep = Deployment(deplyoment_configuration)\n", + "generator = ex_dep.generate()\n", + "num_samples = 2\n", + "pp.pprint([(f'Sample {sample}:', next(generator)) for sample in range(num_samples)])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Model Training\n", + "### Intelligent management (Netops) model training - Create CSV\n", + "[top](#Table-of-content)" + ] + }, + { + "cell_type": "code", + "execution_count": 90, + "metadata": {}, + "outputs": [], + "source": [ + "FILENAME = 'netops_data.csv'\n", + "NUM_SAMPLES = 1000\n", + "\n", + "# Make sure it's a new file\n", + "os.remove(f.name) if os.path.exists(f.name) else None\n", + "\n", + "with open(FILENAME, 'w') as f:\n", + " # Add header columns\n", + " f.write('timestamp\\tcompany\\tlocation\\tLat_long\\tdevice\\tmetric\\tvalue\\tis_error\\talert\\n')\n", + " \n", + " # Create and write samples\n", + " for i in range(NUM_SAMPLES):\n", + " generator_sample = next(generator)\n", + " for company, locations in generator_sample.items():\n", + " for location, devices in locations.items():\n", + " current_coordinates = devices['location']\n", + " for device, metrics in devices['devices'].items():\n", + " for metric_name, data in metrics.items():\n", + " f.write(f'{i}\\t{company}\\t{location}\\t({current_coordinates})\\t{device}\\t{metric_name}\\t{data[\"value\"]}\\t{data[\"is_error\"]}\\t{data[\"alert\"]}\\n')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Get The Data\n", + "[top](#Table-of-content)" + ] + }, + { + "cell_type": "code", + "execution_count": 91, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
timestampcompanylocationLat_longdevicemetricvalueis_erroralertid
00Brown Ltd0((51.51462563504477, -0.1557846123865522))0cpu_utilization100.01Operation - Chassis CPU Utilization (100) exce...Brown Ltd_0_0
10Brown Ltd0((51.51462563504477, -0.1557846123865522))0throughput0.01Low Throughput (0) below threshold (3.0)Brown Ltd_0_0
20Brown Ltd0((51.51462563504477, -0.1557846123865522))0latency20.01Latency (20) above threshold (5.0)Brown Ltd_0_0
30Brown Ltd0((51.51462563504477, -0.1557846123865522))0packet_loss100.01Packet Loss (100) above threshold (5.0)Brown Ltd_0_0
40Brown Ltd0((51.51462563504477, -0.1557846123865522))1cpu_utilization100.01Operation - Chassis CPU Utilization (100) exce...Brown Ltd_0_1
\n", + "
" + ], + "text/plain": [ + " timestamp company location Lat_long \\\n", + "0 0 Brown Ltd 0 ((51.51462563504477, -0.1557846123865522)) \n", + "1 0 Brown Ltd 0 ((51.51462563504477, -0.1557846123865522)) \n", + "2 0 Brown Ltd 0 ((51.51462563504477, -0.1557846123865522)) \n", + "3 0 Brown Ltd 0 ((51.51462563504477, -0.1557846123865522)) \n", + "4 0 Brown Ltd 0 ((51.51462563504477, -0.1557846123865522)) \n", + "\n", + " device metric value is_error \\\n", + "0 0 cpu_utilization 100.0 1 \n", + "1 0 throughput 0.0 1 \n", + "2 0 latency 20.0 1 \n", + "3 0 packet_loss 100.0 1 \n", + "4 1 cpu_utilization 100.0 1 \n", + "\n", + " alert id \n", + "0 Operation - Chassis CPU Utilization (100) exce... Brown Ltd_0_0 \n", + "1 Low Throughput (0) below threshold (3.0) Brown Ltd_0_0 \n", + "2 Latency (20) above threshold (5.0) Brown Ltd_0_0 \n", + "3 Packet Loss (100) above threshold (5.0) Brown Ltd_0_0 \n", + "4 Operation - Chassis CPU Utilization (100) exce... Brown Ltd_0_1 " + ] + }, + "execution_count": 91, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df = pd.read_csv(FILENAME, sep='\\t')\n", + "df['id'] = df[['company', 'location', 'device']].astype(str).apply('_'.join, 1)\n", + "df.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Transform raw data to Feature Vectors\n", + "[top](#Table-of-content)" + ] + }, + { + "cell_type": "code", + "execution_count": 108, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
timestampcpu_utilizationlatencypacket_lossthroughputis_errorcpu_1h_meanlatency_1h_meanpacket_loss_1h_meanthroughput_1h_mean
id
Brown Ltd_0_01173.3619737.5713215.320947204.669315080.5618496.68332219.887976159.772701
Brown Ltd_0_01277.7494750.0000003.569248209.826407078.7076385.01665511.852080177.258235
Brown Ltd_0_01370.6847004.3885024.491987289.715713076.2646963.7156973.893079201.401211
Brown Ltd_0_01472.8125050.6032030.000000232.639139076.4136483.6129613.473818197.309892
Brown Ltd_0_01577.1646725.2736862.741906120.726469076.1202383.3311373.177568188.996403
Brown Ltd_0_01671.8607446.4592570.000000196.298832075.9302093.5057643.153419191.665879
Brown Ltd_0_01776.1285181.2545434.372429226.684887075.3773073.2472673.048915196.815058
Brown Ltd_0_018100.0000003.7228975.23668757.278658077.1356493.5337663.248067184.865948
Brown Ltd_0_01976.5496536.7815522.902568222.568074077.2021193.6356103.343880185.911795
Brown Ltd_0_02072.9983394.3595914.103284172.167095076.5514093.9059323.359096181.794731
Brown Ltd_0_02178.0736876.1235803.960455208.641813076.9696004.1812483.500383186.986708
Brown Ltd_0_02278.4766052.3975223.248029194.121152077.1550734.0779713.328962194.611463
Brown Ltd_0_02375.5060503.6485626.319919188.752718077.3337463.7510753.412209193.285080
Brown Ltd_0_02481.2375711.5884465.192349128.876710077.6244203.8834453.547468186.539272
Brown Ltd_0_025100.0000001.7608010.766677163.008699080.0673623.6644703.237025175.980354
Brown Ltd_0_02672.9482725.9230884.542379127.406300080.0786764.1077943.615557167.210951
Brown Ltd_0_02769.6775334.0593784.908795294.009361079.4547484.0066013.796131181.651192
Brown Ltd_0_02879.3379351.0705030.550190277.538618080.0778473.5575393.841980188.421174
Brown Ltd_0_02974.0676982.7639273.878251296.641925079.9061123.6833213.800799194.250927
Brown Ltd_0_03082.2022051.7043082.914729169.127908078.4229623.5151053.607302203.571698
\n", + "
" + ], + "text/plain": [ + " timestamp cpu_utilization latency packet_loss throughput \\\n", + "id \n", + "Brown Ltd_0_0 11 73.361973 7.571321 5.320947 204.669315 \n", + "Brown Ltd_0_0 12 77.749475 0.000000 3.569248 209.826407 \n", + "Brown Ltd_0_0 13 70.684700 4.388502 4.491987 289.715713 \n", + "Brown Ltd_0_0 14 72.812505 0.603203 0.000000 232.639139 \n", + "Brown Ltd_0_0 15 77.164672 5.273686 2.741906 120.726469 \n", + "Brown Ltd_0_0 16 71.860744 6.459257 0.000000 196.298832 \n", + "Brown Ltd_0_0 17 76.128518 1.254543 4.372429 226.684887 \n", + "Brown Ltd_0_0 18 100.000000 3.722897 5.236687 57.278658 \n", + "Brown Ltd_0_0 19 76.549653 6.781552 2.902568 222.568074 \n", + "Brown Ltd_0_0 20 72.998339 4.359591 4.103284 172.167095 \n", + "Brown Ltd_0_0 21 78.073687 6.123580 3.960455 208.641813 \n", + "Brown Ltd_0_0 22 78.476605 2.397522 3.248029 194.121152 \n", + "Brown Ltd_0_0 23 75.506050 3.648562 6.319919 188.752718 \n", + "Brown Ltd_0_0 24 81.237571 1.588446 5.192349 128.876710 \n", + "Brown Ltd_0_0 25 100.000000 1.760801 0.766677 163.008699 \n", + "Brown Ltd_0_0 26 72.948272 5.923088 4.542379 127.406300 \n", + "Brown Ltd_0_0 27 69.677533 4.059378 4.908795 294.009361 \n", + "Brown Ltd_0_0 28 79.337935 1.070503 0.550190 277.538618 \n", + "Brown Ltd_0_0 29 74.067698 2.763927 3.878251 296.641925 \n", + "Brown Ltd_0_0 30 82.202205 1.704308 2.914729 169.127908 \n", + "\n", + " is_error cpu_1h_mean latency_1h_mean packet_loss_1h_mean \\\n", + "id \n", + "Brown Ltd_0_0 0 80.561849 6.683322 19.887976 \n", + "Brown Ltd_0_0 0 78.707638 5.016655 11.852080 \n", + "Brown Ltd_0_0 0 76.264696 3.715697 3.893079 \n", + "Brown Ltd_0_0 0 76.413648 3.612961 3.473818 \n", + "Brown Ltd_0_0 0 76.120238 3.331137 3.177568 \n", + "Brown Ltd_0_0 0 75.930209 3.505764 3.153419 \n", + "Brown Ltd_0_0 0 75.377307 3.247267 3.048915 \n", + "Brown Ltd_0_0 0 77.135649 3.533766 3.248067 \n", + "Brown Ltd_0_0 0 77.202119 3.635610 3.343880 \n", + "Brown Ltd_0_0 0 76.551409 3.905932 3.359096 \n", + "Brown Ltd_0_0 0 76.969600 4.181248 3.500383 \n", + "Brown Ltd_0_0 0 77.155073 4.077971 3.328962 \n", + "Brown Ltd_0_0 0 77.333746 3.751075 3.412209 \n", + "Brown Ltd_0_0 0 77.624420 3.883445 3.547468 \n", + "Brown Ltd_0_0 0 80.067362 3.664470 3.237025 \n", + "Brown Ltd_0_0 0 80.078676 4.107794 3.615557 \n", + "Brown Ltd_0_0 0 79.454748 4.006601 3.796131 \n", + "Brown Ltd_0_0 0 80.077847 3.557539 3.841980 \n", + "Brown Ltd_0_0 0 79.906112 3.683321 3.800799 \n", + "Brown Ltd_0_0 0 78.422962 3.515105 3.607302 \n", + "\n", + " throughput_1h_mean \n", + "id \n", + "Brown Ltd_0_0 159.772701 \n", + "Brown Ltd_0_0 177.258235 \n", + "Brown Ltd_0_0 201.401211 \n", + "Brown Ltd_0_0 197.309892 \n", + "Brown Ltd_0_0 188.996403 \n", + "Brown Ltd_0_0 191.665879 \n", + "Brown Ltd_0_0 196.815058 \n", + "Brown Ltd_0_0 184.865948 \n", + "Brown Ltd_0_0 185.911795 \n", + "Brown Ltd_0_0 181.794731 \n", + "Brown Ltd_0_0 186.986708 \n", + "Brown Ltd_0_0 194.611463 \n", + "Brown Ltd_0_0 193.285080 \n", + "Brown Ltd_0_0 186.539272 \n", + "Brown Ltd_0_0 175.980354 \n", + "Brown Ltd_0_0 167.210951 \n", + "Brown Ltd_0_0 181.651192 \n", + "Brown Ltd_0_0 188.421174 \n", + "Brown Ltd_0_0 194.250927 \n", + "Brown Ltd_0_0 203.571698 " + ] + }, + "execution_count": 108, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Prepare DF to feature extraction form\n", + "# - Pivot\n", + "# - Fill NAs\n", + "# - Drop duplicates\n", + "# - Set Index\n", + "X = df.pivot_table(index=['timestamp', 'id'], columns='metric', values='value').sort_index().reset_index()\n", + "X = X.sort_values(['id', 'timestamp']).fillna(method='ffill')\n", + "X = X.fillna(method='bfill')\n", + "X = X.join(df.set_index(['timestamp', 'id']), on=['timestamp', 'id'], how='left')[['timestamp', 'id', 'cpu_utilization', 'latency', 'packet_loss', 'throughput', 'is_error']]\n", + "X = X.drop_duplicates(subset=['id', 'timestamp', 'cpu_utilization', 'latency', 'packet_loss', 'throughput'])\n", + "X = X.set_index(['id'])\n", + "\n", + "# Create Features\n", + "X[\"cpu_1h_mean\"] = X.cpu_utilization.rolling(window=12).mean()\n", + "X[\"latency_1h_mean\"] = X.latency.rolling(window=12).mean()\n", + "X[\"packet_loss_1h_mean\"] = X.packet_loss.rolling(window=12).mean()\n", + "X[\"throughput_1h_mean\"] = X.throughput.rolling(window=12).mean()\n", + "\n", + "# Drop first 'Window' samples due to no featuers\n", + "# (Dont want to confuse the ML algorithm)\n", + "feature_vectors = X.dropna()\n", + "feature_vectors.head(n=20)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Prepare traning and test datasets\n", + "[top](#Table-of-content)" + ] + }, + { + "cell_type": "code", + "execution_count": 125, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/orz/anaconda3/lib/python3.6/site-packages/sklearn/model_selection/_split.py:2179: FutureWarning: From version 0.21, test_size will always complement train_size unless both are specified.\n", + " FutureWarning)\n" + ] + } + ], + "source": [ + "X = feature_vectors[['cpu_1h_mean', 'latency_1h_mean', 'packet_loss_1h_mean', 'throughput_1h_mean']].reset_index(drop=True)\n", + "y = feature_vectors['is_error']\n", + "X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.7)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Train Model\n", + "[top](#Table-of-content)" + ] + }, + { + "cell_type": "code", + "execution_count": 126, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "GradientBoostingClassifier(criterion='friedman_mse', init=None,\n", + " learning_rate=0.1, loss='deviance', max_depth=3,\n", + " max_features=None, max_leaf_nodes=None,\n", + " min_impurity_decrease=0.0, min_impurity_split=None,\n", + " min_samples_leaf=1, min_samples_split=2,\n", + " min_weight_fraction_leaf=0.0, n_estimators=10,\n", + " n_iter_no_change=None, presort='auto', random_state=None,\n", + " subsample=1.0, tol=0.0001, validation_fraction=0.1,\n", + " verbose=0, warm_start=False)" + ] + }, + "execution_count": 126, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model = GradientBoostingClassifier(n_estimators=10)\n", + "model.fit(X_train, y_train)" + ] + }, + { + "cell_type": "code", + "execution_count": 127, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.9813733666944676" + ] + }, + "execution_count": 127, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model.score(X_test, y_test)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Save Model\n", + "[top](#Table-of-content)" + ] + }, + { + "cell_type": "code", + "execution_count": 123, + "metadata": {}, + "outputs": [], + "source": [ + "MODEL_FILENAME='netops.model'\n", + "with open(MODEL_FILENAME, 'wb+') as f:\n", + " pickle.dump(model, f)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Predict\n", + "[top](#Table-of-content)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/netops_demo/py/Dockerfile b/netops_demo/py/Dockerfile index 69c4845..10f3db8 100644 --- a/netops_demo/py/Dockerfile +++ b/netops_demo/py/Dockerfile @@ -2,6 +2,7 @@ ARG NUCLIO_TAG=0.5.15 ARG NUCLIO_ARCH=amd64 ARG NUCLIO_BASE_IMAGE=python:3.7 + # Supplies processor uhttpc, used for healthcheck FROM nuclio/uhttpc:0.0.1-amd64 as uhttpc @@ -18,6 +19,9 @@ COPY --from=uhttpc /home/nuclio/bin/uhttpc /usr/local/bin/uhttpc # Copy the appropriate functions COPY functions/generate /opt/nuclio/functions/generate +COPY functions/predict /opt/nuclio/functions/predict + + # Copy all of the shared code COPY libs /opt/nuclio/libs @@ -32,4 +36,19 @@ HEALTHCHECK --interval=1s --timeout=3s CMD /usr/local/bin/uhttpc --url http://lo CMD [ "processor", "--config", "/etc/nuclio/config/processor/processor.yaml", "--platform-config", "/etc/nuclio/config/platform/platform.yaml" ] # Install packages -RUN cd /opt/nuclio && pip install -r requirements.txt + +## Download the model file and make it available locally +ARG MODEL_LOCATION_URL=http://192.168.224.49:8081/1/netops.model +ARG MODEL_FILE=/tmp/model/netops.model + +ENV MODEL_FILE $MODEL_FILE + +RUN mkdir -p /tmp/model && cd /tmp/model && \ +curl -X GET \ + ${MODEL_LOCATION_URL} \ + -o ${MODEL_FILE} \ + -H 'authorization: Basic aWd1YXppbzpkYXRhbEBrZSE=' \ + -H 'cache-control: no-cache' \ + -H 'content-type: application/json' + +RUN cd /opt/nuclio && pip install -r requirements.txt \ No newline at end of file diff --git a/netops_demo/py/functions/generate/generate.py b/netops_demo/py/functions/generate/generate.py index d29190c..5e1b79d 100644 --- a/netops_demo/py/functions/generate/generate.py +++ b/netops_demo/py/functions/generate/generate.py @@ -3,9 +3,11 @@ import json import re +import libs.utils.utils import libs.generator.deployment import libs.nuclio_sdk +#TODO: Seperate predict and generate functions to utils def generate(context, event): if event.path == '/configure': @@ -19,6 +21,8 @@ def generate(context, event): _stop(context) elif event.path == '/sites': return _sites(context) + elif event.path == '/devices': + return _devices(context) elif event.path in ['/generate', '/', '']: if context.user_data.state == 'generating': return _generate(context, **(event.body or {})) @@ -29,12 +33,8 @@ def generate(context, event): def init_context(context): - # initialize context structure - for context_attr in ['state', 'configuration', 'manager']: - setattr(context.user_data, context_attr, None) - - # start in idle state - context.user_data.state = 'idle' + # Init states + libs.utils.utils.init_context(context) # check to see if there's an environment variable with our initial configuration if 'GENERATOR_CONFIGURATION' in os.environ: @@ -94,7 +94,7 @@ def _sites(context): for company in deployment.companies: company_name_label = _company_name_to_label(company.name) - for i, site_locations in enumerate(company.locations): + for i, site_locations in enumerate(company.locations.values()): sites.append({ 'key': f'{company_name_label}/{i}', 'latitude': site_locations[0], @@ -105,6 +105,18 @@ def _sites(context): return sites +def _devices(context): + deployment = context.user_data.deployment + context.logger.info_with('Sending list of devices', deployment=deployment) + + devices = [] + for company in deployment.companies: + for i, site_locations in company.components.items(): + for j, x in enumerate(site_locations['devices']): + devices.append(f'{company.name}/{i}/{j}') + + return devices + def _generate(context, start_timestamp=None, end_timestamp=None, @@ -136,7 +148,7 @@ def _generate(context, emitters = _generate_emitters(context, start_timestamp, num_samples, interval) # send the metrics towards the target - response = _send_emitters_to_target(context, target, emitters) + response = libs.utils.utils.send_emitters_to_target(context, target, emitters) # if this is an event response, make sure it's OK if type(response) is context.Response and response.status_code != 200: @@ -252,23 +264,5 @@ def _create_emitter(context, company_name, site_name, site_info, emitter_id): return emitter - -def _send_emitters_to_target(context, target, metrics_batch): - context.logger.debug_with('Sending metrics to target', target=target) - - if target.startswith('function'): - - # function:netops-ingest -> netops-ingest - target_function = target.split(':')[1] - - context.platform.call_function(target_function, libs.nuclio_sdk.Event(body=metrics_batch)) - elif target == 'response': - return metrics_batch - elif target == 'log': - context.logger.info_with('Sending metrics batch', metrics_batch=metrics_batch) - else: - raise ValueError(f'Unknown target type {target}') - - def _company_name_to_label(company_name): - return re.sub(r'[^a-zA-Z -]', '', company_name).lower().replace(' ', '_').replace('-', '_') + return re.sub(r'[^a-zA-Z -]', '', company_name).lower().replace(' ', '_').replace('-', '_') \ No newline at end of file diff --git a/netops_demo/py/functions/generate/generate_test.py b/netops_demo/py/functions/generate/generate_test.py index df6d20b..6c43a9f 100644 --- a/netops_demo/py/functions/generate/generate_test.py +++ b/netops_demo/py/functions/generate/generate_test.py @@ -5,6 +5,7 @@ import libs.nuclio_sdk.test import functions.generate.generate +import libs.utils.utils class TestCase(libs.nuclio_sdk.test.TestCase): @@ -12,6 +13,7 @@ class TestCase(libs.nuclio_sdk.test.TestCase): def setUp(self): super().setUp() self._module = functions.generate.generate + self._utils = libs.utils.utils def test_configure(self): configuration = { @@ -104,12 +106,12 @@ def test_send_emitters_to_target(self): metrics_batch = {'some': 'metrics'} with self.assertRaises(ValueError): - self._module._send_emitters_to_target(context, 'unknown', metrics_batch) + self._utils.send_emitters_to_target(context, 'unknown', metrics_batch) - response = self._module._send_emitters_to_target(context, 'response', metrics_batch) + response = self._utils.send_emitters_to_target(context, 'response', metrics_batch) self.assertEqual(response, metrics_batch) - self._module._send_emitters_to_target(context, 'function:some-function', metrics_batch) + self._utils.send_emitters_to_target(context, 'function:some-function', metrics_batch) # verify some-function was called name, sent_event = self._platform.get_call_function_call_args(0) @@ -224,7 +226,21 @@ def test_sites(self): # call start response = self._platform.call_handler(self._module.generate, event=libs.nuclio_sdk.Event(path='/sites')) - self.assertEqual(configuration['deployment']['num_companies'] * configuration['deployment']['num_sites_per_company'], len(response)) + self.assertEqual( + configuration['deployment']['num_companies'] * configuration['deployment']['num_sites_per_company'], + len(response)) + + def test_devices(self): + configuration = self._get_sample_configuration() + + # encode configuration into environment variable + os.environ['GENERATOR_CONFIGURATION'] = json.dumps(configuration) + + # call start + response = self._platform.call_handler(self._module.generate, event=libs.nuclio_sdk.Event(path='/devices')) + self.assertEqual( + configuration['deployment']['num_companies'] * configuration['deployment']['num_sites_per_company'] + * configuration['deployment']['num_devices_per_site'], len(response)) @staticmethod def _get_sample_configuration(): @@ -287,5 +303,2417 @@ def _get_sample_configuration(): 'errors': [], 'error_rate': 0.1, 'target': 'response', + 'state': 'generating' } + + @staticmethod + def _get_prometheus_throughput_avg_1h(): + return { + "status": "success", + "data": { + "resultType": "vector", + "result": [ + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/3/1", + "latitute": "-0.11766485686257479", + "longitude": "51.51241260576661", + "site_id": "cook_ramirez_and_howell/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "201.84682698565652" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/3/4", + "latitute": "-0.11766485686257479", + "longitude": "51.51241260576661", + "site_id": "cook_ramirez_and_howell/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "202.02232908643256" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/1/9", + "latitute": "-0.17937324059872775", + "longitude": "51.49981289880396", + "site_id": "cook_ramirez_and_howell/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "195.52091063340944" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/1/8", + "latitute": "-0.08845125744353492", + "longitude": "51.49395842747566", + "site_id": "jackson_gibson/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "196.80557368577473" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/3/8", + "latitute": "-0.14477605500681137", + "longitude": "51.50950646273536", + "site_id": "jackson_gibson/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "197.14578076146293" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/3/9", + "latitute": "-0.1684063123676963", + "longitude": "51.49890595002585", + "site_id": "martinez_inc/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "198.25121288933332" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/0/4", + "latitute": "-0.08743943934424686", + "longitude": "51.49462424727675", + "site_id": "cook_ramirez_and_howell/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "200.3116370269399" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/4/6", + "latitute": "-0.11922450970538258", + "longitude": "51.495592295069905", + "site_id": "cook_ramirez_and_howell/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "201.69564330124905" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/4/9", + "latitute": "-0.10358309561844188", + "longitude": "51.502997658785624", + "site_id": "martinez_inc/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "195.72478779138552" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/1/4", + "latitute": "-0.17937324059872775", + "longitude": "51.49981289880396", + "site_id": "cook_ramirez_and_howell/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "197.80413082951264" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/4/7", + "latitute": "-0.10358309561844188", + "longitude": "51.502997658785624", + "site_id": "martinez_inc/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "199.3129222253966" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/1/1", + "latitute": "-0.18856414865471136", + "longitude": "51.50398145727124", + "site_id": "martinez_inc/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "199.29127778426687" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/2/0", + "latitute": "-0.12588664262819296", + "longitude": "51.50221488435059", + "site_id": "cook_ramirez_and_howell/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "201.24457498024685" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/1/8", + "latitute": "-0.18856414865471136", + "longitude": "51.50398145727124", + "site_id": "martinez_inc/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "200.3373581533792" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/4/7", + "latitute": "-0.10790649546111267", + "longitude": "51.505154712405286", + "site_id": "jackson_gibson/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "199.9646135829882" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/3/7", + "latitute": "-0.1684063123676963", + "longitude": "51.49890595002585", + "site_id": "martinez_inc/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "202.4863893062895" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/4/2", + "latitute": "-0.11922450970538258", + "longitude": "51.495592295069905", + "site_id": "cook_ramirez_and_howell/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "200.05184702490186" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/2/0", + "latitute": "-0.11642291673866854", + "longitude": "51.51683458013747", + "site_id": "martinez_inc/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "195.79330791453125" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/3/0", + "latitute": "-0.1684063123676963", + "longitude": "51.49890595002585", + "site_id": "martinez_inc/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "199.96811468182636" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/2/3", + "latitute": "-0.11642291673866854", + "longitude": "51.51683458013747", + "site_id": "martinez_inc/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "202.77078565378753" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/0/4", + "latitute": "-0.14414594436220526", + "longitude": "51.51080694746054", + "site_id": "martinez_inc/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "204.43106231216132" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/2/4", + "latitute": "-0.12588664262819296", + "longitude": "51.50221488435059", + "site_id": "cook_ramirez_and_howell/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "198.3928395695168" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/1/6", + "latitute": "-0.08845125744353492", + "longitude": "51.49395842747566", + "site_id": "jackson_gibson/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "201.1124768354935" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/3/7", + "latitute": "-0.11766485686257479", + "longitude": "51.51241260576661", + "site_id": "cook_ramirez_and_howell/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "203.6165793877006" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/2/2", + "latitute": "-0.11642291673866854", + "longitude": "51.51683458013747", + "site_id": "martinez_inc/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "198.57428448308957" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/0/0", + "latitute": "-0.14414594436220526", + "longitude": "51.51080694746054", + "site_id": "martinez_inc/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "198.695688192008" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/1/1", + "latitute": "-0.08845125744353492", + "longitude": "51.49395842747566", + "site_id": "jackson_gibson/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "200.3342129942806" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/2/9", + "latitute": "-0.11642291673866854", + "longitude": "51.51683458013747", + "site_id": "martinez_inc/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "199.56559180485672" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/4/5", + "latitute": "-0.11922450970538258", + "longitude": "51.495592295069905", + "site_id": "cook_ramirez_and_howell/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "201.16954763272514" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/4/6", + "latitute": "-0.10790649546111267", + "longitude": "51.505154712405286", + "site_id": "jackson_gibson/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "196.71524325915243" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/2/6", + "latitute": "-0.12588664262819296", + "longitude": "51.50221488435059", + "site_id": "cook_ramirez_and_howell/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "199.28072743830444" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/3/9", + "latitute": "-0.11766485686257479", + "longitude": "51.51241260576661", + "site_id": "cook_ramirez_and_howell/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "200.49862413673156" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/4/1", + "latitute": "-0.10358309561844188", + "longitude": "51.502997658785624", + "site_id": "martinez_inc/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "200.80540298841441" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/3/9", + "latitute": "-0.14477605500681137", + "longitude": "51.50950646273536", + "site_id": "jackson_gibson/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "197.9708384853567" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/1/7", + "latitute": "-0.17937324059872775", + "longitude": "51.49981289880396", + "site_id": "cook_ramirez_and_howell/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "198.3352771171675" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/4/5", + "latitute": "-0.10358309561844188", + "longitude": "51.502997658785624", + "site_id": "martinez_inc/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "198.7710944467823" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/0/9", + "latitute": "-0.14414594436220526", + "longitude": "51.51080694746054", + "site_id": "martinez_inc/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "200.13094249930876" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/0/0", + "latitute": "-0.09275684203595459", + "longitude": "51.50604392091363", + "site_id": "jackson_gibson/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "203.74401774477604" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/3/1", + "latitute": "-0.1684063123676963", + "longitude": "51.49890595002585", + "site_id": "martinez_inc/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "195.06474004803403" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/4/1", + "latitute": "-0.11922450970538258", + "longitude": "51.495592295069905", + "site_id": "cook_ramirez_and_howell/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "197.24436504924168" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/0/7", + "latitute": "-0.14414594436220526", + "longitude": "51.51080694746054", + "site_id": "martinez_inc/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "201.08608593580766" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/2/3", + "latitute": "-0.12588664262819296", + "longitude": "51.50221488435059", + "site_id": "cook_ramirez_and_howell/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "198.7599557286866" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/3/6", + "latitute": "-0.1684063123676963", + "longitude": "51.49890595002585", + "site_id": "martinez_inc/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "204.308557481124" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/4/4", + "latitute": "-0.11922450970538258", + "longitude": "51.495592295069905", + "site_id": "cook_ramirez_and_howell/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "193.0099878859856" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/0/1", + "latitute": "-0.14414594436220526", + "longitude": "51.51080694746054", + "site_id": "martinez_inc/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "201.42345580633963" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/1/8", + "latitute": "-0.17937324059872775", + "longitude": "51.49981289880396", + "site_id": "cook_ramirez_and_howell/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "201.77209237275176" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/3/5", + "latitute": "-0.14477605500681137", + "longitude": "51.50950646273536", + "site_id": "jackson_gibson/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "196.69713104761172" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/0/7", + "latitute": "-0.09275684203595459", + "longitude": "51.50604392091363", + "site_id": "jackson_gibson/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "198.31397445378576" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/1/4", + "latitute": "-0.08845125744353492", + "longitude": "51.49395842747566", + "site_id": "jackson_gibson/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "201.82758047257465" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/1/0", + "latitute": "-0.08845125744353492", + "longitude": "51.49395842747566", + "site_id": "jackson_gibson/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "199.3491855729556" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/1/0", + "latitute": "-0.17937324059872775", + "longitude": "51.49981289880396", + "site_id": "cook_ramirez_and_howell/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "196.17085785311446" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/4/3", + "latitute": "-0.11922450970538258", + "longitude": "51.495592295069905", + "site_id": "cook_ramirez_and_howell/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "204.88745646047883" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/0/2", + "latitute": "-0.09275684203595459", + "longitude": "51.50604392091363", + "site_id": "jackson_gibson/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "196.3480228927308" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/0/2", + "latitute": "-0.14414594436220526", + "longitude": "51.51080694746054", + "site_id": "martinez_inc/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "202.8579103696573" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/0/5", + "latitute": "-0.14414594436220526", + "longitude": "51.51080694746054", + "site_id": "martinez_inc/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "197.37466218794935" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/4/2", + "latitute": "-0.10358309561844188", + "longitude": "51.502997658785624", + "site_id": "martinez_inc/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "202.51812945931016" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/4/9", + "latitute": "-0.10790649546111267", + "longitude": "51.505154712405286", + "site_id": "jackson_gibson/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "197.95775656198037" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/4/3", + "latitute": "-0.10358309561844188", + "longitude": "51.502997658785624", + "site_id": "martinez_inc/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "199.29505953777763" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/2/1", + "latitute": "-0.12588664262819296", + "longitude": "51.50221488435059", + "site_id": "cook_ramirez_and_howell/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "199.72902867003324" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/1/9", + "latitute": "-0.18856414865471136", + "longitude": "51.50398145727124", + "site_id": "martinez_inc/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "196.33084254742477" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/2/3", + "latitute": "-0.15706157829077952", + "longitude": "51.519939570267255", + "site_id": "jackson_gibson/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "198.44927576056375" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/0/9", + "latitute": "-0.08743943934424686", + "longitude": "51.49462424727675", + "site_id": "cook_ramirez_and_howell/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "196.92239718637927" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/4/0", + "latitute": "-0.10358309561844188", + "longitude": "51.502997658785624", + "site_id": "martinez_inc/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "202.71815476920034" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/3/5", + "latitute": "-0.11766485686257479", + "longitude": "51.51241260576661", + "site_id": "cook_ramirez_and_howell/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "201.89862443814354" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/2/5", + "latitute": "-0.15706157829077952", + "longitude": "51.519939570267255", + "site_id": "jackson_gibson/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "198.61435786412522" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/3/2", + "latitute": "-0.14477605500681137", + "longitude": "51.50950646273536", + "site_id": "jackson_gibson/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "200.13486464613476" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/1/9", + "latitute": "-0.08845125744353492", + "longitude": "51.49395842747566", + "site_id": "jackson_gibson/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "201.80828117073895" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/1/6", + "latitute": "-0.17937324059872775", + "longitude": "51.49981289880396", + "site_id": "cook_ramirez_and_howell/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "203.5009752841243" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/2/0", + "latitute": "-0.15706157829077952", + "longitude": "51.519939570267255", + "site_id": "jackson_gibson/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "201.03865831051542" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/3/8", + "latitute": "-0.11766485686257479", + "longitude": "51.51241260576661", + "site_id": "cook_ramirez_and_howell/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "202.40276494043889" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/4/0", + "latitute": "-0.10790649546111267", + "longitude": "51.505154712405286", + "site_id": "jackson_gibson/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "202.0984346718554" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/0/3", + "latitute": "-0.14414594436220526", + "longitude": "51.51080694746054", + "site_id": "martinez_inc/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "202.57778277641512" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/3/6", + "latitute": "-0.14477605500681137", + "longitude": "51.50950646273536", + "site_id": "jackson_gibson/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "197.86322701166387" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/3/4", + "latitute": "-0.14477605500681137", + "longitude": "51.50950646273536", + "site_id": "jackson_gibson/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "198.87411958933114" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/1/4", + "latitute": "-0.18856414865471136", + "longitude": "51.50398145727124", + "site_id": "martinez_inc/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "205.39193276923314" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/4/8", + "latitute": "-0.11922450970538258", + "longitude": "51.495592295069905", + "site_id": "cook_ramirez_and_howell/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "199.6762694607545" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/2/7", + "latitute": "-0.15706157829077952", + "longitude": "51.519939570267255", + "site_id": "jackson_gibson/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "197.30960573882373" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/0/3", + "latitute": "-0.09275684203595459", + "longitude": "51.50604392091363", + "site_id": "jackson_gibson/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "201.771092958179" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/0/5", + "latitute": "-0.08743943934424686", + "longitude": "51.49462424727675", + "site_id": "cook_ramirez_and_howell/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "199.4923922717868" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/2/4", + "latitute": "-0.11642291673866854", + "longitude": "51.51683458013747", + "site_id": "martinez_inc/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "202.5549280217423" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/0/1", + "latitute": "-0.08743943934424686", + "longitude": "51.49462424727675", + "site_id": "cook_ramirez_and_howell/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "202.9675457506287" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/1/3", + "latitute": "-0.17937324059872775", + "longitude": "51.49981289880396", + "site_id": "cook_ramirez_and_howell/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "198.5703293318505" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/1/5", + "latitute": "-0.08845125744353492", + "longitude": "51.49395842747566", + "site_id": "jackson_gibson/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "202.6195506442932" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/0/1", + "latitute": "-0.09275684203595459", + "longitude": "51.50604392091363", + "site_id": "jackson_gibson/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "200.59050851861292" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/0/8", + "latitute": "-0.14414594436220526", + "longitude": "51.51080694746054", + "site_id": "martinez_inc/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "203.5622379069917" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/4/5", + "latitute": "-0.10790649546111267", + "longitude": "51.505154712405286", + "site_id": "jackson_gibson/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "203.81845968239867" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/1/2", + "latitute": "-0.17937324059872775", + "longitude": "51.49981289880396", + "site_id": "cook_ramirez_and_howell/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "198.08604078610432" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/3/5", + "latitute": "-0.1684063123676963", + "longitude": "51.49890595002585", + "site_id": "martinez_inc/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "198.93246514279485" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/1/5", + "latitute": "-0.18856414865471136", + "longitude": "51.50398145727124", + "site_id": "martinez_inc/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "203.5700383167893" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/4/2", + "latitute": "-0.10790649546111267", + "longitude": "51.505154712405286", + "site_id": "jackson_gibson/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "199.49954891178135" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/2/2", + "latitute": "-0.15706157829077952", + "longitude": "51.519939570267255", + "site_id": "jackson_gibson/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "199.3125792525744" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/1/7", + "latitute": "-0.08845125744353492", + "longitude": "51.49395842747566", + "site_id": "jackson_gibson/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "199.63250114277076" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/4/3", + "latitute": "-0.10790649546111267", + "longitude": "51.505154712405286", + "site_id": "jackson_gibson/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "198.72943358456283" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/0/6", + "latitute": "-0.08743943934424686", + "longitude": "51.49462424727675", + "site_id": "cook_ramirez_and_howell/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "200.4231318636992" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/3/1", + "latitute": "-0.14477605500681137", + "longitude": "51.50950646273536", + "site_id": "jackson_gibson/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "199.31267730947303" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/3/2", + "latitute": "-0.1684063123676963", + "longitude": "51.49890595002585", + "site_id": "martinez_inc/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "199.54326952138825" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/2/1", + "latitute": "-0.15706157829077952", + "longitude": "51.519939570267255", + "site_id": "jackson_gibson/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "203.4478702901137" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/4/9", + "latitute": "-0.11922450970538258", + "longitude": "51.495592295069905", + "site_id": "cook_ramirez_and_howell/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "193.502798339676" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/1/3", + "latitute": "-0.08845125744353492", + "longitude": "51.49395842747566", + "site_id": "jackson_gibson/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "202.32434207174623" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/4/8", + "latitute": "-0.10358309561844188", + "longitude": "51.502997658785624", + "site_id": "martinez_inc/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "198.5594718612572" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/3/0", + "latitute": "-0.14477605500681137", + "longitude": "51.50950646273536", + "site_id": "jackson_gibson/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "205.06356467643758" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/0/0", + "latitute": "-0.08743943934424686", + "longitude": "51.49462424727675", + "site_id": "cook_ramirez_and_howell/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "204.31049087691707" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/0/5", + "latitute": "-0.09275684203595459", + "longitude": "51.50604392091363", + "site_id": "jackson_gibson/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "197.64496317318378" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/3/4", + "latitute": "-0.1684063123676963", + "longitude": "51.49890595002585", + "site_id": "martinez_inc/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "196.09901479328602" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/4/1", + "latitute": "-0.10790649546111267", + "longitude": "51.505154712405286", + "site_id": "jackson_gibson/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "197.90912683161795" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/2/1", + "latitute": "-0.11642291673866854", + "longitude": "51.51683458013747", + "site_id": "martinez_inc/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "195.20660684721142" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/0/8", + "latitute": "-0.09275684203595459", + "longitude": "51.50604392091363", + "site_id": "jackson_gibson/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "198.81177258795051" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/0/8", + "latitute": "-0.08743943934424686", + "longitude": "51.49462424727675", + "site_id": "cook_ramirez_and_howell/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "199.26558341667908" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/1/0", + "latitute": "-0.18856414865471136", + "longitude": "51.50398145727124", + "site_id": "martinez_inc/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "202.63322094012966" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/0/2", + "latitute": "-0.08743943934424686", + "longitude": "51.49462424727675", + "site_id": "cook_ramirez_and_howell/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "201.242829647885" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/1/1", + "latitute": "-0.17937324059872775", + "longitude": "51.49981289880396", + "site_id": "cook_ramirez_and_howell/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "203.47636863611046" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/2/8", + "latitute": "-0.12588664262819296", + "longitude": "51.50221488435059", + "site_id": "cook_ramirez_and_howell/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "196.6303931712822" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/4/8", + "latitute": "-0.10790649546111267", + "longitude": "51.505154712405286", + "site_id": "jackson_gibson/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "199.4025509158343" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/2/5", + "latitute": "-0.11642291673866854", + "longitude": "51.51683458013747", + "site_id": "martinez_inc/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "202.244381888705" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/2/9", + "latitute": "-0.15706157829077952", + "longitude": "51.519939570267255", + "site_id": "jackson_gibson/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "198.75932886475152" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/0/3", + "latitute": "-0.08743943934424686", + "longitude": "51.49462424727675", + "site_id": "cook_ramirez_and_howell/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "197.55541164406517" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/3/8", + "latitute": "-0.1684063123676963", + "longitude": "51.49890595002585", + "site_id": "martinez_inc/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "199.67193673177024" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/2/6", + "latitute": "-0.11642291673866854", + "longitude": "51.51683458013747", + "site_id": "martinez_inc/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "201.87301396849193" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/0/4", + "latitute": "-0.09275684203595459", + "longitude": "51.50604392091363", + "site_id": "jackson_gibson/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "208.8742227341114" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/4/6", + "latitute": "-0.10358309561844188", + "longitude": "51.502997658785624", + "site_id": "martinez_inc/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "197.7648261012689" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/0/6", + "latitute": "-0.14414594436220526", + "longitude": "51.51080694746054", + "site_id": "martinez_inc/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "199.9982144628044" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/0/9", + "latitute": "-0.09275684203595459", + "longitude": "51.50604392091363", + "site_id": "jackson_gibson/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "201.46652012853383" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/2/5", + "latitute": "-0.12588664262819296", + "longitude": "51.50221488435059", + "site_id": "cook_ramirez_and_howell/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "200.39455519286264" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/1/7", + "latitute": "-0.18856414865471136", + "longitude": "51.50398145727124", + "site_id": "martinez_inc/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "200.60777016813307" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/2/4", + "latitute": "-0.15706157829077952", + "longitude": "51.519939570267255", + "site_id": "jackson_gibson/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "195.1289531633795" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/1/2", + "latitute": "-0.08845125744353492", + "longitude": "51.49395842747566", + "site_id": "jackson_gibson/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "203.46170393549912" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/2/7", + "latitute": "-0.11642291673866854", + "longitude": "51.51683458013747", + "site_id": "martinez_inc/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "205.7759776027545" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/4/4", + "latitute": "-0.10358309561844188", + "longitude": "51.502997658785624", + "site_id": "martinez_inc/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "202.10716727798894" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/3/3", + "latitute": "-0.14477605500681137", + "longitude": "51.50950646273536", + "site_id": "jackson_gibson/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "199.58662763687067" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/2/8", + "latitute": "-0.11642291673866854", + "longitude": "51.51683458013747", + "site_id": "martinez_inc/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "199.73692392059917" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/3/6", + "latitute": "-0.11766485686257479", + "longitude": "51.51241260576661", + "site_id": "cook_ramirez_and_howell/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "197.8058363586146" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/2/6", + "latitute": "-0.15706157829077952", + "longitude": "51.519939570267255", + "site_id": "jackson_gibson/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "201.4959357936072" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/4/4", + "latitute": "-0.10790649546111267", + "longitude": "51.505154712405286", + "site_id": "jackson_gibson/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "201.15200992534773" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/1/3", + "latitute": "-0.18856414865471136", + "longitude": "51.50398145727124", + "site_id": "martinez_inc/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "198.47767020368474" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/3/0", + "latitute": "-0.11766485686257479", + "longitude": "51.51241260576661", + "site_id": "cook_ramirez_and_howell/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "196.8473143781654" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/1/2", + "latitute": "-0.18856414865471136", + "longitude": "51.50398145727124", + "site_id": "martinez_inc/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "203.16443165242134" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/2/2", + "latitute": "-0.12588664262819296", + "longitude": "51.50221488435059", + "site_id": "cook_ramirez_and_howell/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "204.06110122890823" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/4/7", + "latitute": "-0.11922450970538258", + "longitude": "51.495592295069905", + "site_id": "cook_ramirez_and_howell/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "198.0927403914103" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/0/7", + "latitute": "-0.08743943934424686", + "longitude": "51.49462424727675", + "site_id": "cook_ramirez_and_howell/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "199.8686825637131" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/3/3", + "latitute": "-0.1684063123676963", + "longitude": "51.49890595002585", + "site_id": "martinez_inc/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "200.35823350690367" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/3/7", + "latitute": "-0.14477605500681137", + "longitude": "51.50950646273536", + "site_id": "jackson_gibson/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "200.6086038246571" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/4/0", + "latitute": "-0.11922450970538258", + "longitude": "51.495592295069905", + "site_id": "cook_ramirez_and_howell/4", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "202.84687489498225" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/3/2", + "latitute": "-0.11766485686257479", + "longitude": "51.51241260576661", + "site_id": "cook_ramirez_and_howell/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "196.86890595546433" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/3/3", + "latitute": "-0.11766485686257479", + "longitude": "51.51241260576661", + "site_id": "cook_ramirez_and_howell/3", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "199.39106984840805" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/1/5", + "latitute": "-0.17937324059872775", + "longitude": "51.49981289880396", + "site_id": "cook_ramirez_and_howell/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "197.42025139765155" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/2/9", + "latitute": "-0.12588664262819296", + "longitude": "51.50221488435059", + "site_id": "cook_ramirez_and_howell/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "202.4647531090913" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/2/8", + "latitute": "-0.15706157829077952", + "longitude": "51.519939570267255", + "site_id": "jackson_gibson/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "199.47985538380314" + ] + }, + { + "metric": { + "company_id": "martinez_inc", + "device_id": "martinez_inc/1/6", + "latitute": "-0.18856414865471136", + "longitude": "51.50398145727124", + "site_id": "martinez_inc/1", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "203.75229813981974" + ] + }, + { + "metric": { + "company_id": "cook_ramirez_and_howell", + "device_id": "cook_ramirez_and_howell/2/7", + "latitute": "-0.12588664262819296", + "longitude": "51.50221488435059", + "site_id": "cook_ramirez_and_howell/2", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "201.04338505108396" + ] + }, + { + "metric": { + "company_id": "jackson_gibson", + "device_id": "jackson_gibson/0/6", + "latitute": "-0.09275684203595459", + "longitude": "51.50604392091363", + "site_id": "jackson_gibson/0", + "target_type": "gauge", + "unit": "mbyte_sec", + "ver": "1" + }, + "value": [ + 1540456986.897, + "197.69736363634297" + ] + } + ] + } + } diff --git a/netops_demo/py/functions/generate/model/model b/netops_demo/py/functions/generate/model/model new file mode 100644 index 0000000..bb90482 Binary files /dev/null and b/netops_demo/py/functions/generate/model/model differ diff --git a/netops_demo/py/functions/predict/predict.py b/netops_demo/py/functions/predict/predict.py new file mode 100644 index 0000000..a93dd8b --- /dev/null +++ b/netops_demo/py/functions/predict/predict.py @@ -0,0 +1,162 @@ +import os +import json +import pickle +import http.client +import sklearn +import numpy as np + +import libs.utils.utils +import libs.nuclio_sdk + + +def predict(context, event): + if event.path == '/configure': + if type(event.body) is not dict: + return context.Response(status_code=400) + + _configure(context, event.body) + elif event.path == '/start': + _start(context) + elif event.path == '/stop': + _stop(context) + elif event.path in ['/predict', '/', '']: + if context.user_data.state == 'predicting': + return _predict_error(context, **(event.body or {})) + else: + context.logger.warn_with('Got unsupported path', method=event.method, path=event.path) + return context.Response(status_code=400) + + +def init_context(context): + # Init states + libs.utils.utils.init_context(context) + + # check to see if there's an environment variable with our initial configuration + if 'PREDICTOR_CONFIGURATION' in os.environ: + _configure(context, json.loads(os.environ['PREDICTOR_CONFIGURATION'])) + + +def _configure(context, configuration: dict): + # Load model from given path + try: + if 'MODEL_FILE' in os.environ: + with open(os.environ.get('MODEL_FILE'), 'rb+') as f: + context.user_data.model = pickle.load(f) + except IOError: + context.user_data.model = None + + + # Configure TSDB server for queries + context.user_data.tsdb = configuration.get("tsdb") + + # Configure Metrics + context.user_data.metrics = configuration.get("metrics") + + # Save configuration + context.user_data.configuration = configuration + + try: + context.user_data.state = configuration['state'] + except KeyError: + pass + + +def _start(context): + context.logger.info_with('Starting to predict', prev_state=context.user_data.state) + + # Start predicting + context.user_data.state = 'predicting' + + +def _stop(context): + context.logger.info_with('Stopping to predict', prev_state=context.user_data.state) + + # go back to idle + context.user_data.state = 'idle' + + +def _predict(context): + # Connect to TSDB + client = http.client.HTTPConnection(context.user_data.tsdb) + + # Get metrics list + metrics = sorted(list(context.user_data.metrics)) + results = {} + + # Query per metric (Prometheus query method) + for metric in metrics: + # Build and send query + query = f'/api/v1/query?query=avg_over_time({metric}[1h])' + client.request('GET', query) + response = json.loads(client.getresponse().read().decode()) + response = _extract_results_from_prometheus_response(response) + + # Prepare responses + for label in response: + current_device_metric = _get_label_hash_from_response(label, metric) + device_results = results.setdefault(list(current_device_metric.keys())[0], {}) + + if device_results: + device_results = device_results.setdefault('metrics', {}) + device_results.update(list(current_device_metric.values())[0]['metrics']) + else: + device_results.update(list(current_device_metric.values())[0]) + + # Create feature vector per label (device) + feature_vectors = {} + for device, metrics in results.items(): + feature_vectors[device] = _create_feature_vector_from_metrics(metrics) + + # Predict error per device + predictions = {} + for device, X in feature_vectors.items(): + predictions[device] = { + 'label': { + **X['label'] + }, + 'metric': { + 'prediction': _predict_error(context, X['features']) + } + } + + # get the target from the request to generate or the configuration + target = context.user_data.configuration.get('target') + + # send the metrics towards the target + response = libs.utils.utils.send_emitters_to_target(context, target, predictions) + + # if this is an event response, make sure it's OK + if target == 'response': + return response + + +def _predict_error(context, features: list): + return context.user_data.model.predict(features)[0] + + +def _extract_results_from_prometheus_response(response: dict): + status = response.setdefault("status", "False") + if status != "success": + return [] + return response["data"]["result"] + + +def _get_label_hash_from_response(response: dict, metric: str): + keys_to_keep = ['company_id', 'device_id', 'latitute', 'longitude', 'site_id'] + label_id = response['metric']['device_id'] + labels = {key: response['metric'][key] for key in keys_to_keep} + values = { + metric: response['value'][1] + } + + return { + label_id: { + 'label': labels, + 'metrics': values + } + } + + +def _create_feature_vector_from_metrics(metrics: dict): + metrics['features'] = list(map(lambda metric: metric[1], sorted(metrics['metrics'].items()))) + return metrics diff --git a/netops_demo/py/functions/predict/predict_test.py b/netops_demo/py/functions/predict/predict_test.py new file mode 100644 index 0000000..ffa97c2 --- /dev/null +++ b/netops_demo/py/functions/predict/predict_test.py @@ -0,0 +1,84 @@ +import unittest.mock +import os +import json +import math + +import libs.nuclio_sdk.test +import functions.predict.predict +import libs.utils.utils + + +class TestCase(libs.nuclio_sdk.test.TestCase): + + def setUp(self): + super().setUp() + self._module = functions.predict.predict + self._utils = libs.utils.utils + + def test_configure(self): + configuration = self._get_configuration() + + # call configure - should initialize 'deployment' and 'configuration + response = self._platform.call_handler(self._module.predict, + event=libs.nuclio_sdk.Event(path='/configure', body=configuration)) + + self.assertIsNone(response) + + # make sure 'configuration' was set properly, as was metrics + self.assertIsNotNone(self._platform.get_context(self._module.predict).user_data.metrics) + self.assertEqual(configuration, self._platform.get_context(self._module.predict).user_data.configuration) + + # make sure 'state' is now 'predicting' + self.assertEqual('predicting', self._platform.get_context(self._module.predict).user_data.state) + + def test_init_context_no_configuration(self): + + # create an empty context + context = libs.nuclio_sdk.Context(self._platform._logger, self._platform) + + # initialize context + self._module.init_context(context) + + # expect state to be idle + self.assertEqual(context.user_data.state, 'idle') + + # expect no configuration set + self.assertEqual(context.user_data.configuration, None) + + def test_init_context_with_configuration(self): + configuration = self._get_configuration() + + # encode configuration into environment variable + os.environ['PREDICTOR_CONFIGURATION'] = json.dumps(configuration) + + # create an empty context + context = libs.nuclio_sdk.Context(self._platform._logger, self._platform) + + # initialize context + self._module.init_context(context) + + # verify stuff was set + self.assertEqual(context.user_data.state, 'predicting') + self.assertEqual(context.user_data.configuration, configuration) + + def test_start_and_stop(self): + + # call start + response = self._platform.call_handler(self._module.predict, event=libs.nuclio_sdk.Event(path='/start')) + self.assertIsNone(response) + + self.assertEqual(self._platform.get_context(self._module.predict).user_data.state, 'predicting') + + # call stop + response = self._platform.call_handler(self._module.predict, event=libs.nuclio_sdk.Event(path='/stop')) + self.assertIsNone(response) + + self.assertEqual(self._platform.get_context(self._module.predict).user_data.state, 'idle') + + def _get_configuration(self): + return { + 'metrics': ['cpu_utilization', 'throughput'], + 'tsdb': 'http://192.168.224.49:9090', + 'state': 'predicting', + 'target': 'function:netops-demo-ingest' + } diff --git a/netops_demo/py/libs/generator/baseline/company.py b/netops_demo/py/libs/generator/baseline/company.py index 92bb122..0e8bb3c 100644 --- a/netops_demo/py/libs/generator/baseline/company.py +++ b/netops_demo/py/libs/generator/baseline/company.py @@ -16,7 +16,12 @@ def __init__(self, num_devices: int, num_locations: int, within: dict, metrics: # Set parameters self.name = self.f.company() - self.locations = [self.f.location(within) for i in range(num_locations)] + self.locations = {i:self.f.location(within) for i in range(num_locations)} self.devices = [Device(metrics=metrics, error_scenarios=error_scenarios, - error_rate=error_rate) for i in range(num_devices)] + error_rate=error_rate) for l in self.locations for d in range(num_devices)] + self.components = {l: {'location': self.locations[l], + 'devices': [Device(metrics=metrics, + error_scenarios=error_scenarios, + error_rate=error_rate) for d in range(num_devices)]} + for l in range(num_locations)} diff --git a/netops_demo/py/libs/generator/deployment.py b/netops_demo/py/libs/generator/deployment.py index 8db15e2..0207260 100644 --- a/netops_demo/py/libs/generator/deployment.py +++ b/netops_demo/py/libs/generator/deployment.py @@ -32,12 +32,12 @@ def generate(self): for company in self.companies: tick[company.name] = {} - for i, l in enumerate(company.locations): - tick[company.name][i] = { - 'location': l, + for l, location in enumerate(company.components.values()): + tick[company.name][l] = { + 'location': location['location'], 'devices': {} } - for j, d in enumerate(company.devices): - tick[company.name][i]['devices'][j] = next(d.generate()) + for d, device in enumerate(location['devices']): + tick[company.name][l]['devices'][d] = next(device.generate()) yield tick diff --git a/netops_demo/py/libs/utils/utils.py b/netops_demo/py/libs/utils/utils.py new file mode 100644 index 0000000..4c241e5 --- /dev/null +++ b/netops_demo/py/libs/utils/utils.py @@ -0,0 +1,28 @@ +import libs.generator.deployment +import libs.nuclio_sdk + + +def init_context(context): + # initialize context structure + for context_attr in ['state', 'configuration', 'manager']: + setattr(context.user_data, context_attr, None) + + # start in idle state + context.user_data.state = 'idle' + + +def send_emitters_to_target(context, target, metrics_batch): + context.logger.debug_with('Sending metrics to target', target=target) + + if target.startswith('function'): + + # function:netops-ingest -> netops-ingest + target_function = target.split(':')[1] + + context.platform.call_function(target_function, libs.nuclio_sdk.Event(body=metrics_batch)) + elif target == 'response': + return metrics_batch + elif target == 'log': + context.logger.info_with('Sending metrics batch', metrics_batch=metrics_batch) + else: + raise ValueError(f'Unknown target type {target}') diff --git a/netops_demo/py/requirements.txt b/netops_demo/py/requirements.txt index 9fe30f9..a809935 100644 --- a/netops_demo/py/requirements.txt +++ b/netops_demo/py/requirements.txt @@ -1,2 +1,4 @@ +scikit-learn numpy -faker \ No newline at end of file +faker +xgboost \ No newline at end of file